赞
踩
1.福袋机上的屏幕是一个Android平板,相当于一个Android手机
2.需要给用户生成一张二维码,让用户扫描付款
3.得到用户付款的消息后,转动对应的电机,给用户掉落福袋
1.研究微信支付文档 https://pay.weixin.qq.com/wiki/doc/api/index.html 根据我的需求,我选择了Native支付
2.模式二比较简单,比较容易实现成功,所已选择了模式二
3.拿着公司提供的一个邮箱在微信公众平台https://mp.weixin.qq.com/cgi-bin/loginpage?t=wxm2-login&lang=zh_CN申请一个账号,选择申请的这个公众号为服务号,把公司的相关信息和一些申请资料提交后,1-3天就申请好了.
4.拿到我们申请的公众号后,我们还要花300元进行微信认证,得1-3天就认证好了(可以得到一个AppID)
5.在微信公平平台的微信支付页面,点击 申请接入,发现需要一个商户号,所以我们 现在去微信商户平台https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F注册一个账户(注意:在电脑自带的IE浏览器上进行操作,因为后边要弄财富通,在谷歌浏览器上识别不到财富通),提交一些公司资料后,过1-3天就申请好了(可以自己设置一个32位的秘钥,可以得到一个商户号)
6.有了AppID,秘钥和商户号就可以进行开发了,即使没有后台,全做到Android都可以实现了
7.看微信支付文档有统一下单接口,查询订单接口,关闭订单接口.
CSDN橙子紫了博客主 https://blog.csdn.net/u013164584/article/details/78030481的这片帖子 封装的比较好
1.导入依赖
- //网络
- implementation 'org.lucee:httpcomponents-httpclient:4.5.6'
- //二维码
- implementation 'com.google.zxing:core:3.2.1'
- implementation 'cn.bingoogolapple:bga-qrcodecore:1.1.7@aar'
- implementation 'cn.bingoogolapple:bga-zxing:1.1.7@aar'
2.PayCommonUtil,该工具类中的方法包含:生成签名,判断签名是否正确,生成二维码,xml和map转换,随机字符串,请求下单等等
- package com.wjbzg.wxtestdome.util;
-
- import android.content.Context;
- import android.content.res.AssetManager;
- import android.support.annotation.NonNull;
- import android.util.Log;
-
- import org.apache.http.conn.ssl.SSLContexts;
- import org.w3c.dom.Node;
- import org.w3c.dom.NodeList;
-
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.net.ConnectException;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.security.KeyManagementException;
- import java.security.KeyStore;
- import java.security.KeyStoreException;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.security.NoSuchProviderException;
- import java.security.SecureRandom;
- import java.security.UnrecoverableKeyException;
- import java.security.cert.CertificateException;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Random;
- import java.util.Set;
- import java.util.SortedMap;
- import java.util.TreeMap;
-
- import javax.net.ssl.HttpsURLConnection;
- import javax.net.ssl.KeyManagerFactory;
- import javax.net.ssl.SSLContext;
- import javax.net.ssl.SSLSocketFactory;
- import javax.xml.parsers.DocumentBuilder;
- import javax.xml.parsers.DocumentBuilderFactory;
-
- /**
- * Created by ${szz} on 2019\6\5 0005
- */
- public class PayCommonUtil {
- //判断签名是否正确
- public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
- StringBuffer sb = new StringBuffer();
- Set es = packageParams.entrySet();
- Iterator it = es.iterator();
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- String k = (String) entry.getKey();
- String v = (String) entry.getValue();
- if (!"sign".equals(k) && null != v && !"".equals(v)) {
- sb.append(k + "=" + v + "&");
- }
- }
- sb.append("key=" + API_KEY);
- //算出摘要
- String mysign = MD5Encode(sb.toString(), characterEncoding).toLowerCase();
- String tenpaySign = ((String) packageParams.get("sign")).toLowerCase();
- return tenpaySign.equals(mysign);
- }
-
- /**
- * 生成签名
- * @param characterEncoding 字符编码
- * @param parameters
- * @return
- */
- public static String createSign(String characterEncoding, SortedMap<String, Object> parameters) {
- StringBuffer sb = new StringBuffer();
- Set es = parameters.entrySet();
- Iterator it = es.iterator();
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- String k = (String) entry.getKey();
- Object v = entry.getValue();
- if (null != v && !"".equals(v)
- && !"sign".equals(k) && !"key".equals(k)) {
- sb.append(k + "=" + v + "&");
- }
- }
- sb.append("key=" + Constent.VALUE_API_KEY);
- String sign = MD5Encode(sb.toString(), characterEncoding).toUpperCase();
- return sign;
- }
-
- private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
- "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
-
- private static String byteToHexString(byte b) {
- int n = b;
- if (n < 0)
- n += 256;
- int d1 = n / 16;
- int d2 = n % 16;
- return hexDigits[d1] + hexDigits[d2];
- }
-
- private static String byteArrayToHexString(byte b[]) {
- StringBuffer resultSb = new StringBuffer();
- for (int i = 0; i < b.length; i++)
- resultSb.append(byteToHexString(b[i]));
-
- return resultSb.toString();
- }
-
- public static String MD5Encode(String origin, String charsetname) {
- String resultString = null;
- try {
- resultString = new String(origin);
- MessageDigest md = MessageDigest.getInstance("MD5");
- resultString = byteArrayToHexString(md.digest(resultString
- .getBytes("UTF-8")));
- } catch (Exception exception) {
- }
- return resultString;
- }
-
- //随机字符串生成
- public static String getRandomString(int length) { //length表示生成字符串的长度
- String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- Random random = new Random();
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < length; i++) {
- int number = random.nextInt(base.length());
- sb.append(base.charAt(number));
- }
- return sb.toString();
- }
-
- //请求xml组装
- public static String getRequestXml(SortedMap<String, Object> parameters) {
- StringBuffer sb = new StringBuffer();
- sb.append("<xml>");
- Set es = parameters.entrySet();
- Iterator it = es.iterator();
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- String key = (String) entry.getKey();
- String value = (String) entry.getValue();
- sb.append("<" + key + ">" + value + "</" + key + ">");
- }
- sb.append("</xml>");
- return sb.toString();
- }
-
- //请求方法
- public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
- try {
- URL url = new URL(requestUrl);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setDoOutput(true);
- conn.setDoInput(true);
- conn.setUseCaches(false);
- // 设置请求方式(GET/POST)
- conn.setRequestMethod(requestMethod);
- conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
-
- // 当outputStr不为null时向输出流写数据
- if (null != outputStr) {
- OutputStream outputStream = conn.getOutputStream();
- // 注意编码格式
- outputStream.write(outputStr.getBytes("UTF-8"));
- outputStream.close();
- }
- // 从输入流读取返回内容
- InputStream inputStream = conn.getInputStream();
- InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
- BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
- String str = null;
- StringBuffer buffer = new StringBuffer();
- while ((str = bufferedReader.readLine()) != null) {
- buffer.append(str);
- }
- // 释放资源
- bufferedReader.close();
- inputStreamReader.close();
- inputStream.close();
- inputStream = null;
- conn.disconnect();
- return buffer.toString();
- } catch (ConnectException ce) {
- // System.out.println("连接超时");
- Log.e("Tag","连接超时");
- ce.printStackTrace();
- } catch (Exception e) {
- // System.out.println("https请求异常");
- Log.e("Tag","https请求异常"+e);
- e.printStackTrace();
- }
- return null;
- }
-
- // public static String httpsRequest(Context context, String data) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, CertificateException, NoSuchProviderException {
- // String result = null;
- // // 证书密码(默认为商户ID)
- // String password = Constent.VALUE_MCH_ID;
- // // 实例化密钥库
- // KeyStore ks = KeyStore.getInstance("PKCS12");
- // // 获得密钥库文件流
- // AssetManager am = context.getResources().getAssets();
- // InputStream fis = am.open("apiclient_cert.p12");
- // // 加载密钥库
- // ks.load(fis, password.toCharArray());
- // // 关闭密钥库文件流
- // fis.close();
- // // 实例化密钥库
- // KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- // // 初始化密钥工厂
- // kmf.init(ks, password.toCharArray());
- // // 创建SSLContext
- // SSLContext sslContext = SSLContexts.custom()
- // .loadKeyMaterial(ks, Constent.VALUE_MCH_ID.toCharArray()) //加载证书密码,默认为商户ID
- // .build();
- // sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
- // // 获取SSLSocketFactory对象
- // SSLSocketFactory ssf = sslContext.getSocketFactory();
- // URL url = new URL(Constent.URL_TUIKUAN);
- // HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
- // conn.setRequestMethod("POST");
- // //设置当前实例使用的SSLSocketFactory
- // conn.setSSLSocketFactory(ssf);
- // conn.setDoOutput(true);
- // conn.setDoInput(true);
- // conn.connect();
- // DataOutputStream out = new DataOutputStream(
- // conn.getOutputStream());
- // if (data != null)
- // out.writeBytes(data);
- // out.flush();
- // out.close();
- // //获取输入流
- // BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
- // int code = conn.getResponseCode();
- // if (HttpsURLConnection.HTTP_OK == code) {
- // String temp = in.readLine();
- // while (temp != null) {
- // if (result != null)
- // result += temp;
- // else
- // result = temp;
- // temp = in.readLine();
- // }
- // }
- // return result;
- // }
-
- public static Map<String, String> xmlToMap(String strXML) throws Exception {
- try {
- Map<String, String> data = new HashMap<String, String>();
- DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
- DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
- InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
- org.w3c.dom.Document doc = documentBuilder.parse(stream);
- doc.getDocumentElement().normalize();
- NodeList nodeList = doc.getDocumentElement().getChildNodes();
- for (int idx = 0; idx < nodeList.getLength(); ++idx) {
- Node node = nodeList.item(idx);
- if (node.getNodeType() == Node.ELEMENT_NODE) {
- org.w3c.dom.Element element = (org.w3c.dom.Element) node;
- data.put(element.getNodeName(), element.getTextContent());
- }
- }
-
- try {
- stream.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return data;
- } catch (Exception ex) {
- ex.printStackTrace();
- throw ex;
- }
-
- }
-
- @NonNull
- public static SortedMap<Object, Object> getSortedMap(Map<String, String> map) {
- //过滤空 设置 TreeMap
- SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
- Iterator it = map.keySet().iterator();
- while (it.hasNext()) {
- String parameter = (String) it.next();
- String parameterValue = map.get(parameter);
-
- String v = "";
- if (null != parameterValue) {
- v = parameterValue.trim();
- }
- packageParams.put(parameter, v);
- }
- return packageParams;
- }
- //---------------------
- // 作者:橙子紫了
- // 来源:CSDN
- // 原文:https://blog.csdn.net/u013164584/article/details/78030481
- // 版权声明:本文为博主原创文章,转载请附上博文链接!
- }
3.MainActivty
- package com.wjbzg.wxtestdome;
-
- import android.graphics.Bitmap;
- import android.os.AsyncTask;
- import android.os.Handler;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.util.Log;
- import android.widget.ImageView;
-
- import com.wjbzg.wxtestdome.util.Constent;
- import com.wjbzg.wxtestdome.util.PayCommonUtil;
-
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.impl.client.CloseableHttpClient;
- import org.apache.http.impl.client.HttpClients;
- import org.json.JSONObject;
-
- import java.util.Map;
- import java.util.SortedMap;
- import java.util.TreeMap;
-
- import cn.bingoogolapple.qrcode.core.BGAQRCodeUtil;
- import cn.bingoogolapple.qrcode.zxing.QRCodeEncoder;
-
- public class MainActivity extends AppCompatActivity {
- //Native支付
- //统一下单:https://api.mch.weixin.qq.com/pay/unifiedorder
- // 公众账号ID appid
- // 商户号 mch_id
- // 随机字符串 nonce_str 随机字符串,长度要求在32位以内。推荐随机数生成算法 秘钥
- // 签名 sign
- // 商品描述 body
- // 商户订单号 out_trade_no
- // 标价金额 total_fee
- // 终端IP spbill_create_ip
- // 通知地址 notify_url
- // 交易类型 trade_type NATIVE -Native支付
- ImageView img_ewm;
- String time;
- SortedMap<Object, Object> packageParams;
- Handler handler = new Handler();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- updateUI(packageParams);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- };
- Handler handler2 = new Handler();
-
- Runnable runnable2 = new Runnable() {
- @Override
- public void run() {
- new Thread(new Runnable() {//每次都要开一个线程去查询订单情况,直到有用户支付成功的结果。
- @Override
- public void run() {
- checkOrder();
- }
- }).start();
- handler2.postDelayed(runnable2, 5000);
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initView();
- createQRCode();//生成二维码
-
- }
-
- private void initView() {
- img_ewm = (ImageView) findViewById(R.id.img_ewm);
- }
-
- /**
- * 生成二维码
- */
- private void createQRCode() {
- new AsyncTask<Void, Void, Bitmap>() {
- @Override
- protected Bitmap doInBackground(Void... params) {
- // System.out.println("ds>>> 生成二维码成功");
- return QRCodeEncoder.syncEncodeQRCode(unifiedOrder(), BGAQRCodeUtil.dp2px(MainActivity.this, 150));
- }
-
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- if (bitmap != null) {
- Log.e("Tag","生成二维码成功");
- img_ewm.setImageBitmap(bitmap);
- handler2.post(runnable2);//在main中调用 查询订单
- } else {
- // System.out.println("ds>>> 生成二维码失败");
- Log.e("Tag","生成二维码失败");
- }
- }
- }.execute();
- }
-
- //1 统一下单
- public String unifiedOrder() {
- Log.e("Tag","****准备下单数据****");
- SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
- parameterMap.put(Constent.APPID, Constent.VALUE_APPID);//公众号ID
- parameterMap.put(Constent.MCH_ID, Constent.VALUE_MCH_ID);//商户号
- parameterMap.put(Constent.NONCE_STR, PayCommonUtil.getRandomString(32));//随机字符串
- parameterMap.put(Constent.BODY, "一瓶可乐");//商品描述
- parameterMap.put(Constent.SIGN_TYPE, Constent.MD);//签名类型
- // parameterMap.put(Constent.DETAIL, "");//商品详情
- // parameterMap.put(Constent.ATTACH, "欧亚国际分店");//附加数据
- time = System.currentTimeMillis() + "";
- parameterMap.put(Constent.OUT_TRADE_NO, time);//商户订单号
- // parameterMap.put(Constent.FEE_TYPE, Constent.CNY);//标价币种
- parameterMap.put(Constent.TOTAL_FEE, "1");//标价金额
- parameterMap.put(Constent.SPBILL_CREATE_IP, "127.0.0.1");//终端IP
- parameterMap.put(Constent.TIME_START, System.currentTimeMillis() + "");//交易起始时间
- //异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的,不能携带参数。
- parameterMap.put(Constent.NOTIFY_URL, "http://www.wjbzg.cn/");//通知地址(支付结果通知)
- parameterMap.put(Constent.TRADE_TYPE, Constent.NATIVE);//交易类型
- // parameterMap.put(Constent.PRODUCT_ID, "");//商品ID(和设备ID一起需知,扫码支付时必须传)
- // parameterMap.put(Constent.LIMIT_PAY, Constent.NO_CREDIT);//指定支付方式
- parameterMap.put(Constent.SIGN, PayCommonUtil.createSign(Constent.UTF, parameterMap));//签名
- final String requestXML = PayCommonUtil.getRequestXml(parameterMap);//将请求组装成xml形式
- Log.e("Tag","----下单的xml-----"+requestXML);
- String result = PayCommonUtil.httpsRequest(
- Constent.URL_TONGYI_XIADAN, Constent.POST,
- requestXML);//调用统一支付接口返回String类型字符串
- Log.e("Tag","----下单后微信后台返回的结果xml-----"+result);
- Map<String, String> map = null;
- try {
- map = PayCommonUtil.xmlToMap(result);//将返回的结果转为map形式
- } catch (Exception e) {
- Log.e("Tag","---------下单失败----------"+e);
- e.printStackTrace();
- }
- String string = map.toString();
- Log.e("Tag","---------返回的结果xml转成Map.toString----------"+string);
- String result_code = map.get("result_code");
- Log.e("Tag","****下单结果****"+result_code);
- if (result_code.equals("SUCCESS")){
- //下单成功
- String code_url = map.get("code_url");
- Log.e("Tag","二维码的url为:"+ code_url);
- return code_url;
- }else {
- return null;
- }
- }
-
-
- // 2 查询订单 每5秒查询一次订单
- public void checkOrder() {
- SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
- parameterMap.put(Constent.APPID, Constent.VALUE_APPID);//公众号ID
- parameterMap.put(Constent.MCH_ID, Constent.VALUE_MCH_ID);//商户号
- parameterMap.put(Constent.OUT_TRADE_NO, time);//商户订单号
- parameterMap.put(Constent.NONCE_STR, PayCommonUtil.getRandomString(32));//随机字符串
- parameterMap.put(Constent.SIGN, PayCommonUtil.createSign(Constent.UTF, parameterMap));//签名
- String requestXML = PayCommonUtil.getRequestXml(parameterMap);//将请求组装成xml形式
- Log.e("Tag","调用查询订单准备的xml:"+requestXML);
- String result = PayCommonUtil.httpsRequest(
- Constent.URL_CHAXUN_DINGDAN, Constent.POST,
- requestXML);//调用查询订单接口返回String类型字符串
- Log.e("Tag","调用查询订单接口返回String类型字符串:"+result);
- Map<String, String> map = null;
- try {
- if (result != null)
- map = PayCommonUtil.xmlToMap(result);//将返回的结果转为map形式
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (map != null) {
- packageParams = PayCommonUtil.getSortedMap(map);
- }
- if (packageParams != null && PayCommonUtil.isTenpaySign(Constent.UTF, packageParams, Constent.VALUE_API_KEY)) {
- handler.post(runnable);//在新的线程去匹配返回的信息,做相应的UI变化
- } else {
- System.out.println("通知签名验证失败");
- }
- }
-
-
- private void updateUI(SortedMap<Object, Object> packageParams) throws InterruptedException {
- String result_code = (String) packageParams.get(Constent.RESULT_CODE);
- String return_code = (String) packageParams.get(Constent.RETURN_CODE);
- String trade_state = (String) packageParams.get(Constent.TRADE_STATE);
- String trade_state_desc = (String) packageParams.get(Constent.TRADE_STATE_DESC);
- String error_code = (String) packageParams.get(Constent.ERROR_CODE);
- Log.e("Tag","result_code=" + result_code + ", return_code=" + return_code + ", trade_state=" + trade_state);
- Log.e("Tag","trade_state_desc=" + trade_state_desc + ", error_code=" + error_code);
- if (result_code.equals(Constent.SUCCESS) && return_code.equals(Constent.SUCCESS) && trade_state.equals(Constent.SUCCESS)) {
- handler2.removeCallbacks(runnable2);
- //支付成功,做相关逻辑。
- } else if (Constent.PAYERROR.equals(packageParams.get(Constent.TRADE_STATE))) {
- handler2.removeCallbacks(runnable2);
- //支付失败,做相关逻辑。
- }
- }
- }
3.Constent
- package com.wjbzg.wxtestdome.util;
-
- /**
- * Created by ${szz} on 2019\6\5 0005
- */
- public class Constent {
- //秘钥
- public static final String VALUE_API_KEY = "";
- //商户ID kv
- public static final String MCH_ID = "mch_id";
- public static final String VALUE_MCH_ID = "";
- //退款url
- // public static final String URL_TUIKUAN = ;
- //APPID kv
- public static final String APPID = "appid";
- public static final String VALUE_APPID = "";
-
- //随机字符串 k
- public static final String NONCE_STR = "nonce_str";
- //商品描述 k
- public static final String BODY = "body";
- //签名类型 kv
- public static final String SIGN_TYPE = "sign_type";
- public static final String MD = "MD5";
- //商品详情
- // public static final String DETAIL = ;
- //附加数据
- public static final String ATTACH = "ATTACH";
- //商户订单号 k
- public static final String OUT_TRADE_NO = "out_trade_no";
- //标价金额 k
- public static final String TOTAL_FEE = "total_fee";
- //终端IP k
- public static final String SPBILL_CREATE_IP = "spbill_create_ip";
- //交易起始时间 k
- public static final String TIME_START = "time_start";
- //异步接收微信支付结果通知的回调地址 K
- public static final String NOTIFY_URL = "notify_url";
- //交易类型
- public static final String TRADE_TYPE = "trade_type";
- public static final String NATIVE = "NATIVE";
-
- public static final String SIGN = "sign";
- public static final String UTF = "UTF-8";
- public static final String URL_TONGYI_XIADAN = "https://api.mch.weixin.qq.com/pay/unifiedorder";
- public static final String POST = "POST";
- public static final String CODE_URL = "CODE_URL";
-
- //2.查询订单接口
- public static final String URL_CHAXUN_DINGDAN = "https://api.mch.weixin.qq.com/pay/orderquery";
- public static final String RESULT_CODE = "return_code";
- public static final String RETURN_CODE = "result_code";
- public static final String TRADE_STATE = "trade_state";
- public static final String TRADE_STATE_DESC = "trade_state_desc";
- public static final String ERROR_CODE = "err_code";
- public static final String SUCCESS = "SUCCESS";
-
- public static final String PAYERROR = "PAYERROR";
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。