Android微信支付爬坑【转】

来源:互联网 发布:css书籍推荐知乎 编辑:程序博客网 时间:2024/06/06 02:04

来自:http://blog.csdn.net/ywl5320/article/details/50856922

最近在做支付模块,最常用的就是微信支付和支付宝支付,其中最坑的就是微信支付了!!各种问题,官方文档也写得不详细。。。哎 不过最后还是成功的爬坑完成集成了微信支付。先附上一张支付成功的页面高兴高兴 哈哈哈:


下面就是爬坑过程

微信支付分为以下几个步骤:

1、首先要在微信开放平台注册,添加自己的APP并成功申请支付功能

2、下载微信支付的SDK并添加到自己的项目里(以上都是最基本的,问题不大)

3、现在就可以着手集成微信支付了(从下单到支付):

(1):准备好需要的资料数据,并向微信注册当前APP

首先要在微信后台配置当前APP打包key所生成的签名(微信官网有签名工具),然后还必须设置商户的key(32位,商户自己设置的),然后就是APP_ID这个是微信为每一个APP生成的,最后就是开通了支付功能的商户的ID用户我们把钱支付给商家。

然后在适当的地方注册APP(oncreate中)

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>msgApi = WXAPIFactory.createWXAPI(context, null);  
  2.         msgApi.registerApp(AppConfig.WX_APP_ID);//wxappkey  

(2):调用统一下单接口(https://api.mch.weixin.qq.com/pay/unifiedorder)生成订单,这一步是最容易出错的(此乃大坑)。

1、首先我们设计好所要传给微信的必要参数(OrderPayBean):

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private String appid; //appid  
  2. private String body; //商品描述  
  3. private String mch_id; //商户ID  
  4. private String nonce_str; //随机字符串  
  5. private String notify_url; //微信通知后台支付结果url  
  6. private String out_trade_no; //我们自己的订单号  
  7. private String spbill_create_ip; //客户端IP  
  8. private int total_fee; //总的支付金额  
  9. private String trade_type; //因为是移动应用 所以是APP  
  10. private String sign; //以上所有参数的MD5签名  
例如以下商品数据:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>//微信支付  
  2.         orderPaybean.setAppid(AppConfig.WX_APP_ID);  
  3.         orderPaybean.setBody("操蛋的微信支付");  
  4.         orderPaybean.setMch_id(AppConfig.WX_MCH_ID);  
  5.         orderPaybean.setNonce_str(nonceStr);  
  6.         orderPaybean.setNotify_url("http://********/payNotify/wx.do");  
  7.         orderPaybean.setTotal_fee(1);  
  8. <span style="white-space:pre">    </span>//wxPayBean.setTotal_fee(totlefee + "");  
  9.         orderPaybean.setTrade_type("APP");  
  10.         orderPaybean.setSpbill_create_ip("196.168.1.1");  
2、商品参数准备好了,接下来我们为之生成签名:

签名算法如下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.      * 微信支付签名算法sign 
  3.      * @param characterEncoding 签名编码(UTF-8) 
  4.      * @param parameters 要签名的参数的集合 
  5.      * @param key 商户自己设置的key 
  6.      */  
  7.     @SuppressWarnings("unchecked")  
  8.     public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters, String key){  
  9.         StringBuffer sb = new StringBuffer();  
  10.         Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)  
  11.         Iterator it = es.iterator();  
  12.         while(it.hasNext()) {  
  13.             Map.Entry entry = (Map.Entry)it.next();  
  14.             String k = (String)entry.getKey();  
  15.             Object v = entry.getValue();  
  16.             if(null != v && !"".equals(v)  
  17.                     && !"sign".equals(k) && !"key".equals(k)) {  
  18.                 sb.append(k + "=" + v + "&");  
  19.             }  
  20.         }  
  21.         sb.append("key=" + key);  
  22.         System.out.println(sb.toString());  
  23.         String sign = WxMd5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  
  24.         System.out.println(sign);  
  25.         return sign;  
  26.     }  

构造商品参数集合:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();  
  2.         parameters.put("appid", orderPaybean.getAppid());  
  3.         parameters.put("body", orderPaybean.getBody());  
  4.         parameters.put("mch_id", orderPaybean.getMch_id());  
  5.         parameters.put("nonce_str", orderPaybean.getNonce_str());  
  6.         parameters.put("notify_url", orderPaybean.getNotify_url());  
  7.         parameters.put("out_trade_no", orderPaybean.getOut_trade_no());  
  8.         parameters.put("total_fee", orderPaybean.getTotal_fee());  
  9.         parameters.put("trade_type", orderPaybean.getTrade_type());  
  10.         parameters.put("spbill_create_ip", orderPaybean.getSpbill_create_ip());  
  11.         parameters.put("sign", CommonUtil.createSign("UTF-8", parameters, AppConfig.WX_KEY));//传入签名好的参数值  
3、因为统一下单接口需要以xml格式post发送给微信,所以我们先拼接xml格式的参数:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>StringBuilder xmlBuilder = new StringBuilder();  
  2.         xmlBuilder.append("<xml>");  
  3.         Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)  
  4.         Iterator it = es.iterator();  
  5.         while (it.hasNext()) {  
  6.             Map.Entry entry = (Map.Entry) it.next();  
  7.             String k = (String) entry.getKey();  
  8.             Object v = entry.getValue();  
  9.             xmlBuilder.append("<").append(k).append(">");  
  10.             xmlBuilder.append(v);  
  11.             xmlBuilder.append("</").append(k).append(">");  
  12.         }  
  13.         xmlBuilder.append("</xml>");  
  14.         System.out.println(xmlBuilder.toString());  
  15.         try {  
  16.             new GetPrepayId(new String(xmlBuilder.toString().getBytes(), "ISO8859-1")).execute();//这一步非常重要,不这样转换编码的话,传递中文就会报“签名错误”,这是很多人都会遇到的错误。  
  17.         } catch (Exception e) {  
  18.             e.printStackTrace();  
  19.         }  
然后是我们的异步线程请求统一下单接口:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>public class GetPrepayId extends AsyncTask {  
  2.         String str;  
  3.   
  4.         public GetPrepayId(String str) {  
  5.             this.str = str;  
  6.         }  
  7.   
  8.         @Override  
  9.         protected void onPreExecute() {  
  10.             super.onPreExecute();  
  11.         }  
  12.   
  13.         @Override  
  14.         protected Object doInBackground(Object[] params) {  
  15.             String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";  
  16.             byte[] buf = Util.httpPost(url, str);  
  17.             String content = new String(buf);  
  18.             return content;  
  19.         }  
  20.     }  
这里从微信返回来的正确的结果为:xml格式的字符串,里面的“prepay_id”就是我们需要用在调取支付界面所要的重要参数。其中的Util.httpPost(url, str)方法可以在微信提供的demo中拷贝过来就行。(在这一步很多时候都返回的是“签名错误”,就要检查商户key是否正确,最常见的错误就是“body”字段是中文,然后post发送的时候没有转换为“iso8859-1”编码,导致签名错误。

4、通过统一下单接口成功获取到了“prepay_id”后,就可以调取支付接口了:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>@Override  
  2.         protected Object doInBackground(Object[] params) {  
  3.             String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";  
  4.             byte[] buf = Util.httpPost(url, str);  
  5.             String content = new String(buf);  
  6.             Map<String, String> map = xmlToMap(content);  
  7.             String nonceStr = CommonUtil.genNonceStr();  
  8.             String timeStamp = String.valueOf(CommonUtil.genTimeStamp());  
  9.             SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();  
  10.             parameters.put("appid", orderPaybean.getAppid());  
  11.             parameters.put("partnerid", orderPaybean.getMch_id());  
  12.             parameters.put("prepayid", map.get("prepay_id"));  
  13.             parameters.put("package""Sign=WXPay");  
  14.             parameters.put("noncestr", nonceStr);  
  15.             parameters.put("timestamp", timeStamp);  
  16.   
  17.             PayReq request = new PayReq();  
  18.             request.appId = orderPaybean.getAppid();  
  19.             request.partnerId = orderPaybean.getMch_id();  
  20.             request.prepayId = map.get("prepay_id");  
  21.             request.packageValue = "Sign=WXPay";  
  22.             request.nonceStr = nonceStr;  
  23.             request.timeStamp = timeStamp;  
  24.             request.sign = CommonUtil.createSign("UTF-8", parameters, AppConfig.WX_KEY);  
  25.             msgApi.sendReq(request);  
  26.             return content;  
  27.         }  

这里用到了把xml转换为list的方法(用的是dom4j.jar):

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>public Map<String, String> xmlToMap(String xmlstr) {  
  2.         Map<String, String> map = new HashMap<>();  
  3.   
  4.         try {  
  5.             SAXReader reader = new SAXReader();  
  6.             InputStream ins = new ByteArrayInputStream(xmlstr.getBytes("UTF-8"));  
  7.             Document doc = reader.read(ins);  
  8.             Element root = doc.getRootElement();  
  9.   
  10.             List<Element> list = root.elements();  
  11.   
  12.             for (Element e : list) {  
  13.                 map.put(e.getName(), e.getText());  
  14.             }  
  15.             ins.close();  
  16.         } catch (Exception e) {  
  17.             e.printStackTrace();  
  18.         }  
  19.         return map;  
  20.     }  

5、这样就成功的调到了支付界面 


这是刚开始解决中文乱码是,单独对中文转码后的结果,微信端没有转码,就成这样了。


这是body是英文的时候,能正常支付。

6、最后在微信回调页面处理支付结果:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler{  
  2.   
  3.     private IWXAPI api;  
  4.   
  5.     @Override  
  6.     public void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8. //      setContentView(R.layout.pay_result);  
  9.   
  10.         api = WXAPIFactory.createWXAPI(this, AppConfig.WX_APP_ID);  
  11.   
  12.         api.handleIntent(getIntent(), this);  
  13.     }  
  14.   
  15.     @Override  
  16.     protected void onNewIntent(Intent intent) {  
  17.         super.onNewIntent(intent);  
  18.         setIntent(intent);  
  19.         api.handleIntent(intent, this);  
  20.     }  
  21.   
  22.     @Override  
  23.     public void onReq(BaseReq req) {  
  24.     }  
  25.   
  26.     @Override  
  27.     public void onResp(BaseResp resp) {  
  28.   
  29.         System.out.println(resp.errCode);  
  30.         if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {  
  31.             if(resp.errCode == 0)  
  32.             {  
  33.                 AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  34.                 builder.setTitle("微信支付结果");  
  35.                 builder.setMessage("支付订单成功!");  
  36.                 builder.setPositiveButton("确定"new DialogInterface.OnClickListener() {  
  37.   
  38.                     @Override  
  39.                     public void onClick(DialogInterface dialog, int which) {  
  40.                         // TODO Auto-generated method stub  
  41.                         finish();  
  42.                     }  
  43.                 });  
  44.                 builder.show();  
  45.             }  
  46.             else if(resp.errCode == -1)  
  47.             {  
  48.                 CommonUtil.showToast("支付出错:" + resp.errStr);  
  49.                 finish();  
  50.             }  
  51.             else if(resp.errCode == -2)  
  52.             {  
  53.                 CommonUtil.showToast("取消支付");  
  54.                 finish();  
  55.             }  
  56.         }  
  57.     }  
  58. }  

这样微信支付爬坑结束,不容易啊。。。 哈哈哈
0 0
原创粉丝点击