微信
一、前期准备
- 在开放平台的“开发者引用登记界面”申请AppID,只有在开放平台上通过审核的应用才能集成微信支付的功能。
- 下载微信终端开发工具包【网址:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&token=&lang=zh_CN】
- 或在微信支付商户平台开发文档页面下载工具包和demo:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1
将工具包中libs目录下的libammsdk.jar复制到你的libs目录下,
- 【eclipse项目】右击选中“Configure Build Path…”—>“Add jars…”导入到工程中。如图:
【AndroidStudio项目】选中项目,按“F4”调出“Project Sructure”窗口,添加jar包到项目中。如图:
- 【eclipse项目】右击选中“Configure Build Path…”—>“Add jars…”导入到工程中。如图:
在清单文件中添加权限:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
添加混淆规则。在混淆配置文件proguard.cfg中,增加如下代码,否则,将导致无法弹出发送第三方消息的确认框。
-keep class com.tencent.mm.sdk.** { *;}
二、项目集成【微信支付目前的做法,凡是涉及签名的操作均交由后台服务器去做】
与微信建立通信联系:在代码中向微信APP注册你的APPId,可以在程序入口Activity的onCreate方法中,也可以在其他合适的地方进行注册。笔者比较喜欢在调用微信支付的时候才进行注册。
final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);msgApi.registerApp(Constants.APP_ID);
- 将用户选择的订单信息发送给后台服务器,由后台服务器调用微信支付API提供的统一下单接口等一系列和签名相关的操作,签名完成后,APP接收后台传送回来的prepay_id、sign等数据。
调用api.sendReq(req)发起支付。
//从后台获取返回的参数PayReq req = new PayReq();req.appId = json.getString("appid");req.partnerId = json.getString("partnerid");req.prepayId = json.getString("prepayid");req.nonceStr = json.getString("noncestr");req.timeStamp = json.getString("timestamp");req.packageValue = json.getString("package");req.sign = json.getString("sign");req.extData = "app data"; // optional// 发起支付。//在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信api.sendReq(req);
- 支付完成后,微信会同步返回一个支付结果给APP,并通过异步返回支付结果给后台服务器。
APP将支付结果发送给后台服务器,查询支付结果, 获取实际支付结果,并展示结果。
附一张微信支付流程图【摘自微信支付平台:)】
三、项目集成【APP端请求统一下单接口、进行签名,这是微信支付之前的做法,目前已经不支持,写在这里只是为了纪念一下那段苦逼的日子】
- 在调用微信支付的Activity的onCreate方法中实例化支付请求对象:
req = new PayReq(); 与微信建立通信联系:在代码中向微信APP注册你的APPId,可以在程序入口Activity的onCreate方法中,也可以在其他合适的地方进行注册。笔者比较喜欢在调用微信支付的时候才进行注册。
final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);msgApi.registerApp(Constants.APP_ID);
调用统一下单接口,生成预支付订单号prepay_id:
(1). URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
(2).开启任务:GetPrepayIdTask getPrepayId = new GetPrepayIdTask(); getPrepayId.execute();
(3).在任务中调用统一下单接口,获取prepay_id。
private class GetPrepayIdTask extends AsyncTask<Void, Void, Map<String, String>> { private ProgressDialog dialog; @Override protected void onPreExecute() { dialog = ProgressDialog.show(context, getString(R.string.app_tip), getString(R.string.getting_prepayid)); } @Override protected void onPostExecute(Map<String, String> result) { if (dialog != null) { dialog.dismiss(); } resultunifiedorder = result; System.out.println("result=" + result); // 生成签名参数 genPayReq(); // 调起支付接口 sendPayReq(); } @Override protected void onCancelled() { super.onCancelled(); } @Override protected Map<String, String> doInBackground(Void... params) { // 统一下单接口 String url = String //genProductArgs方法用来生成订单详细信息,在官方demo中有详细代码。 String entity = genProductArgs(); System.out.println("entity=" + entity); byte[] buf = Util.httpPost(url, entity); String content = new String(buf); System.out.println("content=" + content); Map<String, String> xml; try { xml = decodeXml(new String(content.getBytes("iso8859-1"), "utf-8")); return xml; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } }
订单详细信息中需要注意的几个参数:
- notify_url:微信和我们后台建立链接的HTTP协议地址,在支付完成后,微信会通过这个地址向我们的后台服务器发送支付结果。
- out_trade_no:这个参数是我们服务器生成的订单编号。
- spbill_create_ip:终端IP,我们服务器定好的。
- total_fee:订单金额,单位为分。
- 返回订单详情时一定要注意中文编码问题:String(xmlstring.toString().getBytes(), “ISO8859-1”)。
任务执行完成后,将参数重新签名。
//在任务执行完成后调用这个方法。private void genPayReq() { req.appId = Constants.APP_ID; req.partnerId = Constants.MCH_ID; req.prepayId = resultunifiedorder.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); }
发起支付。
msgApi.sendReq(req);
回调支付结果
在包名路径下创建新的文件夹wxapi,并在此文件夹下创建WXPayEntryActivity类,注意:文件夹名称和类名称必须按照这样命名,否则会导致无法回调。在类中实现onResp方法,支付完成后微信APP会返回到我们的APP上,并回调此方法。我们要做的就是在这个方法中接收通知,判断返回码,如果支付成功则将返回结果发送给后台服务器,查询支付结果再向用户展示实际支付结果。千万要记住:不能以APP返回的结果作为用户支付的结果,要以后台服务器接收的异步通知或从后台查询得知的结果位准。