前言
一直以為支付寶的文檔寫的已經(jīng)夠爛了庸疾,后來我才發(fā)現(xiàn)我太年輕了锦聊,那是因?yàn)槲疫€沒有遇到微信的文檔,簡直坑爹享甸。截碴。。<心中一萬只草泥馬...>
- 支付業(yè)務(wù)流程
商戶系統(tǒng)和微信支付系統(tǒng)主要交互說明:
步驟1:用戶在商戶APP中選擇商品枪萄,提交訂單隐岛,選擇微信支付。
步驟2:商戶后臺收到用戶支付單瓷翻,調(diào)用微信支付統(tǒng)一下單接口聚凹。參見【[統(tǒng)一下單API](https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_1)】。
步驟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ā)步驟說明](https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=8_5)】
步驟5:商戶后臺接收支付通知旗们。api參見【[支付結(jié)果通知API](https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_7)】
步驟6:商戶后臺查詢支付結(jié)果蚓哩。,api參見【[查詢訂單API](https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_2)】
注意
1.微信支付現(xiàn)在已經(jīng)很便捷了上渴,提供了
統(tǒng)一下單
接口岸梨,自己的后臺服務(wù)器調(diào)用該接口,獲取prepayId
2.最重要的一步稠氮,也是網(wǎng)上現(xiàn)在坑最多的一步曹阔,調(diào)用統(tǒng)一下單
接口后,微信返回格式如下隔披,而這么多數(shù)據(jù)中赃份,真正對我們有用的只有 預(yù)支付訂單號prepayId
,微信返回的sign
沒有任何用锹锰,我們得根據(jù)簽名規(guī)范重新生成簽名(關(guān)于這點(diǎn)芥炭,上面的流程交互中就有提到),然后將重新生成的簽名返回給APP端恃慧,用于APP端調(diào)用微信支付园蝠。(當(dāng)然重新生成簽名的步驟也可以放在APP端來做,不過為了安全考慮痢士,建議放在服務(wù)端處理彪薛,下面也會(huì)給出APP端簽名的代碼)
Tip
很多人都遇到這樣的問題,參數(shù)都處理好調(diào)用微信支付怠蹂,結(jié)果進(jìn)入微信界面后發(fā)現(xiàn)只有一個(gè)確定按鈕善延,返回后錯(cuò)誤碼為 -2,造成這個(gè)原因的就是因?yàn)閰?shù)不對城侧,而且大多是都是因?yàn)楹灻?sign 不對易遣,沒有進(jìn)行二次簽名,而直接拿微信返回的sign當(dāng)作參數(shù) 嫌佑, 所以調(diào)用微信支付接口時(shí)豆茫,一定要用 重新簽名的sign!N菀 ?辍!
- APP端調(diào)用支付時(shí)炮温,sign不要用調(diào)用統(tǒng)一下單接口返回的
sign
,而要自己重新生成火脉,生成規(guī)則見微信提供的簽名生成算法
Paste_Image.png
相關(guān)代碼如下:
- APP端打開微信微信支付代碼
#pragma mark - 微信支付
- (void)wechatPay:(WechatOrderModel *)model
{
//調(diào)起微信支付 model 為自己服務(wù)器返回的參數(shù)
PayReq *req = [[PayReq alloc] init];
req.partnerId = model.partnerid;
req.prepayId = model.prepayid;
req.nonceStr = model.noncestr;
req.timeStamp = model.timestamp.intValue;
req.package = model.package;
req.sign = model.sign;//sign 為自己服務(wù)器獲取到預(yù)支付訂單號prepayId后送浊,重新生成的簽名袄友,當(dāng)然本地也可以生成簽名漾唉,簽名代碼如下
[WXApi sendReq:req];
//日志輸出
NSLog(@"微信支付請求參數(shù) ===== appid=%@\npartid=%@\nprepayid=%@\nnoncestr=%@\ntimestamp=%ld\npackage=%@\nsign=%@",model.appid,req.partnerId,req.prepayId,req.nonceStr,(long)req.timeStamp,req.package,req.sign);
}
- APP端重新生成簽名(建議放在服務(wù)端處理)
#pragma mark - 微信支付本地簽名
//創(chuàng)建發(fā)起支付時(shí)的sign簽名
-(NSString *)createMD5SingForPayWithAppID:(NSString *)appid_key partnerid:(NSString *)partnerid_key prepayid:(NSString *)prepayid_key package:(NSString *)package_key noncestr:(NSString *)noncestr_key timestamp:(UInt32)timestamp_key{
NSMutableDictionary *signParams = [NSMutableDictionary dictionary];
[signParams setObject:appid_key forKey:@"appid"];//微信appid 例如wxfb132134e5342
[signParams setObject:noncestr_key forKey:@"noncestr"];//隨機(jī)字符串
[signParams setObject:package_key forKey:@"package"];//擴(kuò)展字段 參數(shù)為 Sign=WXPay
[signParams setObject:partnerid_key forKey:@"partnerid"];//商戶賬號
[signParams setObject:prepayid_key forKey:@"prepayid"];//此處為統(tǒng)一下單接口返回的預(yù)支付訂單號
[signParams setObject:[NSString stringWithFormat:@"%u",timestamp_key] forKey:@"timestamp"];//時(shí)間戳
NSMutableString *contentString =[NSMutableString string];
NSArray *keys = [signParams allKeys];
//按字母順序排序
NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2 options:NSNumericSearch];
}];
//拼接字符串
for (NSString *categoryId in sortedArray) {
if ( ![[signParams objectForKey:categoryId] isEqualToString:@""]
&& ![[signParams objectForKey:categoryId] isEqualToString:@"sign"]
&& ![[signParams objectForKey:categoryId] isEqualToString:@"key"]
)
{
[contentString appendFormat:@"%@=%@&", categoryId, [signParams objectForKey:categoryId]];
}
}
//添加商戶密鑰key字段 API 密鑰
[contentString appendFormat:@"key=%@", @"商戶密鑰"];
NSString *result = [contentString md5String];//md5加密
return result;
}
- MD5 加密方法
/**
* MD5 加密
*
* @return 加密后字符串
*/
- (NSString *)md5String
{
if(self == nil || [self length] == 0) return nil;
unsigned char digest[CC_MD5_DIGEST_LENGTH], i;
CC_MD5([self UTF8String], (int)[self lengthOfBytesUsingEncoding:NSUTF8StringEncoding], digest);
NSMutableString *ms = [NSMutableString string];
for(i=0;i<CC_MD5_DIGEST_LENGTH;i++)
{
[ms appendFormat: @"%02x", (int)(digest[i])];
}
return [ms copy];
}
至此微信集成結(jié)束故俐,坑的地方就是 app端調(diào)用微信支付時(shí)的簽名參數(shù)sign一定要重新生成单山,不要使用統(tǒng)一下單接口返回的sign
,切記?醚贰P咏凇0桥兵睛!
記錄點(diǎn)滴肯骇,與君共勉。