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

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; 获取到。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容