android 微信、支付宝支付踩坑之旅

这两天为项目集成微信、支付宝支付功能写demo。多多少少遇到些坑,把这些记录一下,防止再掉进去。

自动代扣

又称“委托代扣”,“委托扣费”。使用不当会造成很严重的结果。也是比较流氓的功能。功能例子嘛:参考微博会员,爱奇艺会员,滴滴打车,Uber。基本就是在一次购买之后,每月会自动扣费,一旦中招很难察觉。但是无论微信还是支付宝,会员自动扣费的功能都是没有对普通开发者开放的,需要深度合作,查了半天资料,才确定金坷垃是不要想了。
不过意外的发现了两个开发文档,就当参考吧

微信委托代扣开发步骤指引
支付宝代扣服务协议

下面是正篇

微信

微信的各种平台很多,支付开发,首先要来这里微信开放平台
1.创建一个应用,
2.审核通过后,再申请开放微信支付的权限。
3.审核的过程中会发给你一个微信商户平台的账号
做完了这些就可以开始正式开发了(总共大概需要几天时间,企业的话需要银行对公账户)
微信支付的demo比较坑,文档上说了好多资源,实际下载下来只有一个SDK的jar包和html的Javadoc,其他的基本靠猜,好在之前做过微信登录,基本逻辑差不多。(而且微信登录和微信支付其实SDK都是同一个)

微信SDKAndroid资源下载

微信支付开发文档

腾讯的产品,参数中代签名,签名逻辑从来都是很麻烦的,不过还好,这部分内容扔给服务端了,客户端这边就是掉个接口,所有参数就都有了
写个解析类大概这样

public class WxOrdersBean {
    public String appid;
    public String noncestr;
    public String partnerid;
    public String prepayid;
    public String sign;
    public String timestamp;

    public WxOrdersBean() {
    }

    @Override
    public String toString() {
        return "WxOrdersBean{" +
                "appid='" + appid + '\'' +
                ", noncestr='" + noncestr + '\'' +
                ", partnerid='" + partnerid + '\'' +
                ", prepayid='" + prepayid + '\'' +
                ", sign='" + sign + '\'' +
                ", timestamp='" + timestamp + '\'' +
                '}';
    }
}

这时,在Activity中可以对微信发起支付请求了

public void payByWeChat(WxOrdersBean wxOrdersBean) {
        //这些参数全部来自服务端
        IWXAPI api = WXAPIFactory.createWXAPI(getApplicationContext(), null);
        api.registerApp(AppID);
        PayReq request = new PayReq();
        request.appId = wxOrdersBean.appid;//微信开放平台审核通过的应用APPID
        request.partnerId = wxOrdersBean.partnerid;//微信支付分配的商户号
        request.prepayId = wxOrdersBean.prepayid;//微信返回的支付交易会话ID
        request.packageValue = "Sign=WXPay";//暂填写固定值Sign=WXPay
        request.nonceStr = wxOrdersBean.noncestr;//随机字符串,不长于32位。推荐随机数生成算法
        request.timeStamp = wxOrdersBean.timestamp;//时间戳,请见接口规则-参数规定
        request.sign = wxOrdersBean.sign;//签名,详见签名生成算法
        api.sendReq(request);
    }

这中间会遇到一些问题:
1.服务端签名错误,比如签名时没有区分大小写,拼写错误,再有就是可能没加入Sign=WXPay这类的
2.客户端APP签名错误,微信客户端在被调起时会检查发起者的签名,一般需要正式keystore签名过的才可以调起,建议先做微信分享或者微信登录,如果成功完成,那么微信支付基本不会是客户端的错误。这样有利于错误定位,排除客户端的原因。
3.关于微信的回调,按照微信一贯的蛋疼作风自然回调要在指定名字的 包名.wxapi.WXPayEntryActivity里

<activity
       android:name=".wxapi.WXPayEntryActivity"
       android:exported="true"
       android:launchMode="singleTop" />

WXPayEntryActivity. java

public static final int CODE_SUCCESS = 0;
public static final int CODE_ERROR = -1;
public static final int CODE_CANCLE = -2;
IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
    api = WXAPIFactory.createWXAPI(getApplicationContext(), AppID);
    api.handleIntent(getIntent(), this);
}
    
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    api.handleIntent(intent, this);
}
@Override
public void onReq(BaseReq baseReq) {

}
@Override
public void onResp(BaseResp baseResp) {
     if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
        if (baseResp.errCode == CODE_SUCCESS) {
            //在这里需要向自己的服务器发送请求查询是否真正成功
         } else if (baseResp.errCode == CODE_ERROR) {

         } else if (baseResp.errCode == CODE_CANCLE) {
          
         }
         
     }
 }

支付宝

其实支付宝要和微信做的也差不多,都是向自己服务端发起请求,获取参数和签名,通知支付宝客户端进行支付,返回结果后去自己服务器查询实际结果。
这里也会有几个问题
1.还是两个认证,一个蚂蚁金服商家账号,一个开发账号,这次可以是同一个用户名,不过都要填写认真资料。
2.还是签名,服务端的签名这次是需要自己生成RSA的公钥和私钥,并且把公约上传,用私钥签名。
3.注意沙箱环境!!!
沙箱环境用它生成的沙箱应用,新的APPID,公钥也需要重新上传,客户端需要在调起支付宝前加入代码

EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);

同时对应的要在文档下载指定的沙箱支付宝客户端,支付宝登录使用沙箱用户登录

 <activity
      android:name="com.alipay.sdk.app.H5PayActivity"
      android:configChanges="orientation|keyboardHidden|navigation|screenSize"
      android:exported="false"
      android:screenOrientation="behind"
      android:windowSoftInputMode="adjustResize|stateHidden"></activity>
<activity
      android:name="com.alipay.sdk.app.H5AuthActivity"
      android:configChanges="orientation|keyboardHidden|navigation"
      android:exported="false"
      android:screenOrientation="behind"
      android:windowSoftInputMode="adjustResize|stateHidden"></activity>

另外不得不说。RxJava简直不要太爽,上述逻辑完全可以封装成一个方法

MyClient.orderApi().aliOrderRx(...)//这部分是retrofit 返回一个Observable 参数略
                .subscribeOn(Schedulers.io())
                .map(new Func1<AliOrderBean, String>() {
                    @Override
                    public String call(AliOrderBean aliOrderBean) {
                        //这里将返回参数拼接成一段字符串,签名已经在参数中,不要在这里签名
                        Map<String, String> params=OrderInfoUtil2_0.buildOrderParamMap(aliOrderBean);
                        return OrderInfoUtil2_0.buildOrderParam(params);
                    }
                })
                .map(new Func1<String, AliPayResult>() {
                    @Override
                    public AliPayResult call(String orderInfo) {
                        //这里调用支付宝的支付SDK 是按照文档需要在非主线程
                        EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
                        PayTask alipay = new PayTask(activity);
                        Map<String, String> result = alipay.payV2(orderInfo, true);
                        return new AliPayResult(result);
                    }
                })
                .flatMap(new Func1<AliPayResult, Observable<String>>() {
                    @Override
                    public Observable<String> call(AliPayResult aliPayResult) {
                        /**
                         对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
                         */
                        String resultStatus = aliPayResult.getResultStatus();
                        // 判断resultStatus 为9000则代表支付成功
                        if (TextUtils.equals(resultStatus, "9000")) {
                                //这里发起网络请求查询支付结果
                                return MyClient.getAliOrderRx(...);  
                        }
                        //TODO 这里可能需要更合理的返回错误方式
                        throw new Error(aliPayResult.toString());
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                //这里交个外部传入的observer来处理对应的结果
                .subscribe(observer);

阿里还是很良心的,demo写的相当全,上面的代码很大一部分都来自官方的demo中,包括AliPayResult,OrderInfoUtil2_0这两个类。

App支付Android调用说明
App支付DEMO&SDK

    原文作者:夕枫晚照
    原文地址: https://www.jianshu.com/p/5a3a07045706
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞