先附上 微信支付文档给出的说明商户系统和微信支付系统主要交互说明:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。参见【统一下单API】。
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP参与签名的字段名为的appid,PARTNERID,prepayid,noncestr,时间戳,包注意:包的值格式为符号= WXPay
步骤4:商户APP调起微信支付.api参见本章节【app端开发步骤说明】
步骤5:商户后台接收支付通知.api参见【支付结果通知API】
步骤6:商户后台查询支付结果。,api参见【查询订单API】
以上是官网给出的服务端与客户端的交互流程
统一下单大致的意思是:
服务端:统一下单需要10个参数其中第10个是签名是对前9个参数进行签名处理,微信后台会返回生成的预付款订单,然后服务端会给客户端返回7个参数其中第7个参数是对前6个参数整体进行的签名 app端:掉起微信支付需要服务器传递过来的7个参数
其中步骤2和步骤3是服务端做的事,本文是把步骤2和步骤3的操作放在客户端进行,
作用:
1.熟练掌握微信支付的流程
2.可以检测服务器是否返回的内容有错(我当时用了将近1天的时间去处理微信返回的错误码是-1的情况,后来我在本地生成了预付款订单,把服务端的操作全放在了本地,可以正常支付,才发现不是我的问题,而是服务端的问题)
具体实现:
1.网络请求用的AsyncTask 调用微信的统一下单接口 需要10个参数,其中第10个是对前9个参数的签名,签名规则要根据微信的要求来
protected Map<String, String> doInBackground(Void... params) { //本地调用统一下单的接口 微信返回的数据格式是xml 需要本地处理 String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder"); String entity = genEntity(); Log.e("实体", entity); byte[] buf = Util.httpPost(url, entity); String content = new String(buf); Log.e("内容", content); Map<String, String> xml = decodeXml(content); return xml; }
public String genEntity() { String nonceStr = genNonceStr(); List<NameValuePair> packageParams = new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID)); packageParams.add(new BasicNameValuePair("body", "我是购买的商品")); packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID)); packageParams.add(new BasicNameValuePair("nonce_str", nonceStr)); packageParams.add(new BasicNameValuePair("notify_url", "http://121.40.35.3/test")); packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo())); packageParams.add(new BasicNameValuePair("spbill_create_ip", "127.0.0.1")); packageParams.add(new BasicNameValuePair("total_fee", "1")); packageParams.add(new BasicNameValuePair("trade_type", "APP")); String sign = genPackageSign(packageParams); packageParams.add(new BasicNameValuePair("sign", sign)); String xmlstring = XmlUtil.toXml(packageParams); try { return new String(xmlstring.toString().getBytes(), "ISO-8859-1"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; }
微信的签名规则
public static String genPackageSign(List<NameValuePair> params) { try { StringBuilder sb = new StringBuilder(); for (int i = 0; i < params.size(); i++) { sb.append(params.get(i).getName()); sb.append('='); sb.append(params.get(i).getValue()); sb.append('&'); } sb.append("key="); sb.append(Constants.API_KEY); String packageSign = MD5Util.getMessageDigest( sb.toString().getBytes("utf-8")).toUpperCase(); return packageSign; } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } }
2.调用统一下单接口后,微信会返回xml 根据返回的xml 获取到预支付的会话标示 prepay_id
(解释:服务端的操作是根据微信返回的参数,对appid ,mch_id ,nonce_str ,prepay_id ,trade_type ,微信默认的字符串package="Sign=WXPay"这6个参数进行签名处理 生成第7个参数sign 返回给客户端,客户端拿到这7个参数,然后掉起来微信
3.拿到预支付的会话标示后掉起微信,此时需要7个参数
/** * 掉起微信支付 这里是客户端必须进行的 也就是接受服务器 返回的数据 进行处理 */ private void genPayReq() { req.appId = Constants.APP_ID; req.partnerId = Constants.MCH_ID; req.prepayId = resultunifiedorder.get("prepay_id"); req.packageValue = "Sign=WXPay"; String prepayID = resultunifiedorder.get("prepay_id"); req.nonceStr = genNonceStr(); req.timeStamp = String.valueOf(genTimeStamp()); List<NameValuePair> signParams = new LinkedList<NameValuePair>(); signParams.add(new BasicNameValuePair("appid", req.appId)); signParams.add(new BasicNameValuePair("noncestr", req.nonceStr)); signParams.add(new BasicNameValuePair("package", req.packageValue)); signParams.add(new BasicNameValuePair("partnerid", req.partnerId)); signParams.add(new BasicNameValuePair("prepayid", req.prepayId)); signParams.add(new BasicNameValuePair("timestamp", req.timeStamp)); //因为微信支付需要签2次名 这里是第二次签名 本应该放在服务端的 req.sign = genAppSign(signParams); sb.append("sign\n" + req.sign + "\n\n"); //show.setText(sb.toString()); Log.e("orion", signParams.toString()); //调起微信支付 msgApi.registerApp(Constants.APP_ID); msgApi.sendReq(req); }
如果想要运行本demo 必须填写以下信息
//appid public static final String APP_ID = "";// //商户id public static final String MCH_ID = ""; //商户和微信签约的秘钥 public static final String API_KEY = "";
demo地址:点击打开链接
提示:
如果直接run 运行的项目 请修改微信后台的签名 -改为debug签名,
微信后台的签名只要和你当前项目的签名保持一致即可,比如:如果你微信后台填写的是正式签名,那么你app就不能直接run执行 ,因为run 执行默认的是用的debug签名
所以 为了方便测试,我微信后台暂时填写的是我debug的签名