美文网首页
解决微信支付失败-1的坑

解决微信支付失败-1的坑

作者: CokeNello | 来源:发表于2019-04-01 19:05 被阅读0次

    1. 基本使用

    最近公司需要用到微信支付,后台说已经搞好了所有的签名,好吧,我直接调用微信的接口就好了:

    • 接入依赖
    //微信支付
    implementation 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
    
    • 使用:
    //微信支付调起来
      IWXAPI api =WXAPIFactory.createWXAPI(getContext(),null);
      api.registerApp(HttpsContract.Wx_Pay_App_Id);
      PayReq req = new PayReq();//PayReq就是订单信息对象
      //给req对象赋值
      req.appId = HttpsContract.Wx_Pay_App_Id;//APP-ID
      req.partnerId = wxPayBean.payWxBean.mchId;//    商户号
      req.prepayId = wxPayBean.payWxBean.prepayId;//  预付款ID
      req.nonceStr = wxPayBean.payWxBean.nonceStr;//随机数
      req.timeStamp = wxPayBean.payWxBean.timestamp;//时间戳
      req.packageValue = wxPayBean.payWxBean.signType;//固定值Sign=WXPay
      req.sign = wxPayBean.payWxBean.paySign;//签名
      api.sendReq(req);//将订单信息对象发送给微信服务器,即发送支付请求
    

    上面其中,除了 HttpsContract.Wx_Pay_App_Id 外,其他所有的都是服务器接口返回给我的,好了,确实挺简单的。

    • 接收微信支付的结果返回,WXPayEntryActivity ,名称不能错,一定要这个,写死,而且要放在:<你的包名>.wxapi.下!
    public class WXPayEntryActivity extends BaseActivity implements IWXAPIEventHandler {
        private IWXAPI api;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_wxpay_entry);
            api = WXAPIFactory.createWXAPI(this, HttpsContract.Wx_Pay_App_Id);
            api.handleIntent(getIntent(), this);
        }
    
        @Override
        public void onReq(BaseReq baseReq) {
        }
    
        @Override
        public void onResp(BaseResp baseResp) {
            if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
                Log.i("WXPayEntryActivity",
                        "onPayFinish, errCode = " + baseResp.errCode
                                + ", errStr: " + baseResp.errStr
                                + ", openId: " + baseResp.openId
                                + ", transaction: " + baseResp.transaction);
                int errCord = baseResp.errCode;
                if (errCord == 0) {
                    toast("支付成功!");
                } else {
                    toast("支付失败");
                }
                finish();
            }
        }
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            setIntent(intent);
            api.handleIntent(intent, this);
        }
    }
    
    • AndroidManifest文件中注册这个Activity:
     <!--微信支付 -->
    <activity
        android:name=".wxapi.WXPayEntryActivity"
        android:exported="true"
        android:launchMode="singleTop">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="${WX_Pay_AppId}" />
        </intent-filter>
    </activity>
    

    2. 调起失败,-1

    说实话,这个问题真的很恶心,微信开放平台提供的文档在关于-1这个问题的描述(可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等)。一开始我看到这个说明的时候,我的内心是崩溃的,这说了跟没说有什么区别。

    3. 排查

    还是一步一步来仔细排查吧!

    APP-ID不对

    APP-ID是指这个,一般不会有人写错吧?(不好意思我是二班的)

    Snipaste_2019-04-01_18-38-07.png

    要仔细检查!有很多地方用到了这个IP:初始化 IWXAPI 用到了,分别在调起支付的时候,和接收支付回包的时候,还有,在 manifest 中声明 activity 的时候用到。

    签名、包名问题

    签名在后台配置的,位置在这里:

    Snipaste_2019-04-01_18-41-07.png

    不管你是 debug / release 都可以,只要是签名和后台一样就可以了,我开发的时候,是把 debug 和 release 的签名都用同一个,debug 的时候就可以调起来了。还有这里的包名也要仔细核对!

    使用微信分享接口来验证上述的信息是否有误

    因为一般申请了支付的,都有申请了微信的分享接口,而分享接口,也是需要后台配置好签名,包名,所有我们可以先调用一下微信分享(不需要额外引用包):

    final IWXAPI api =WXAPIFactory.createWXAPI(getContext(),null);
    api.registerApp(HttpsContract.Wx_Pay_App_Id);
    WXWebpageObject webpage = new WXWebpageObject();
    webpage.webpageUrl = "http://www.baidu.com";
    WXMediaMessage msg = new WXMediaMessage(webpage);
    msg.title = "这里填写标题";
    msg.description = "这里填写内容";
    //这里替换一张自己工程里的图片资源
    Bitmap thumb = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
    msg.setThumbImage(thumb);
    SendMessageToWX.Req req = new SendMessageToWX.Req();
    req.transaction = String.valueOf(System.currentTimeMillis());
    req.message = msg;
    req.scene = SendMessageToWX.Req.WXSceneSession;
    api.sendReq(req);
    

    如果你在这里都调不起来分享,那就好好仔细检查信息吧!

    服务器返回的签名不对

    当时我就是被这里给坑了。首先,要先清楚大致的调用逻辑:

    • 1)客户端向自己服务器调用下单接口
    • 2)下单接口由自己服务器去调用微信服务器,注意,这里会返回一个签名!有人直接把这个签名返回给我了,擦,不对的哦!客户端需要一个二次签名!
    • 3)在自己服务器中做二次签名!关于怎么签名,你让后台小哥去百度吧
    • 4)或者,服务器不做签名,也好,我们客户端自己做!

    如果你是服务器中做二次签名,我们在这里就要开始怀疑服务器的二次签名有误,所有我们在代码中先,自己来写签名!(我们不相信别人,只相信自己的代码!),签名类我都帮你写好了:

    public class WXPayHelper {
    
        public IWXAPI api;
        private PayReq req;
    
        private String appId;
        private String prePayId;
        private String partNerId;
        private String partNerSecret;//商户密钥
    
        public WXPayHelper(Context context, String appId, String prePayId, String partNerId, String partNerSecret) {
            this.appId = appId;
            this.prePayId = prePayId;
            this.partNerId = partNerId;
            this.partNerSecret = partNerSecret;
            api = WXAPIFactory.createWXAPI(context, this.appId,false);
        }
    
        /**
         * 向微信服务器发起的支付请求
         */
        public void pay() {
            req = new PayReq();
            req.appId = appId;//APP-ID
            req.partnerId = partNerId;//    商户号
            req.prepayId = prePayId;//  预付款ID
            req.nonceStr = String.valueOf(System.nanoTime());                   //随机数
            req.timeStamp = String.valueOf(System.currentTimeMillis()*0.001);   //时间戳
            req.packageValue = "Sign=WXPay";//固定值Sign=WXPay
            req.sign = getSign();//签名
            api.registerApp(BuildConfig.WX_Pay_AppId);
            api.sendReq(req);
        }
    
        @NonNull
        private String getSign() {
            Map<String, String> map = new HashMap<>();
            map.put("appid", req.appId);
            map.put("partnerid", req.partnerId);
            map.put("prepayid", req.prepayId);
            map.put("package", req.packageValue);
            map.put("noncestr", req.nonceStr);
            map.put("timestamp", req.timeStamp);
    
            ArrayList<String> sortList = new ArrayList<>();
            sortList.add("appid");
            sortList.add("partnerid");
            sortList.add("prepayid");
            sortList.add("package");
            sortList.add("noncestr");
            sortList.add("timestamp");
            Collections.sort(sortList);
    
            StringBuilder md5 = new StringBuilder();
            int size = sortList.size();
            for (int k = 0; k < size; k++) {
                if (k == 0) {
                    md5.append(sortList.get(k)).append("=").append(map.get(sortList.get(k)));
                } else {
                    md5.append("&").append(sortList.get(k)).append("=").append(map.get(sortList.get(k)));
                }
            }
            String stringSignTemp = md5+"&key="+partNerSecret;
    
            return Md5(stringSignTemp).toUpperCase();
        }
    
        private String Md5(String s) {
            char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
            try {
                byte[] e = s.getBytes(StandardCharsets.UTF_8);
                MessageDigest mdTemp = MessageDigest.getInstance("MD5");
                mdTemp.update(e);
                byte[] md = mdTemp.digest();
                int j = md.length;
                char[] str = new char[j * 2];
                int k = 0;
                for (byte byte0 : md) {
                    str[k++] = hexDigits[byte0 >>> 4 & 15];
                    str[k++] = hexDigits[byte0 & 15];
                }
                return new String(str);
            } catch (Exception var10) {
                return null;
            }
        }
    }
    

    直接使用:

    WXPayHelper wxPayHelper = new WXPayHelper(getContext(),
            wxPayBean.payWxBean.appId,
            wxPayBean.payWxBean.prepayId,
            wxPayBean.payWxBean.mchId,
            "这里是商户号的密钥!");
    wxPayHelper.pay();
    

    如果,我们自己签名可以调起来,那么就是服务器的二次签名有问题,你可以拿刀问候一下后台小哥了。如果不是,那就好好检查信息!

    在这里我们看到自己签名会多用到一个商户号密钥,这很重要的,所以一般是放在服务器中。

    参考微信支付官方Demo?

    你参考我的还比较好。

    4. 统一APP-ID

    APP-ID在很多地方都用到了,AndroidManifest中,Java代码中,gradle 中,那么怎么统一起来呢?也许可以这样:

    • AndroidManifest,${WX_Pay_AppId} ,在Gradle中使用占坑的形式声明
     <!--微信支付 -->
    <activity
        android:name=".wxapi.WXPayEntryActivity"
        android:exported="true"
        android:launchMode="singleTop">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="${WX_Pay_AppId}" />
        </intent-filter>
    </activity>
    
    • Gradle:
    apply plugin: 'com.android.application'
    
    def WX_Pay_AppId = "wx12192u012091"
    
    android {
        //...
        defaultConfig {
            //...
            manifestPlaceholders = [
                    //微信支付APPID
                    WX_Pay_AppId : WX_Pay_AppId,
            ]
            //...
        }
        //...
        buildTypes {
            debug {
                //...
                buildConfigField "String", "WX_Pay_AppId", "\"$WX_Pay_AppId\""
                //...
            }
            release {
                //...
                buildConfigField "String", "WX_Pay_AppId", "\"$WX_Pay_AppId\""
                //...
            }
        }
    }
    

    在最上方声明好WX-APP-ID,然后,继续声明好 manifestPlaceholders ,映射到 Manifest 文件,最后,在 buildTypes 中,声明:buildConfigField ,做好映射到JAVA代码,在Java代码就可以:String Wx_Pay_App_Id = BuildConfig.WX_Pay_AppId; 获取到。

    相关文章

      网友评论

          本文标题:解决微信支付失败-1的坑

          本文链接:https://www.haomeiwen.com/subject/oqlbbqtx.html