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中)
- <span style="white-space:pre"> </span>msgApi = WXAPIFactory.createWXAPI(context, null);
- msgApi.registerApp(AppConfig.WX_APP_ID);
(2):调用统一下单接口(https://api.mch.weixin.qq.com/pay/unifiedorder)生成订单,这一步是最容易出错的(此乃大坑)。
1、首先我们设计好所要传给微信的必要参数(OrderPayBean):
- private String appid;
- private String body;
- private String mch_id;
- private String nonce_str;
- private String notify_url;
- private String out_trade_no;
- private String spbill_create_ip;
- private int total_fee;
- private String trade_type;
- private String sign;
例如以下商品数据:
- <span style="white-space:pre"> </span>
- orderPaybean.setAppid(AppConfig.WX_APP_ID);
- orderPaybean.setBody("操蛋的微信支付");
- orderPaybean.setMch_id(AppConfig.WX_MCH_ID);
- orderPaybean.setNonce_str(nonceStr);
- orderPaybean.setNotify_url("http://********/payNotify/wx.do");
- orderPaybean.setTotal_fee(1);
- <span style="white-space:pre"> </span>
- orderPaybean.setTrade_type("APP");
- orderPaybean.setSpbill_create_ip("196.168.1.1");
2、商品参数准备好了,接下来我们为之生成签名:签名算法如下:
-
-
-
-
-
-
- @SuppressWarnings("unchecked")
- public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters, String key){
- 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=" + key);
- System.out.println(sb.toString());
- String sign = WxMd5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
- System.out.println(sign);
- return sign;
- }
构造商品参数集合:
- <span style="white-space:pre"> </span>SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
- parameters.put("appid", orderPaybean.getAppid());
- parameters.put("body", orderPaybean.getBody());
- parameters.put("mch_id", orderPaybean.getMch_id());
- parameters.put("nonce_str", orderPaybean.getNonce_str());
- parameters.put("notify_url", orderPaybean.getNotify_url());
- parameters.put("out_trade_no", orderPaybean.getOut_trade_no());
- parameters.put("total_fee", orderPaybean.getTotal_fee());
- parameters.put("trade_type", orderPaybean.getTrade_type());
- parameters.put("spbill_create_ip", orderPaybean.getSpbill_create_ip());
- parameters.put("sign", CommonUtil.createSign("UTF-8", parameters, AppConfig.WX_KEY));
3、因为统一下单接口需要以xml格式post发送给微信,所以我们先拼接xml格式的参数:
- <span style="white-space:pre"> </span>StringBuilder xmlBuilder = new StringBuilder();
- xmlBuilder.append("<xml>");
- 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();
- xmlBuilder.append("<").append(k).append(">");
- xmlBuilder.append(v);
- xmlBuilder.append("</").append(k).append(">");
- }
- xmlBuilder.append("</xml>");
- System.out.println(xmlBuilder.toString());
- try {
- new GetPrepayId(new String(xmlBuilder.toString().getBytes(), "ISO8859-1")).execute();
- } catch (Exception e) {
- e.printStackTrace();
- }
然后是我们的异步线程请求统一下单接口:
- <span style="white-space:pre"> </span>public class GetPrepayId extends AsyncTask {
- String str;
-
- public GetPrepayId(String str) {
- this.str = str;
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- }
-
- @Override
- protected Object doInBackground(Object[] params) {
- String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
- byte[] buf = Util.httpPost(url, str);
- String content = new String(buf);
- return content;
- }
- }
这里从微信返回来的正确的结果为:xml格式的字符串,里面的“prepay_id”就是我们需要用在调取支付界面所要的重要参数。其中的Util.httpPost(url, str)方法可以在微信提供的demo中拷贝过来就行。(在这一步很多时候都返回的是“签名错误”,就要检查商户key是否正确,最常见的错误就是“body”字段是中文,然后post发送的时候没有转换为“iso8859-1”编码,导致签名错误。4、通过统一下单接口成功获取到了“prepay_id”后,就可以调取支付接口了:
- <span style="white-space:pre"> </span>@Override
- protected Object doInBackground(Object[] params) {
- String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
- byte[] buf = Util.httpPost(url, str);
- String content = new String(buf);
- Map<String, String> map = xmlToMap(content);
- String nonceStr = CommonUtil.genNonceStr();
- String timeStamp = String.valueOf(CommonUtil.genTimeStamp());
- SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
- parameters.put("appid", orderPaybean.getAppid());
- parameters.put("partnerid", orderPaybean.getMch_id());
- parameters.put("prepayid", map.get("prepay_id"));
- parameters.put("package", "Sign=WXPay");
- parameters.put("noncestr", nonceStr);
- parameters.put("timestamp", timeStamp);
-
- PayReq request = new PayReq();
- request.appId = orderPaybean.getAppid();
- request.partnerId = orderPaybean.getMch_id();
- request.prepayId = map.get("prepay_id");
- request.packageValue = "Sign=WXPay";
- request.nonceStr = nonceStr;
- request.timeStamp = timeStamp;
- request.sign = CommonUtil.createSign("UTF-8", parameters, AppConfig.WX_KEY);
- msgApi.sendReq(request);
- return content;
- }
这里用到了把xml转换为list的方法(用的是dom4j.jar):
- <span style="white-space:pre"> </span>public Map<String, String> xmlToMap(String xmlstr) {
- Map<String, String> map = new HashMap<>();
-
- try {
- SAXReader reader = new SAXReader();
- InputStream ins = new ByteArrayInputStream(xmlstr.getBytes("UTF-8"));
- Document doc = reader.read(ins);
- Element root = doc.getRootElement();
-
- List<Element> list = root.elements();
-
- for (Element e : list) {
- map.put(e.getName(), e.getText());
- }
- ins.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return map;
- }
5、这样就成功的调到了支付界面
这是刚开始解决中文乱码是,单独对中文转码后的结果,微信端没有转码,就成这样了。
这是body是英文的时候,能正常支付。6、最后在微信回调页面处理支付结果:
- public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler{
-
- private IWXAPI api;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
-
- api = WXAPIFactory.createWXAPI(this, AppConfig.WX_APP_ID);
-
- api.handleIntent(getIntent(), this);
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- setIntent(intent);
- api.handleIntent(intent, this);
- }
-
- @Override
- public void onReq(BaseReq req) {
- }
-
- @Override
- public void onResp(BaseResp resp) {
-
- System.out.println(resp.errCode);
- if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
- if(resp.errCode == 0)
- {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle("微信支付结果");
- builder.setMessage("支付订单成功!");
- builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
-
- finish();
- }
- });
- builder.show();
- }
- else if(resp.errCode == -1)
- {
- CommonUtil.showToast("支付出错:" + resp.errStr);
- finish();
- }
- else if(resp.errCode == -2)
- {
- CommonUtil.showToast("取消支付");
- finish();
- }
- }
- }
- }
这样微信支付爬坑结束,不容易啊。。。 哈哈哈 0 0