小铲子 发表于 2015-12-29 12:34:31

[Android实例] Android微信支付彻底扫坑


由于公司运营需要,Android客户端要增加微信支付。在看了几遍官方文档之后,加上之前有集成微信分享的经验,所以很快就把调用微信支付的代码写好了,待微信支付相关接口完成后联调时,才发现山高路远坑深啊!从下午2点半开始调试,一直折腾到快6点,那个微信支付界面才“千呼万唤始出来”,更坑爹的是,压根儿就不是我客户端的问题,而是后台接口那边sign生成时出了问题。在解决问题的过程中,看到网上太多关于微信支付各种问题的帖子,但遗憾的是并没有找到真正有效的解决方案,所以就来彻底扫一下Android集成微信支付中的坑。首先讲一下我们的逻辑,如微信支付开发文档(https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=8_5)中Android部分描述的那样,由服务器端请求微信支付平台生成prepayid,大家一般也都是这么做的,发现网上有一部分人从服务器端拿到prepayid后,在客户端自己拼字符串参数,然后调用算法生成sign,这样是可以,但是安全性不好,而且客户端逻辑也变复杂了,估计大家是按照官方demo写的,至于其demo暂时就不评价了,下面会提及。我们的做法是所有的必要参数,如partnerId、prapayId、packageValue、nonceStr、timeStamp、sign等都是由服务器端生成,至于appId自己写在客户端也行,服务器端传过来也行,因为之前微信分享appId是写在客户端了,因此微信支付就没让服务器端返回appId这个参数。其实微信支付官方文档也是这样建议的,原文为“商户服务器生成支付订单,先调用统一下单API(详见第7节)生成预付单,获取到prepay_id后将参数再次签名传输给APP发起支付”。App端拿到上述6个主要参数后,加上appId,一共7个,就可以调起支付了。如上所述,客户端的逻辑就这么简单,所以当调试时竟然调不出支付界面,真觉得不可思议。我遇到的问题是这样的:当发起支付时调不出微信支付界面,直接响应WXPayEntryActivity中的onResp回调,并且errCode始终返回-1。如果微信未登录,则会调起登陆界面,登陆完成后还是调不起来,errCode依然返回-1。我们客户端的实现逻辑基本跟官方文档一致(注意官方文档有个书写错误,在调用支付部分代码最后一行的参数中,request写成了req,后面也会提到),主要核心代码如下:1.首先注册,其中api为IWXAPI的实例
view plaincopy



[*]api = WXAPIFactory.createWXAPI(context, APP_ID, false);
[*]api.registerApp(APP_ID);

2.从服务端拿到上述必要参数后,调支付即可,其中params是自定义的用来保存从服务端获取的所有的对象

view plaincopy



[*]if (api != null) {
[*]    if (isWXAppInstalled()) {
[*]      PayReq req = new PayReq();
[*]      req.appId = APP_ID;
[*]      req.partnerId = params.getPartnerId();
[*]      req.prepayId = params.getPrepayId();
[*]      req.packageValue = params.getPackageValue();
[*]      req.nonceStr = params.getNonceStr();
[*]      req.timeStamp = params.getTimeStamp();
[*]      req.sign = params.getSign();
[*]
[*]      api.sendReq(req);
[*]    }
[*]}

3.WXPayEntryActivity这个回调界面实际上不会影响前面的调起支付的逻辑,写过微信分享的应该知道,这个Activity一定要放到“App包名.wxapi”的package中,否则无法响应回调,当然别忘了在AndroidManifest.xml中注册。微信分享的回调WXEntryActivity也是这样的,放在同一个包即可。没错,微信就是这么霸道。
Android客户端的核心逻辑就是这些,下面来一一列举微信支付中的坑,或者叫注意点吧,有些是我知道因此没有亲自踩上去的也一并列出。1.首先如果要使用微信支付的话,必须先到微信开放平台注册应用,具体地址为https://open.weixin.qq.com/,注册时需要填应用的包名和签名,注意这里的签名是App正式版的签名,可以找一个已上线的包或打一个正式包,使用微信提供的工具(签名工具下载地址为https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk)来获取,获取后填上即可。待审核通过后,会得到一个AppID和AppSecret,AppID分享和支付都要用到,AppSecret没什么实际用途,此时微信分享能力是直接拥有的,支付能力还要额外申请,其中涉及到财务信息等,最好让公司财务部门去申请,申请成功后会拿到一个商户id,后面生成sign时会用到。只有所有审核都通过后,才可调用微信支付功能,这点是前提。2.微信分享和微信支付SDK是同一个架包,名为libammsdk.jar。3.官方开发文档中有一处错误,需要注意下,如下图最后一行参数req应该为request,照搬代码的估计IDE也不会放过你,哈哈。http://img.blog.csdn.net/20151204132429106?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
4.测试微信支付时,务必对自己的App做正式签名,因为一开始就在微信平台注册过签名信息,微信SDK会做校验,只有这样才能调起微信分享和微信支付,直接debug版的包则绝对调不起来,这点务必注意,很多人是跌在这里了!当初做微信分享曾遇到过,所以会很留心,也因为如此,如果微信分享能调起来,微信支付不行,那就不要怀疑签名问题了。5.还是签名,网上有人说要注意大小写,这点其实是不必的。在微信开放平台看到审核通过的App的签名是大写的,而用微信签名获取工具获得的则显示小写,这个没关系,不要贸然改动平台注册信息,不然又可能导致漫长的审核等待,上面也说了,微信分享如可以,那就不是签名问题。6.来说下官方demo,这东西害人不浅啊!很多人参考其写法,如生成sign放在客户端啊,调支付的Activity添加intent-filter啊,最主要的还是签名问题。其实客户端逻辑很简单,直接上手集成即可,demo看看逻辑就行,照抄小心掉坑里。7.网上有人说需要给调用支付的Activity配置如下intent-filter(见下图),可能也是被demo误导了


[*]<intent-filter>
[*]    <action android:name="android.intent.action.VIEW"/>
[*]    <category android:name="android.intent.category.DEFAULT"/>
[*]    <data android:scheme="appid"/>
[*]</intent-filter>
原文可以参考个人CSDN博客:http://blog.csdn.net/ahence/article/details/50173621

页: [1]
查看完整版本: [Android实例] Android微信支付彻底扫坑