今日推薦
經(jīng)常閱讀博客是個好習(xí)慣
推薦鴻洋CSDN的博客
微信支付相關(guān)文章
詳細(xì)介紹Android開發(fā)集成微信支付(一) --- 僅客戶端版
詳細(xì)介紹Android開發(fā)集成微信支付(二) --- 完整版本
引言
本篇文章目的在于縮短集成微信支付的時間,讓您更快的接入微信支付,躲坑
我的CSDN博客地址 (由于csdn的圖片經(jīng)常出現(xiàn)不顯示問題,以后就在簡書寫博客了)
GitHub由于近期較忙,正加急整理中,敬請期待...
常用鏈接
微信開放平臺 -- 注冊并創(chuàng)建應(yīng)用
微信支付SDK下載集成 -- 如何集成sdk
微信開放平臺資源中心 -- 所有的資源
微信支付App開發(fā)文檔 -- 微信支付的開發(fā)文檔
微信支付業(yè)務(wù)流程 -- 里面有完成的支付流程
微信支付官方實例sample -- 下載官方示例
簽名驗證 -- 用于驗證一下你代碼生成的簽名是否正確
這里有一個獲取app簽名工具的鏈接(簽名工具下載地址) -- 用于獲取打包后App的應(yīng)用簽名填寫到開放平臺上
目錄
開始前準(zhǔn)備
1.1 注冊微信開放平臺理清業(yè)務(wù)流程
開始集成
3.1 下載SDK和官方實例
3.2 開始集成
開啟微信支付
這篇文章是一步一步的詳細(xì)介紹了如何集成微信支付(包括完整的客戶端和服務(wù)端該做的事情)如果你只是完成客戶端開發(fā),請看詳細(xì)介紹Android開發(fā)集成微信支付(一) --- 僅客戶端版
ok ,Let's go!(這篇文章不只是代碼放在這,因為微信支付一直在改動,所以具體的每一步思路都在這,如果變動根據(jù)每一步去微信用最新的方式替換即可)
一: 開發(fā)前準(zhǔn)備
1.1 注冊微信開放平臺
這一步的目的是在微信開放平臺注冊并創(chuàng)建應(yīng)用,然后獲取微信支付需要用到的 APP_ID , Mch_Id(商戶號) , Mch_Key(商戶key,簽名的時候用)
首先我們點擊上面的常用鏈接中的微信開放平臺進(jìn)入微信開放平臺的官網(wǎng),也可以百度搜索微信開放平臺
接著點擊移動應(yīng)用開發(fā)
然后按照上圖的流程一步一步的創(chuàng)建好應(yīng)用然后通過審核,然后獲取我們需要的各種ID
二:理清業(yè)務(wù)流程
首先微信開發(fā)文檔已經(jīng)有了簡單的步驟介紹點擊查看
點擊常用鏈接的微信開放平臺資源中心,如下圖 包含了我們所有需要的東西
首先按照邏輯,我們應(yīng)該先搞清楚微信支付的總體流程然后根據(jù)自己APP的業(yè)務(wù)需求制定適合自己的業(yè)務(wù)流程,然后才是下載SDK和集成代碼
首先我們 點擊進(jìn)入開發(fā)文檔 查看業(yè)務(wù)流程 如下圖:
商戶系統(tǒng)和微信支付系統(tǒng)主要交互說明:
步驟1:用戶在商戶APP中選擇商品,提交訂單八秃,選擇微信支付痘括。
步驟2:商戶后臺收到用戶支付單爱咬,調(diào)用微信支付統(tǒng)一下單接口烛愧。參見【統(tǒng)一下單API】兄世。
步驟3:統(tǒng)一下單接口返回正常的prepay_id伤哺,再按簽名規(guī)范重新生成簽名后纸巷,將數(shù)據(jù)傳輸給APP贞绵。參與簽名的字段名為appId厉萝,partnerId,prepayId,nonceStr谴垫,timeStamp章母,package。注意:package的值格式為Sign=WXPay
步驟4:商戶APP調(diào)起微信支付翩剪。api參見本章節(jié)【app端開發(fā)步驟說明】
步驟5:商戶后臺接收支付通知胳施。api參見【支付結(jié)果通知API】
步驟6:商戶后臺查詢支付結(jié)果。肢专,api參見【查詢訂單API】
總結(jié)一下就是:(商品類購買):
第一步:用戶在APP中選擇相應(yīng)的商品和數(shù)量,提交給自己的后臺,然后后臺根據(jù)選擇的商品調(diào)用微信的統(tǒng)一下單API(這里需要第一次生成簽名),獲取prepay_id
第二步:后臺獲取到prepay_id之后需要再次生成一次簽名,(上面有詳細(xì)的簽名需要的字段)
第三步:后臺將簽名好的字段和客戶端需要調(diào)起微信需要的字段傳給客戶端
第四步:客戶端調(diào)起微信支付,并接收支付結(jié)果(本地回調(diào),不可信),然后去后臺查詢支付結(jié)果,拿到微信支付的真實結(jié)果(后臺會收到微信的支付結(jié)果通知,也可以去調(diào)用微信的支付結(jié)果)
三:開始集成
具體的流程搞清楚了,現(xiàn)在我們開始一步一步來集成微信支付
3.1 下載微信支付SDK和官方實例代碼
首先我們先去下載SDK和官方實例 (記得之前微信的sdk還是要打包下載的,現(xiàn)在微信支付改版成為了托管到了JCenter上了,直接可以在gradle中添加依賴就可以了)
在build.gradle文件中舞肆,添加如下依賴即可:
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
}
或
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
}
(其中,前者包含統(tǒng)計功能)
添加好依賴,就ok了
接著我們?nèi)ハ螺d官方實例代碼,1.是可以看里面的具體流程2.是可以直接拷貝里面的工具類和代碼
下載好之后解壓,并在AndroidStudio中open,打開之后發(fā)現(xiàn)只包含微信分享和一些其他的例子,并不包含微信支付(最新版的已經(jīng)將微信支付的實例代碼去除,需要到微信APP支付Android開發(fā)文檔 里面下載)
打開之后可能會有報錯,我們不用管,因為我們不用運行,只是看一下里面有用的代碼,最新版微信的實例代碼已經(jīng)將微信支付的實例去除,需要下載的話需要到微信APP支付Android開發(fā)文檔 -- SDK下載里面去Download
下載完成 打開是這樣的:
這里 wxapi/WXPayEntryActivity 是微信支付的回調(diào)頁面 ,這個頁面必須在 包名/wxapi 之下 所以直接把這個文件復(fù)制到我們工程中
MD5是一個工具類也復(fù)制到自己的項目中,需要用
public class MD5 {
private 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;
}
}
}
PayActivity中有調(diào)起微信支付的代碼可以參考
3.2 開始集成(寫代碼)
改集成也集成好了,流程也弄清楚了,實例代碼也復(fù)制好了,這樣就可以按照微信支付Android開發(fā)文檔一步一步的開始寫代碼就ok了
微信支付開發(fā)文檔
按照這個流程(因為這篇文章是所有的流程,所以全部都寫一遍):
商戶系統(tǒng)和微信支付系統(tǒng)主要交互說明:
步驟1:用戶在商戶APP中選擇商品博杖,提交訂單椿胯,選擇微信支付。
步驟2:商戶后臺收到用戶支付單剃根,調(diào)用微信支付統(tǒng)一下單接口哩盲。參見【統(tǒng)一下單API】。
步驟3:統(tǒng)一下單接口返回正常的prepay_id狈醉,再按簽名規(guī)范重新生成簽名后廉油,將數(shù)據(jù)傳輸給APP。參與簽名的字段名為appId苗傅,partnerId抒线,prepayId,nonceStr渣慕,timeStamp嘶炭,package。注意:package的值格式為Sign=WXPay
步驟4:商戶APP調(diào)起微信支付逊桦。api參見本章節(jié)【app端開發(fā)步驟說明】
步驟5:商戶后臺接收支付通知眨猎。api參見【支付結(jié)果通知API】
步驟6:商戶后臺查詢支付結(jié)果。强经,api參見【查詢訂單API】
3.2.1 統(tǒng)一下單
首先初始化微信
/**
* 初始化微信支付
*/
private void initWX() {
if (wxApi == null) {
wxApi = WXAPIFactory.createWXAPI(this, "你的微信APP_ID");
wxApi.registerApp("你的微信APP_ID");
}
}
查看統(tǒng)一下單API的文檔,查看具體的統(tǒng)一下單的鏈接地址,需要的參數(shù)
統(tǒng)一下單的鏈接地址:URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
post請求
參數(shù)是文檔里需要的,請求參數(shù)需要轉(zhuǎn)換為xml
舉例如下:
<xml>
<appid>wx2421b1c4370ec43b</appid>
<attach>支付測試</attach>
<body>APP支付測試</body>
<mch_id>10000100</mch_id>
<nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
<notify_url>http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url>
<out_trade_no>1415659990</out_trade_no>
<spbill_create_ip>14.23.150.211</spbill_create_ip>
<total_fee>1</total_fee>
<trade_type>APP</trade_type>
<sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>
定義一個統(tǒng)一下單JavaBean
public class WXPrePost {
//必須帶的參數(shù)
public String appid;//微信開放平臺審核通過的應(yīng)用APPID
public String mch_id;//微信支付分配的商戶號
public String nonce_str;//隨機(jī)字符串睡陪,不長于32位。推薦隨機(jī)數(shù)生成算法
public String sign;//簽名匿情,詳見簽名生成算法
public String body;//商品描述交易字段格式根據(jù)不同的應(yīng)用場景按照以下格式:APP——需傳入應(yīng)用市場上的APP名字-實際商品名稱兰迫,天天愛消除-游戲充值。
public String out_trade_no;//商戶系統(tǒng)內(nèi)部的訂單號,32個字符內(nèi)码秉、可包含字母, 其他說明見商戶訂單號
public int total_fee;//訂單總金額逮矛,單位為分,詳見支付金額
public String spbill_create_ip;//用戶端實際ip
public String notify_url;//接收微信支付異步通知回調(diào)地址转砖,通知url必須為直接可訪問的url须鼎,不能攜帶參數(shù)鲸伴。
public String trade_type;//支付類型
//非必須攜帶的參數(shù)
public String device_info;//終端設(shè)備號(門店號或收銀設(shè)備ID),默認(rèn)請傳"WEB"
public String detail;//商品名稱明細(xì)列表
public String attach;//附加數(shù)據(jù)晋控,在查詢API和支付通知中原樣返回汞窗,該字段主要用于商戶攜帶訂單的自定義數(shù)據(jù)
public String fee_type;//符合ISO 4217標(biāo)準(zhǔn)的三位字母代碼,默認(rèn)人民幣:CNY赡译,其他值列表詳見貨幣類型
public String time_start;//訂單生成時間仲吏,格式為yyyyMMddHHmmss,如2009年12月25日9點10分10秒表示為20091225091010蝌焚。其他詳見時間規(guī)則
public String time_expire;//訂單失效時間裹唆,格式為yyyyMMddHHmmss,如2009年12月27日9點10分10秒表示為20091227091010只洒。其他詳見時間規(guī)則 注意:最短失效時間間隔必須大于5分鐘
public String goods_tag;//商品標(biāo)記许帐,代金券或立減優(yōu)惠功能的參數(shù),說明詳見代金券或立減優(yōu)惠
public String limit_pay;//no_credit--指定不能使用信用卡支付
}
初始化統(tǒng)一下單的參數(shù)
// 統(tǒng)一下單
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
WXPrePost post = new WXPrePost();
post.appid = "你的APP_ID";
post.mch_id = "你的商戶號";
post.nonce_str = genNonceStr();//隨機(jī)字符串 **1
post.body = "介紹";
post.detail = "打賞";
post.out_trade_no = getTradeNo(); //商戶訂單號 **2
post.total_fee = 1;//單位是分
post.spbill_create_ip = getLocalIpAddress();//ip地址 **3
post.notify_url = "http://www.weixin.qq.com/wxpay/pay.php";//這里是后臺接受支付結(jié)果通知的url地址
post.trade_type = "APP";
post.sign = genPackageSign(post);//簽名 **4
**1 : 隨機(jī)字符串毕谴,不長于32位成畦。推薦隨機(jī)數(shù)生成算法
微信支付API接口協(xié)議中包含字段nonce_str,主要保證簽名不可預(yù)測涝开。我們推薦生成隨機(jī)數(shù)算法如下:調(diào)用隨機(jī)數(shù)函數(shù)生成循帐,將得到的值轉(zhuǎn)換為字符串。
private String genNonceStr() {
Random random = new Random();
//這里就用到了微信實例代碼中的MD5那個類
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
*2 商戶訂單號
商戶系統(tǒng)內(nèi)部訂單號舀武,要求32個字符內(nèi)拄养,只能是數(shù)字、大小寫字母_-|@ 奕剃,且在同一個商戶號下唯一衷旅。詳見商戶訂單號
商戶支付的訂單號由商戶自定義生成,微信支付要求商戶訂單號保持唯一性(建議根據(jù)當(dāng)前系統(tǒng)時間加隨機(jī)序列來生成訂單號)纵朋。重新發(fā)起一筆支付要使用原訂單號,避免重復(fù)支付茄袖;已支付過或已調(diào)用關(guān)單操软、撤銷(請見后文的API列表)的訂單號不能重新發(fā)起支付。
public String getTradeNo() {
return "這里可以是app名字" + genTimeStamp();
}
private long genTimeStamp() {
return System.currentTimeMillis() / 1000;
}
**3 ip地址 (可以不獲取,直接給個默認(rèn),如果項目不要求的話)
public String getLocalIpAddress() {
StringBuilder IFCONFIG = new StringBuilder();
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress() && inetAddress.isSiteLocalAddress()) {
IFCONFIG.append(inetAddress.getHostAddress().toString() + ",");
break;
}
}
}
String[] split = IFCONFIG.toString().split(",");
if (split != null && split.length > 0) {
String ip = split[0];
if (ip != null && ip.length() > 0) {
return ip;
} else {
return "127.0.0.1";
}
} else {
return "127.0.0.1";
}
} catch (SocketException ex) {
return "127.0.0.1";
}
}
**4 獲取簽名宪祥,詳見簽名生成算法 生成完之后 點擊這里驗證簽名 生成的簽名是否正確
簽名生成的通用步驟如下:
第一步聂薪,設(shè)所有發(fā)送或者接收到的數(shù)據(jù)為集合M,將集合M內(nèi)非空參數(shù)值的參數(shù)按照參數(shù)名ASCII碼從小到大排序(字典序)蝗羊,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串stringA藏澳。
特別注意以下重要規(guī)則:
◆ 參數(shù)名ASCII碼從小到大排序(字典序);
◆ 如果參數(shù)的值為空不參與簽名耀找;
◆ 參數(shù)名區(qū)分大小寫翔悠;
◆ 驗證調(diào)用返回或微信主動通知簽名時业崖,傳送的sign參數(shù)不參與簽名,將生成的簽名與該sign值作校驗蓄愁。
◆ 微信接口可能增加字段双炕,驗證簽名時必須支持增加的擴(kuò)展字段
第二步,在stringA最后拼接上key得到stringSignTemp字符串撮抓,并對stringSignTemp進(jìn)行MD5運算妇斤,再將得到的字符串所有字符轉(zhuǎn)換為大寫,得到sign值signValue丹拯。
key設(shè)置路徑:微信商戶平臺(pay.weixin.qq.com)-->賬戶設(shè)置-->API安全-->密鑰設(shè)置
/**
* 生成簽名
*
* @param params
*/
private String genPackageSign(WXPrePost params) {
//拼接排序list
List<NameValuePair> packageParams = new LinkedList<>();
packageParams.add(new BasicNameValuePair("appid", "你的APP_ID"));
packageParams.add(new BasicNameValuePair("body", params.body));
packageParams.add(new BasicNameValuePair("detail", params.detail));
packageParams.add(new BasicNameValuePair("mch_id", "你的商戶號"));
packageParams.add(new BasicNameValuePair("nonce_str", params.nonce_str));
packageParams.add(new BasicNameValuePair("notify_url", params.notify_url));
packageParams.add(new BasicNameValuePair("out_trade_no", params.out_trade_no));
packageParams.add(new BasicNameValuePair("spbill_create_ip", params.spbill_create_ip));
packageParams.add(new BasicNameValuePair("total_fee", params.total_fee + ""));
packageParams.add(new BasicNameValuePair("trade_type", params.trade_type));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < packageParams.size(); i++) {
sb.append(packageParams.get(i).getName());
sb.append('=');
sb.append(packageParams.get(i).getValue());
sb.append('&');
}
sb.append("key=");
sb.append("商戶key");//key設(shè)置路徑:微信商戶平臺(pay.weixin.qq.com)-->賬戶設(shè)置-->API安全-->密鑰設(shè)置
//這里又用到了從實例代碼復(fù)制的MD5 可以去上面copy
String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
return packageSign;
}
ps:
**如上已經(jīng)生成了統(tǒng)一下單需要的簽名,生成完成之后可以去點擊這里驗證簽名 生成的簽名是否正確
**
上面可能會遇到問題:由于代碼寫完的時候是支持NameValuePair,前幾天升級之后,發(fā)現(xiàn)Android已經(jīng)去掉了Apache的相關(guān)類,其中就有NameValuePair,這里解決方式有兩種:
一是 : 在Gradle中添加這兩個就可以接著使用NameValuePair
compile 'org.apache.httpcomponents:httpcore:4.4.1'
compile 'org.apache.httpcomponents:httpclient:4.5'
二是: 可以通過ContentValues 簡單實現(xiàn)一個類似的類,然后提供一個查詢的方法可以看這里
上面列表中參數(shù)的名稱像appid,body,mch_id一定要按照上面寫,大小寫也需要一樣,和官方文檔中一致才可以
將參數(shù)轉(zhuǎn)換為xml 并post請求統(tǒng)一下單
這里給一個將參數(shù)轉(zhuǎn)換為xml的方法,內(nèi)部的參數(shù)用List<NameValuePair>封裝
private String toXml(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
sb.append("<xml>");
for (int i = 0; i < params.size(); i++) {
sb.append("<" + params.get(i).getName() + ">");
sb.append(params.get(i).getValue());
sb.append("</" + params.get(i).getName() + ">");
}
sb.append("</xml>");
return sb.toString();
}
參數(shù)列表在這里獲取
@NonNull
private List<NameValuePair> getFirstSignParams(WXPrePost params) {
List<NameValuePair> packageParams = new LinkedList<>();
packageParams.add(new BasicNameValuePair("appid", "你的APP_ID"));
packageParams.add(new BasicNameValuePair("body", params.body));
packageParams.add(new BasicNameValuePair("detail", params.detail));
packageParams.add(new BasicNameValuePair("mch_id", "你的商戶號"));
packageParams.add(new BasicNameValuePair("nonce_str", params.nonce_str));
packageParams.add(new BasicNameValuePair("notify_url", params.notify_url));
packageParams.add(new BasicNameValuePair("out_trade_no", params.out_trade_no));
packageParams.add(new BasicNameValuePair("spbill_create_ip", params.spbill_create_ip));
packageParams.add(new BasicNameValuePair("total_fee", params.total_fee + ""));
packageParams.add(new BasicNameValuePair("trade_type", params.trade_type));
packageParams.add(new BasicNameValuePair("sign", params.sign));
return packageParams;
}
然后我們將上面初始化完成的WxPrePost 傳給這個方法然后調(diào)用toXml就可以獲取到統(tǒng)一下單的xml參數(shù)了
Next:有了統(tǒng)一下單的xml參數(shù),我們就可以直接post請求url 將xml參數(shù)傳過去,返回一個String類型的字符串也是xml,解析即可獲取prepay_id,返回結(jié)果如下:
只有return_code和result_code都為SUCCESS的時候才會有prepay_id,簡單的判斷一下然后解析xml
獲取我們需要的參數(shù)
public Map<String, String> decodeXml(String content) {
try {
Map<String, String> xml = new HashMap<>();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new StringReader(content));
int event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
String nodeName = parser.getName();
switch (event) {
case XmlPullParser.START_DOCUMENT:
break;
case XmlPullParser.START_TAG:
if (!"xml".equals(nodeName)) {
xml.put(nodeName, parser.nextText());
}
break;
case XmlPullParser.END_TAG:
break;
}
event = parser.next();
}
return xml;
} catch (Exception e) {
}
return null;
}
我們將解析出來的xml放入map中,然后遍歷一下獲取我們再次簽名需要的prepay_id , nonce_str , appid
//判斷是否成功
//...
//再次簽名(參與簽名的字段有 :Appid partnerId prepayId nonceStr TimeStamp package)
String appId = "";
String prepayId = "";
String nonceStr = "";
for (Map.Entry<String, String> entry : stringMap.entrySet()) {
if ("appid".equals(entry.getKey())) {
appId = entry.getValue();
} else if ("prepay_id".equals(entry.getKey())) {
prepayId = entry.getValue();
} else if ("nonce_str".equals(entry.getKey())) {
nonceStr = entry.getValue();
}
}
//有可能會有解析失敗的情況 ,需要判斷
//...
到這里統(tǒng)一下單就結(jié)束了,接下來就是再次簽名獲取調(diào)起微信支付的參數(shù)
3.2.2 第二次簽名
上一步已經(jīng)獲取到了再次簽名的參數(shù),接下來再次簽名,按照相同的簽名規(guī)則
參與簽名的字段名為appId站超,partnerId,prepayId乖酬,nonceStr顷编,timeStamp,package剑刑。注意:package的值格式為Sign=WXPay
看一下上面的參數(shù)appId partnerId(商戶號),prepayId,nonceStr ,package 都已經(jīng)有了 就差一個時間戳timeStamp
String TimeStamp = String.valueOf(genTimeStamp());
private long genTimeStamp() {
return System.currentTimeMillis() / 1000;
}
獲取到所有參數(shù)之后,接著封裝到列表之后,進(jìn)行第二次簽名
//獲取參數(shù)列表
private List<NameValuePair> getSecondSignParams(String appId, String prepayId, String nonceStr, String timeStamp) {
//appId媳纬,partnerId,prepayId施掏,nonceStr钮惠,timeStamp,package
List<NameValuePair> packageParams = new LinkedList<>();
packageParams.add(new BasicNameValuePair("appid", appId));
packageParams.add(new BasicNameValuePair("noncestr", nonceStr));
packageParams.add(new BasicNameValuePair("package", "Sign=WXPay"));
packageParams.add(new BasicNameValuePair("partnerid", "你的商戶號"));
packageParams.add(new BasicNameValuePair("prepayid", prepayId));
packageParams.add(new BasicNameValuePair("timestamp", timeStamp));
return packageParams;
}
//第二次簽名
private String genSecondPackageSign(List<NameValuePair> params) {
//拼接排序list
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.size(); i++) {
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
}
sb.append("key=");
sb.append("商戶密鑰");//上面已經(jīng)獲取
String packageSign = getMessageDigest(sb.toString().getBytes()).toUpperCase();
return packageSign;
}
//ok 獲取簽名
String secondPackageSign = genSecondPackageSign(getSecondSignParams(appId, prepayId, nonceStr, TimeStamp));
別忘了獲取簽名之后去驗證一下(驗證鏈接在上面),到這里調(diào)起微信需要的所有參數(shù)都已經(jīng)獲取到了
3.2.3 調(diào)起微信 *
已經(jīng)最后一步了,我們馬上就可以去驗證是不是能夠成功的調(diào)起微信并接收到微信支付的本地回調(diào)
調(diào)起微信支付,需要在開放平臺設(shè)置包名和簽名(這也是微信支付最大的一個坑,大部分人調(diào)不起微信基本都是這里的問題)
首先先看官方文檔 的詳細(xì)步驟
這里有一個獲取簽名工具的鏈接(簽名工具下載地址 安裝到手機(jī)上獲取自己app的簽名(打包之后安裝到手機(jī)上)
這里只能是你在開放平臺上填的簽名的app才可以調(diào)起微信,比如我打包之后用上面的簽名工具獲取app的簽名填入開放平臺,所以想要測試微信支付需要打包安裝到手機(jī)上才可以調(diào)起微信,如果發(fā)現(xiàn)沒有調(diào)起微信就這樣操作,雖然麻煩點,但是可以解決
//調(diào)起支付
try {
//一下所有的參數(shù)上面均獲取到了
PayReq req = new PayReq();
req.appId = "你的APP_ID";
req.partnerId = "你的商戶號";
req.prepayId = "你的prepayId";
req.nonceStr = "你的nonceStr";
req.timeStamp = "你的TimeStamp";
req.packageValue = "Sign=WXPay";
req.sign = "你的簽名";
req.extData = "app data"; // optional
// 在支付之前七芭,如果應(yīng)用沒有注冊到微信素挽,應(yīng)該先調(diào)用IWXMsg.registerApp將應(yīng)用注冊到微信
wxApi.sendReq(req);
} catch (Exception e) {
Log.e("PAY_GET", "異常:" + e.getMessage());
}
到這里正常情況下肯定可以調(diào)起微信支付 ,如果出現(xiàn)了問題 1.簽名問題(去上面驗證下自己的簽名) 2.應(yīng)用簽名問題請參考(3.2.3 調(diào)起微信 也就是上面)
3.3.4 接受微信支付的回調(diào)
到這一步說明你的微信已經(jīng)成功調(diào)起,這里接受微信支付的回調(diào)
我們需要在應(yīng)用的包名下建立wxapi的包名然后將實例中的WXPayEntryActivity.java復(fù)制過來
記住一定是項目的包名下建立wxapi包然后復(fù)制過來
然后再AndroidManifest中添加
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"/>
在WXPayEntryActivity中就可以接受回調(diào)了
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//這里可以不給布局,也可以給個透明或者loading框 根據(jù)項目的需求
setContentView(R.layout.act_pay);
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);
}
以上兩個微信已經(jīng)寫好,接下來是微信回調(diào)的方法
@Override
public void onResp(BaseResp resp) {
Log.d(TAG, "onPayFinish, errCode = " + resp.errCode);
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
//根據(jù)下面的errCode表中 switch一下即可
//如果是0的話,就是成功,然后這里去服務(wù)器查詢具體的支付結(jié)果,注意服務(wù)器查詢的支付結(jié)果才是可靠地支付結(jié)果
}
}
支付回調(diào)可能遇到的問題:
1.如果項目中存在兩種即以上的支付(比如:商城購買 和 普通的打賞支付 或者其他),兩種支付完成后都會回調(diào)onResp但是之后的邏輯不一樣,所以我們需要手動的區(qū)分兩種支付(比如在支付前可以存一個變量標(biāo)識)
2.支付成功回調(diào)之后,也就是errCode = 0 的時候,我們需要去服務(wù)器查詢結(jié)果,一般會需要給他們訂單號去查詢,但是微信回調(diào)之后不會給你訂單號,所以也需要你去本地存一下(或者其他更好的方式)
到這里微信支付就集成完了,當(dāng)然代碼很粗糙可以在具體的細(xì)節(jié)細(xì)化,當(dāng)然有其他更好的方式也可以提意見優(yōu)化
希望這篇文章可以幫助到需要的人,如果還有其他問題或者補(bǔ)充可以聯(lián)系我~~~