最近項目要求添加一個微信支付的功能,要求是不需要服務端的配合,獨立在客戶端完成。
開始看官方demo的時候發現客戶端只有短短的幾行代碼便成功了,更關鍵的是文檔中那些參數都解釋的含含糊糊。結果花了我好幾天的時間才最終弄好。現在細數其辛酸歷程。
//調起微信支付
PayReq* req = [[[PayReq alloc] init]autorelease];
req.partnerId = [dict objectForKey:@"partnerid"];
req.prepayId = [dict objectForKey:@"prepayid"];
req.nonceStr = [dict objectForKey:@"noncestr"];
req.timeStamp = stamp.intValue;
req.package = [dict objectForKey:@"package"];
req.sign = [dict objectForKey:@"sign"];
[WXApi sendReq:req];
這就官方文檔中最核心的調出支付的代碼,我們所需要做的一切都是獲取這六個參數。
首先來一個個的解釋這些參數
partnerId :這個就是在你申請通過微信商戶資料后發到你郵件的中的一個商戶號
prepayid : 這個是需要向微信服務器提交申請后返回的一個支付交易會話ID,詳細的下面會提到。
nonceStr : 這個是你自己生成的一個隨機數。
timeStamp : 這個是你生成的一個時間戳。10位!!!不是13位的那個!
package : 這個目前是一個定死的值 Sign=WXPay。
sign : 這個是自己根據參數生成的一個簽名!最坑的就是它了!
現在來一個的說如何得到這些參數值
1、prepayid
這個一般來說是在服務端申請好的,客戶端直接獲取就行。但是萬惡的公司居然要求在客戶端弄。
先看官方文檔:https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_1
乍一看無非是向微信的一個接口提交數據,然后就會返回了。
但是這茫茫多的參數中其實隱藏著無數的細節,稍有不慎就返回一個大大失敗,然后你就愁的一頭包了。
這些參數里面有一個是需要生成一個簽名,這個簽名也是有官方文檔專門介紹的:https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=4_3
這個文檔中有舉一個例子,大概就是說把一些參數按照ASCII的順序先進行排序然后再拼接上一個key(這個key是你在申請成功商戶資料后按照郵件中提示進行設置的,32位)。拼接好后進行MD5轉碼。看起來很輕松明了吧,但是這里面最大的一個坑就是他這個舉例了!這個例子中只有寥寥幾個參數,如果你就按照他這個也只是用這幾個參數生成簽名,那就怎么也獲取不到這個prepayid了!實際上,這個簽名里面所包含的參數是需要包含你所要提交獲取prepayid的所有參數的!
也就是前面給的官方文檔中所有表示必須要的參數,當然除了你現在要生成的這個sign。
順便提一句,這里的提交數據是以XML的形式,解析數據也是XML的格式。
這樣就可以順利的獲得prepayid了。
2、nonceStr
這個很簡單
NSString * nonce_str = [self md5:[NSString stringWithFormat:@"%d", arc4random() % 10000]];
nonce_str = [nonce_str uppercaseString];
- (NSString *) md5: (NSString *) inPutText
{
const char *cStr = [inPutText UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(cStr, strlen(cStr), result);
return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
] lowercaseString];
}
其實就是一個隨機數,怎么生成隨你。有個不得不提的地方,這里的noncestr就是你在第一次生成簽名時的那個隨機數,不用再次生成了!
3、timeStamp
NSString * timeString = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
這個地方需要提示一下
@property (nonatomic, assign) UInt32 timeStamp;
他的類型是這個樣的,而你生成的是一個字符串類型的,最后提交的時候需要進行轉化的!
4、sign
這里的簽名不同于你第一次申請prepayid的簽名,這里的生成簽名的參數是appid,prepayid,partnerid,timestamp,noncestr,package,這幾個排序后再拼接key,最后生成一個sign。
這樣一看,其實還是很簡答的嘛!果然還是我太蠢了.......好了,如果還是不行,請再看一遍,仔細的看一遍。實在不行,請聯系我!