主要记录自己在集成微信支付功能所踩的坑。
##### 1.开发准备 1.注册微信开发者账号 2.注册微信商户号 3.[微信官方文档] (https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5) 4.官方Demo
上面1和2看官方的注册流程来就ok,在开放平台注册你目前所开发的App应用,这里需要你App应用签名,微信官方提供查看签名的工具(资源下载中下载签名工具)。这里需要注意的是App审核通过之后需要申请支付功能,里面所关联的商户号才是你在开发中需要的(商户ID)。
##### 2.资源配置 1.导入微信支付的Jar包 2.Manifest中添加微信支付所需要的权限如下:
注意:在集成的过程中要按照 官方Demo中src的目录结构来 也就是本应用的包名+.wxapi 官方Demo中在调微信支付逻辑处理已经在后台处理好了(关于钱的事就没有小事情),所以只需要把接口请求过 来的数据传回去就支付功能就成功了(论好的后台人员的重要性),然而我并没遇到这样的好事情微信所需要的nonce_str,sign,prepay_id都需要自己处理。
在进行代码逻辑处理的时候强烈建议好好阅读API列表
部分逻辑代码: ruby //微信发送请求到第三方应用时,会回调到该方法 @Override public void onReq(BaseReq req) { Log.e("11111111111", req.toString()); }
//第三方应用发送到微信的请求处理后的响应结果,会回调到该方法 @Override public void onResp(BaseResp resp) { if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.app_tip); String code = String.valueOf(resp.errCode); if (code.equals("0")) { builder.setMessage(getString(R.string.pay_result_callback_msg, "支付成功")); builder.show(); } else if (code.equals("-1")) { builder.setMessage(getString(R.string.pay_result_callback_msg, "支付失败")); builder.show(); } else if (code.equals("-2")) { builder.setMessage(getString(R.string.pay_result_callback_msg, "用户取消支付")); builder.show(); } } } //微信支付 private class GetPrepayIdTask extends AsyncTask<Void, Void, Map<String, String>> { private StringBuffer sb = new StringBuffer(); private Map<String, String> result; private PayReq req = new PayReq(); private IWXAPI mApi; private Context mContext; private double price; private String orderNo; private String orderNos; private ProgressDialog dialog; public GetPrepayIdTask(Context context, double price, String orderNo, String orderNos) { mApi = WXAPIFactory.createWXAPI(context, null); this.mContext = context; this.price = price; this.orderNo = orderNo; this.orderNos = orderNos; } @Override protected void onPreExecute() { dialog = ProgressDialog.show(WXPayEntryActivity.this, "提示", "正在获取预支付订单..."); } @Override protected void onPostExecute(Map<String, String> resultMap) { if (dialog != null) { dialog.dismiss(); } sb.append("prepay_id\n" + resultMap.get("prepay_id") + "\n\n"); result = resultMap; genPayReq(); mApi.registerApp(wxId); //调支付 mApi.sendReq(req); } // 生成最终签名,和最终的请求参数 private void genPayReq() { req.appId = wxId; req.partnerId = wxPartenr; req.prepayId = result.get("prepay_id"); req.packageValue = "Sign=WXPay"; 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)); req.sign = genAppSign(signParams); sb.append("sign\n" + req.sign + "\n\n"); Log.e("orion", signParams.toString()); } private String genAppSign(List<NameValuePair> signParams) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < signParams.size(); i++) { sb.append(signParams.get(i).getName()); sb.append('='); sb.append(signParams.get(i).getValue()); sb.append('&'); } sb.append("key="); sb.append(wxPartenrKey); this.sb.append("sign str\n" + sb.toString() + "\n\n"); String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(); Log.e("orionAppSign", appSign); return appSign; } @Override protected void onCancelled() { super.onCancelled(); } @Override protected Map<String, String> doInBackground(Void... params) { String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder"); String entity = genProductArgs(); //post请求 byte[] buf = Util.httpPost(url, entity); String content = new String(buf); Log.e("orion", content); Map<String, String> xml = decodeXml(content); return xml; } } // 以xml的方式来统一下单参数,获取prepay_id private String genProductArgs() { StringBuffer xml = new StringBuffer(); try { String nonceStr = genNonceStr(); xml.append("</xml>"); List<NameValuePair> packageParams = new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair("appid", wxId)); packageParams.add(new BasicNameValuePair("body", mPaySn + "")); packageParams.add(new BasicNameValuePair("mch_id", wxPartenr)); packageParams.add(new BasicNameValuePair("nonce_str", nonceStr)); packageParams.add(new BasicNameValuePair("notify_url", notify_url)); packageParams.add(new BasicNameValuePair("out_trade_no", mPaySn)); double moneyOfCent = MathUtil.multiply(mPrice + "", "100"); int total_fee = (int) moneyOfCent; packageParams.add(new BasicNameValuePair("spbill_create_ip", "127.0.0.1")); packageParams.add(new BasicNameValuePair("total_fee", total_fee + "")); packageParams.add(new BasicNameValuePair("trade_type", "APP")); //签名 String sign = genPackageSign(packageParams); packageParams.add(new BasicNameValuePair("sign", sign)); String xmlstring = toXml(packageParams); return xmlstring; } catch (Exception e) { // Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage()); return null; } } private Map<String, String> decodeXml(String content) { try { Map<String, String> xml = new HashMap<String, String>(); XmlPullParser parser = Xml.newPullParser(); parser.setInput(new StringReader(content)); int event = parser.getEventType(); while (event != XmlPullParser.END_DOCUMENT) { String nodeName = parser.getName(); switch (event) { case XmlPullParser.START_DOCUMENT: break; case XmlPullParser.START_TAG: if ("xml".equals(nodeName) == false) { // 实例化student对象 xml.put(nodeName, parser.nextText()); } break; case XmlPullParser.END_TAG: break; } event = parser.next(); } return xml; } catch (Exception e) { Log.e("orion", e.toString()); } return null; } private String toXml(List<NameValuePair> params) { StringBuilder sb = new StringBuilder(); sb.append("<xml>"); for (int i = 0; i < params.size(); i++) { sb.append("<" + params.get(i).getName() + ">"); sb.append(params.get(i).getValue()); sb.append("</" + params.get(i).getName() + ">"); } sb.append("</xml>"); Log.e("orion", sb.toString()); return sb.toString(); } // 生成签名 private String genPackageSign(List<NameValuePair> params) { 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(wxId); String packageSign = MD5.getMessageDigest(sb.toString().getBytes()) .toUpperCase(); Log.e("orionStringBuilder", sb.toString()); Log.e("orionAppMd5", packageSign); return packageSign; } //随机字符串 private String genNonceStr() { Random random = new Random(); return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } // 时间戳 private long genTimeStamp() { return System.currentTimeMillis() / 1000; }总结: GetPrepayIdTask 继承自 AsyncTask,是辅助用来后台执行然后更新UI 1.先生成预支付交易订单(需要xml来统一接口参数需要生成签名),获取到prepay_id后将参数再次签名传输给APP发起支付 2.参数签名时一定要保证有序(按参数名ASCII码从小到大排序),签名要转换成大写形式 3.App_Id 和 商户ID 不匹配的,查看开放平台中所绑定的商户号是那个? 4.调支付返回-1 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。