前言
之前做過(guò)一次微信支付的集成,但是沒(méi)有總結(jié)脐区。最近一個(gè)App又要集成微信支付愈诚,又要重新下載demo,重新看開(kāi)發(fā)文檔,重新寫(xiě)代碼炕柔。相信所有的程序員遇到這種事情都會(huì)抓狂酌泰。觀察了一下微信支付并不設(shè)計(jì)業(yè)務(wù)邏輯,完全可以封裝成一個(gè)工具匕累。
這里我們分三大步走:
一陵刹、導(dǎo)入微信SDK
二、寫(xiě)支付邏輯
三欢嘿、封裝
下面開(kāi)始詳解:
一衰琐、集成微信支付SDK
在集成第三方的時(shí)候,首先是要在自己的項(xiàng)目中集成對(duì)應(yīng)的SDK后才可以開(kāi)發(fā)的炼蹦。這個(gè)毋庸置疑羡宙。這里給出微信官方的集成文檔,讀者可自行查看掐隐,我在這里只對(duì)關(guān)鍵地方做出說(shuō)明狗热。
微信官方集成文檔:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=1417751808&token=6e7c5d2622dcc43878e06cd70caaa27a86d3d1d7&lang=zh_CN
1.導(dǎo)入sdk
如下圖,微信支付sdk已經(jīng)可以通過(guò)gradle來(lái)導(dǎo)入了虑省,所以建議還在堅(jiān)守eclipse的同學(xué)趕緊轉(zhuǎn)入Android studio匿刮。
2.大坑---接收微信的請(qǐng)求及返回值
先看官方文檔,仔細(xì)理解下圖被框住的文字慷妙。第一次做微信支付被這句話(huà)坑慘了僻焚,搞了兩天都TM找不到我到底錯(cuò)在哪里了,現(xiàn)在想起來(lái)就生氣膝擂。所以這句話(huà)的正確解讀是:在你的包名下一級(jí)目錄里面虑啤,新建一個(gè)文件夾名字為wxapi。而不是像下圖一樣有兩個(gè)并列的net.sourceforge.simcpux架馋。
當(dāng)時(shí)之所以被坑的慘狞山,也跟包結(jié)構(gòu)顯示樣式不同有關(guān)系。用Android Studio開(kāi)發(fā)時(shí)包結(jié)構(gòu)多半是這樣的:
對(duì)比以上兩張圖叉寂,相信聰明的你一點(diǎn)會(huì)發(fā)現(xiàn)問(wèn)題萍启。
二、微信支付開(kāi)發(fā)步驟
微信SDK集成之后屏鳍,準(zhǔn)備工作也就做好了勘纯,接下來(lái)就是要寫(xiě)代碼了,有木有一點(diǎn)小激動(dòng)呢钓瞭。官方文檔:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2
1.統(tǒng)一下單(服務(wù)端做)
為了更加安全驳遵,微信推薦統(tǒng)一下單是交給服務(wù)端人員來(lái)做的,當(dāng)然也有一下服務(wù)端開(kāi)發(fā)人員覺(jué)得麻煩山涡,會(huì)推到客戶(hù)端來(lái)做堤结,這個(gè)時(shí)候千萬(wàn)別慫唆迁,一定要跟他講。
2.請(qǐng)求我們自己的接口
在我們自己的APP中點(diǎn)擊微信支付按鈕后竞穷,我們首先要請(qǐng)求一個(gè)我們自己服務(wù)端的接口唐责,這時(shí)服務(wù)端需要走統(tǒng)一下單的邏輯,然后將一些參數(shù)返回給我們瘾带。這里需要注意鼠哥,嚴(yán)格來(lái)說(shuō)的話(huà),這個(gè)接口應(yīng)該返回如下所有參數(shù):
尤其是這個(gè)簽名的過(guò)程看政,微信官方強(qiáng)烈建議放在服務(wù)端來(lái)做肴盏。
而事實(shí)上,會(huì)有一些服務(wù)端開(kāi)發(fā)人員為了他們自己方便帽衙,返回過(guò)來(lái)的數(shù)據(jù)是這樣的:
如果這樣的話(huà),簽名過(guò)程就要放在客戶(hù)端來(lái)做嘍贞绵。
3.調(diào)起微信APP進(jìn)行支付
調(diào)起微信APP是需要請(qǐng)求參數(shù)的厉萝,也就是上一步中說(shuō)到的那些參數(shù),當(dāng)你把這些參數(shù)都湊夠了榨崩,那么這一步也就沒(méi)什么難度了谴垫,就是照著模板寫(xiě)了:
private IWXAPI iwxapi; //微信支付api
/**
*調(diào)起微信支付的方法
**/
private void toWXPay() {
iwxapi = WXAPIFactory.createWXAPI(this, null); //初始化微信api
iwxapi.registerApp(appid); //注冊(cè)appid appid可以在開(kāi)發(fā)平臺(tái)獲取
Runnable payRunnable = new Runnable() { //這里注意要放在子線(xiàn)程
@Override
public void run() {
PayReq request = new PayReq(); //調(diào)起微信APP的對(duì)象
//下面是設(shè)置必要的參數(shù),也就是前面說(shuō)的參數(shù),這幾個(gè)參數(shù)從何而來(lái)請(qǐng)看上面說(shuō)明
request.appId = appid;
request.partnerId = partnerId;
request.prepayId = prepayId;
request.packageValue = "Sign=WXPay";
request.nonceStr = nonceStr;
request.timeStamp = timeStamp;
request.sign = sign;
iwxapi.sendReq(request);//發(fā)送調(diào)起微信的請(qǐng)求
}
};
Thread payThread = new Thread(payRunnable);
payThread.start();
}
4.處理微信支付的回調(diào)
處理微信支付的回調(diào)就是在剛剛創(chuàng)建的WXPayEntryActivity中處理母蛛。需要實(shí)現(xiàn)IWXAPIEventHandler接口翩剪,這個(gè)接口會(huì)要求你實(shí)現(xiàn)onResp方法,我們就在這個(gè)方法中處理回調(diào)彩郊。
@Override
public void onResp(BaseResp resp) {
if(resp.getType()==ConstantsAPI.COMMAND_PAY_BY_WX){
if(resp.errCode==0){
Toast.makeText(this, "支付成功", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(this, "支付失敗", Toast.LENGTH_LONG).show();
}
finish();
}
}
到此微信支付也就完成了前弯,是不是很簡(jiǎn)單呀。
簽名問(wèn)題
前面提到秫逝,有時(shí)候簽名會(huì)讓客戶(hù)端來(lái)做恕出,那么我們就來(lái)看看簽名怎么來(lái)搞搞吧。
先看看官方的簽名規(guī)則:
仔細(xì)閱讀上面的簽名規(guī)則违帆,應(yīng)該不難理解浙巫。理解不了也沒(méi)關(guān)系,下面就是我寫(xiě)好的代碼:
/**
* 調(diào)起微信APP支付刷后,簽名
*/
public static String genPackageSign2(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.size(); i++) { //將參數(shù)拼接成鍵值對(duì)樣式的字符串
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
}
sb.append("key=");
sb.append(Constants.API_KEY); //拼接key
//進(jìn)行MD5加密的畴,并轉(zhuǎn)為大寫(xiě)
String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
return packageSign; //返回簽名
}
/**
* MD5加密算法
*/
public final 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 (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
三、微信支付的封裝
由于微信支付不涉及很多業(yè)務(wù)邏輯尝胆,因此完全可以封裝成工具類(lèi)丧裁。這里對(duì)微信支付做了封裝,并且用了Builder設(shè)計(jì)模塊(類(lèi)似Dialog的使用)班巩。
封裝后的使用案例:
//在服務(wù)端簽名
findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//假裝請(qǐng)求了服務(wù)器 獲取到了所有的數(shù)據(jù)
WXPayUtils.WXPayBuilder builder = new WXPayUtils.WXPayBuilder();
builder.setAppId("123")
.setPartnerId("56465")
.setPrepayId("41515")
.setPackageValue("5153")
.setNonceStr("5645")
.setTimeStamp("56512")
.setSign("54615")
.build().toWXPayNotSign(MainActivity.this,"123");
}
});
//在客戶(hù)端簽名
findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//假裝請(qǐng)求了服務(wù)端信息渣慕,并獲取了appid嘶炭、partnerId、prepayId
WXPayUtils.WXPayBuilder builder = new WXPayUtils.WXPayBuilder();
builder.setAppId("123")
.setPartnerId("213")
.setPrepayId("3213")
.setPackageValue("Sign=WXPay")
.build()
.toWXPayAndSign(MainActivity.this,"123","key");
}
});
經(jīng)過(guò)這樣封裝后逊桦,下次再接入微信支付就簡(jiǎn)單多了眨猎。會(huì)少走很多彎路。
微信支付到此也就總結(jié)完了强经,是不是感覺(jué)很簡(jiǎn)單呢睡陪,不過(guò)一定要注意別掉坑里。
詳細(xì)代碼請(qǐng)參考github:https://github.com/chaohengxing/WXPayUtils.git
另外在開(kāi)發(fā)中遇到問(wèn)題可以直接私信我匿情,希望可以幫助到大家
分享一個(gè)在線(xiàn)測(cè)試接口兰迫,可能大家用得到
https://wxpay.wxutil.com/pub_v2/app/app_pay.php
以前不知道這個(gè),感謝下面這位兄弟