关于如何申请 “微信公众平台开发账号” 和 “微信商户平台账号” 这些步骤,在这里就不再做介绍了,本文假设我们已经做好了所有的申请并已经被微信后台审核通过了。
第一步,打开 “微信公众平台” 后台,添加你的APP。在管理中心当中点击 “创建移动应用”, 填写一大堆资料后,通过审核,就可以获得一个AppID,例如:wx*********************。这里大家需要注意一点是,在你创建移动应用的过程当中,有一个叫做“应用签名”的参数,如何生成这个参数呢?这里有些要点,打开微信公众平台后台页面,点击 资源中心 > 资源下载 > 签名生成工具(https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&token=&lang=zh_CN),下载这个工具,这个东西下载后是一个.zip文件,然后把这个文件的后缀名改成.apk,发送到你的手机当中(记住这个手机要安装了你的APP才可以),然后安装这个apk,打开这个apk,输入你自己app的包名,什么是app包名,打开你的android studio打开model的build.gradle文件,找到applicationId,这个就是你要填写的包名。在填入包名后,就可以生成签名了,没错,就是这么简陋,手动把这个签名填到你的app信息当中,千万不要填错了。
第二步,当申请的APP通过审核后,进入后台在管理中心点击“查看”你自己申请的APP,就可以看到当前APP的详细信息,其中有一项“微信支付”,我们就是要申请这个功能,点击申请,然后又是填写一大堆资料,然后等审核通过,通过后,前期的工作就算准备好了。
第三步,正式接入SDK,首先当然去下载SDK,本人是使用AS,所以直接build.gradel直接加入这个compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'就可以了。用Eclipse的兄弟,可以自行参考官方文档下载SDK导入即可,但为了方便还是尽快使用gradle管理项目。
第四步,在你的项目根目录新建一个包,名字固定为“wxapi”,全部小写,例如:
在“wxapi”包下新建一个Activity,名字规定为“WXPayEntryActivity”,这个activity几乎为固定的内容,此activity的作用是当你成功调起微信支付并成功支付后,微信就会调用这个activity,说清楚,是成功调起微信支付并得到支付结果(成功或失败)后,微信SDK才会调起这个activity,此Activity无关重要但又不可缺少,如果你喜欢,甚至可以忽略为此activity做任何布局文件。此Activity看起来大概就是这个样子,只要存在于“wxapi”包之下,就可以了。
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
//这个就是你自己APP盛申请成功后在后台看到的appId。
private final String APP_ID = "wx******************";
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
api = WXAPIFactory.createWXAPI(this, APP_ID);
api.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
api.handleIntent(intent, this);
}
@Override
public void onReq(BaseReq req) {
//
}
//这个方法是支付结果的回调,大家可以随意开始你们的表演,也可以什么都不表演,像我一样直接finish。
@Override
public void onResp(BaseResp resp) {
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
if (resp.errCode == 0) {
System.out.println("支付成功");
} else {
System.out.println("支付失败, errorCode = " + resp.errCode);
}
finish();
}
}
}
最后在app清单当中声明此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**********************" />这个是你申请到的appId。
</intent-filter>
</activity>
以上步骤基本为固定步骤,一下的内容才是描述如何调起微信支付SDK。
第五步,在你需要调起微信支付的Activity去实现一个接口implements IWXAPIEventHandler,随意一个都可以。
public class XXXActivity extends Activity implements IWXAPIEventHandler {
private final String APP_ID = "wx**********************";
private IWXAPI mWeChatAPI;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pay);
}
@Override
public void onReq(BaseReq baseReq) {
}
@Override
public void onResp(BaseResp baseResp) {
}
private void payByWeChat(String item, String userId) {
Call<PrePayResponse> call = HttpManager.INSTANCE.getPrePay(item, userId);
if (call != null) {
call.enqueue(new Callback<PrePayResponse>() {
@Override
public void onResponse(@NonNull Call<PrePayResponse> call, @NonNull Response<PrePayResponse> response) {
final PrePayResponse prePayResponse = response.body();
if (prePayResponse != null) {
final String appId = prePayResponse.getAppId();
final String nonceStr = prePayResponse.getNonceStr();
final String partnerId = prePayResponse.getPartnerId();
final String timeStamp = prePayResponse.getTimeStamp();
final String prepayId = prePayResponse.getPrepayId();
final String packageValue = prePayResponse.getPackageValue();
String prePaySign = "appid=" + appId +
"&noncestr=" + nonceStr +
"&package=Sign=WXPay" +
"&partnerid=" + partnerId +
"&prepayid=" + prepayId +
"×tamp=" + timeStamp +
"&key=*******************************************";
final String paySign = CommonUtil.getMessageDigest(prePaySign.getBytes()).toUpperCase();
System.out.println("appId = " + appId);
System.out.println("nonceStr = " + nonceStr);
System.out.println("partnerId = " + partnerId);
System.out.println("sign = " + paySign);
System.out.println("timeStamp = " + timeStamp);
System.out.println("prepayId = " + prepayId);
System.out.println("packageValue = " + packageValue);
call.cancel();
new Thread(new Runnable() {
@Override
public void run() {
mWeChatAPI = WXAPIFactory.createWXAPI(PayEntryActivity.this, null);
mWeChatAPI.registerApp(APP_ID);
PayReq payReq = new PayReq();
payReq.appId = appId;
payReq.nonceStr = nonceStr;
payReq.partnerId = partnerId;
payReq.sign = paySign;
payReq.timeStamp = timeStamp;
payReq.prepayId = prepayId;
payReq.packageValue = packageValue;
mWeChatAPI.sendReq(payReq);
}
}).start();
finish();
} else {
System.out.println("prePayResponse body is null");
}
}
@Override
public void onFailure(@NonNull Call<PrePayResponse> call, @NonNull Throwable t) {
}
});
}
}
}
我们关注的是payByWeChat这个方法,不管你使用什么网络框架和你自己的服务器后台通信,你需要得到的都是一串Json,这个工作流程就是你自己的服务器后台首先需要去调用微信的统一支付接口,获得预付订单的返回信息,这里有2种情况,你公司的后台开发是一个极度懒惰的人(例如我公司那个),他就会把从微信得到的返回信息甚至原封不动的转发给你,最后你自己还要在app端对json做各种截取字符串的操作,自己进行二次签名。第二种情况是你公司的后台开发是一个负责人的人,他已经把各种你要的参数都处理好了,你从json里面得到的数据就是直接用于调起微信支付所需要的数据。现在我们从一个懒惰后台开发者的角度说一说如何处理这个json。
从你的服务器后台获取原始的预付订单信息后,我们从Json当中可以获得什么,举个例子:
{"appId":"wx******************",
"nonceStr":"****************************************",
"package":"prepay_id=wx******************************************",
"partnerId":"99999999999",
"paySign":"2767257DC4034263D73F3C22B718FCEA",
"signType":"MD5",
"timeStamp":"1507441751"}
这就是你从那个懒惰后台那里得到的,原始的微信预付订单信息,参考微信的文档,我们一共需要传递7个参数才能成功调起微信SDK的支付接口,他们分别是:
PayReq payReq = new PayReq();
payReq.appId = appId;
payReq.nonceStr = nonceStr;
payReq.partnerId = partnerId;
payReq.sign = paySign;
payReq.timeStamp = timeStamp;
payReq.prepayId = prepayId;
payReq.packageValue = packageValue;
新建一个PayReq对象,并为这7个参数赋值,其中一些,我们可以从json当中直接获取,例如appid,nonceStr ,partnerId等,但其中有3个参数我们需要额外注意,就是payReq.prepayId,payReq.packageValue和payReq.sign,payReq.packageValue是一个固定的值,值为“Sign=WXPay”,payReq.prepayId需要你从那个懒惰后台得到的json当中,从packge那个字段里面取出来,从“wx”这里开始取,前面的“prepay_id=”要去掉。下面重点说一下payReq.sign如何处理。
payReq.sign这个就是我们说的二次签名,需要什么来组成这个签名呢?答案是6个参数+1个key,6个参数就是上面PayReq 对象7个值当中除去payReq.sign这个值,key就是你在“微信商户平台”里面设置的那个key,看清楚,是微信商户平台后台里面设置的那个key,然后把这7个参数按照一定循序组合成一个字符串:
String prePaySign = "appid=" + appId +
"&noncestr=" + nonceStr +
"&package=Sign=WXPay" +
"&partnerid=" + partnerId +
"&prepayid=" + prepayId +
"×tamp=" + timeStamp +
"&key=你自己的key";
大家一定要注意,这个字符串拼接的顺序不能错,直接复制我的或者去https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=20_1这个页面,在校验方式里面选自定义,然后把这7个参数填入去,让工具为你自动生成这个顺序,这7个参数的名字也不能错,参考https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2这个页面当中的7个参数,直接复制参数的名字。在拼接完这个字符串后,我们就要用MD5为这个字符串生成校验码,不要用安卓自带的MD5,这里使用微信SDK内使用的那个方法:
static String getMessageDigest(byte[] buffer) {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(buffer);
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 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return "";
}
}
到此为止,你的二次签名算是完成了,最后凑齐7个龙珠,可以召唤神龙了,记得在另一个线程召唤。
new Thread(new Runnable() {
@Override
public void run() {
mWeChatAPI = WXAPIFactory.createWXAPI(PayEntryActivity.this, null);
mWeChatAPI.registerApp(APP_ID);
PayReq payReq = new PayReq();
payReq.appId = appId;
payReq.nonceStr = nonceStr;
payReq.partnerId = partnerId;
payReq.sign = paySign;
payReq.timeStamp = timeStamp;
payReq.prepayId = prepayId;
payReq.packageValue = packageValue;
mWeChatAPI.sendReq(payReq);
}
}).start();
如无意外,大家应该可以正确的召唤出微信支付的界面了。