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;
获取到。
网友评论