公司要求項(xiàng)目添加上微信支付和支付寶支付在這里我將自己的心得以及自己總結(jié)的步驟總結(jié)在這里,希望讓讀者少一點(diǎn)入坑涝焙。卑笨,那么我們現(xiàn)在從最難的骨頭啃起來,一步步教大家完成微信支付仑撞,關(guān)于申請(qǐng)微信支付的東西我就不再這里累贅赤兴,很多帖子都有(其實(shí)是因?yàn)楣具@部分我沒有參與,嘿嘿)隧哮。開始我們的微信支付的旅行吧桶良。
前提條件,讓你的 APP有支付的本領(lǐng) 沮翔,申請(qǐng)到微信支付相關(guān)以后陨帆,下面這些東西對(duì)我們很重要。
前提條件:
//APPID 一般以wx開頭
static NSString *const ZQAppID = @"APPID";
//appsecret
static NSString *const ZQAppSecret = @"appsecret";
//商戶號(hào)采蚀,填寫商戶對(duì)應(yīng)參數(shù)
static NSString *const ZQMchID = @"商戶號(hào)";
//商戶API密鑰疲牵,填寫相應(yīng)參數(shù)
static NSString *const ZQPartnerID = @"商戶API密鑰";
// 預(yù)支付請(qǐng)求路徑固定可以不改變
static NSString *const ZQPrePayURL = @"https://api.mch.weixin.qq.com/pay/unifiedorder";
// // 支付回調(diào)頁面(異步) (https://api.mch.weixin.qq.com/pay/unifiedorder)(異步處理支付調(diào)用返回?cái)?shù)據(jù))
static NSString *const ZQPayNotifyURL = @"支付回調(diào)頁面";
注意
微信支付的單位為分!2妗瑰步!整數(shù)類型才可以(int)
流程簡(jiǎn)述
支付要保證安全性,就要使用加密璧眠。微信當(dāng)然也是這樣,微信為了防止中間有人加入竊取信息或者改變價(jià)格读虏。有自己的加密方式——生成預(yù)支付Id责静,我們通過封裝數(shù)據(jù)形成XML格式(中間加密)以字符串類型傳給微信,獲取預(yù)支付Id盖桥。緊接著灾螃,獲取以后通過預(yù)支付等信息再次加密。APP將參數(shù)傳給微信揩徊,付款成功腰鬼!回調(diào)信息說明支付情況嵌赠。(關(guān)于加密具體怎么實(shí)現(xiàn)我會(huì)在下面詳細(xì)說明)。
步驟以及代碼
接下來說說主要的步驟吧(比比叨這么久終于說正事了熄赡,請(qǐng)不要打我么么噠~)
1.在做微信支付以前導(dǎo)入
libc++.tbd
libsqlite3.0.tbd
libz.tbd
SystemConfiguration.framework
CoreTelephony.framework
Security.framework
2.在AppDelegate 的導(dǎo)入頭文件 #import "WXApi.h" 掛上代理 WXApiDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//這里是你自己寫的一些其他代碼 實(shí)例化window 設(shè)置根視圖云云
[WXApi registerApp:@"APPID" withDescription:@"應(yīng)用描述"];
}
//支付回調(diào)
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [WXApi handleOpenURL:url delegate:self];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [WXApi handleOpenURL:url delegate:self];
}
#pragma mark 微信回調(diào)的代理方法
- (void)onResp:(BaseResp *)resp {
if ([resp isKindOfClass:[PayResp class]]) {
PayResp *response = (PayResp *)resp;
switch (response.errCode) {
case WXSuccess:
NSLog(@"suceess");
break;
default:
NSLog(@"failed");
break;
}
}
}
如果集成里支付寶以及微信支付等 姜挺,走的回調(diào)方法是相同的 ,我們是通過 回調(diào)中字符串sourceApplication 進(jìn)行判斷的 例如支付寶支付 為com.alipay.iphoneclient 微信支付為 com.tencent.xin
3.在targets的info中添加 urltypes添加一個(gè)在 identifier自己起一個(gè)名稱(最好軟件英文名字) 在 URL schemes 中寫下APPID
4.觸發(fā)支付
觸發(fā)支付彼硫,就要對(duì)自己的訂單號(hào)價(jià)格等進(jìn)行加密 在這里就可以分成兩種加密 炊豪,一種是在APP端進(jìn)行加密,第二種是在服務(wù)端進(jìn)行加密拧篮。一般使用的在服務(wù)端加密比較安全词渤。一個(gè)個(gè)進(jìn)行說明。
4.1 服務(wù)端進(jìn)行加密
服務(wù)端加密我們不需要知道具體加密怎么進(jìn)行的串绩。(在底下我會(huì)給你說清楚的啦~)我們只是需要將所需參數(shù)傳過去 我是用的AFN
//初始化一個(gè)請(qǐng)求管理器
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//接口地址
NSString *urlString = [NSString stringWithFormat:@"%@%@",@"地址頭",@"其他"];
//參數(shù)字典
NSDictionary *parameters =@{@"fcode": @"賬號(hào)",
@"password": @"密碼",@"out_trade_no":@"訂單號(hào)",@"total_fee":@"金額(分為單位)",@"attach":@"商品詳情"};
//post請(qǐng)求
[manager POST:urlString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
//返回狀態(tài)值1表示成功 0表示失敗
NSString *state=responseObject[@"state"];
//預(yù)支付ID
NSString *prepayid=responseObject[@"prepayid"];
//返回文字信息成功或者失敗
NSString *message=responseObject[@"message"];
//請(qǐng)求數(shù)據(jù)成功
if ([state intValue]==1) {
//支付信息
PayReq* req = [[PayReq alloc] init];
//APPID
req.openID = [responseObject objectForKey:@"appid"];
//商戶號(hào)
req.partnerId = [responseObject objectForKey:@"partnerid"];
//預(yù)支付ID
req.prepayId = [responseObject objectForKey:@"prepayid"];
//時(shí)間戳
req.nonceStr = [responseObject objectForKey:@"noncestr"];
//支付類型(為固定字符串:Sign=WXPay)
req.timeStamp = [[responseObject objectForKey:@"timestamp"] intValue];
//加密串
req.package = [responseObject objectForKey:@"package"];
//預(yù)支付ID
req.sign = [responseObject objectForKey:@"sign"];
// 發(fā)起微信支付
[WXApi sendReq:req];;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
后臺(tái)沒有加密錯(cuò)誤缺虐,那么會(huì)跳轉(zhuǎn)到微信上進(jìn)行支付。(好累啊 怎么還不結(jié)束呀)
4.2 APP端進(jìn)行加密
這種方法可以自己先進(jìn)行測(cè)試 礁凡,或者為了縮短工期自己進(jìn)行所有工作志笼。(看起來好像好厲害的樣子啊 )
首先,下載文章最底部封裝的微信支付文件把篓,導(dǎo)入到工程中纫溃。
支付界面引入頭文件
#import "ZQPay.h"
在觸發(fā)支付的方法中調(diào)用
[ZQPay payWXWithOrderName:@"訂單名字(不是訂單詳情)" price:@"訂單價(jià)格(單位為分)" tradeNo:@"訂單號(hào)" attach:@"訂單詳情"]
調(diào)用支付成功!結(jié)束 (我說了“結(jié)束”一定會(huì)打我的吧韧掩,原理步驟都不說 這太敷衍了 哈哈哈 紊浩,你們來打我啊)
![ZH]0RDFI%M7FXPS`(0FBEUE.jpg](http://upload-images.jianshu.io/upload_images/1141241-53e22ffdd4735dac.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
(傲迫瘛7凰!滑臊!不要打我 我說還不行嗎)
繼續(xù)正題口芍!
傳入?yún)?shù)我具體做了一些什么呢現(xiàn)在我就說說 步驟了啊(我不會(huì)就這樣輕易的狗帶)雇卷。
4.2.1 獲取預(yù)支付Id 鬓椭,將所需要參數(shù)封裝成字典
NSMutableDictionary *orderParas = [NSMutableDictionary dictionary];
[orderParas setObject: ZQAppID forKey:@"appid"]; //開放平臺(tái)appid
[orderParas setObject: ZQMchID forKey:@"mch_id"];//商戶號(hào)
[orderParas setObject: @"APP-001" forKey:@"device_info"]; //支付設(shè)備號(hào)或門店號(hào)
[orderParas setObject: noncestr forKey:@"nonce_str"]; //隨機(jī)串
[orderParas setObject: @"APP" forKey:@"trade_type"]; //支付類型,固定為APP
[orderParas setObject: order_name forKey:@"body"]; //訂單描述关划,展示給用戶
[orderParas setObject: ZQPayNotifyURL forKey:@"notify_url"]; //支付結(jié)果異步通知
[orderParas setObject: tradeNo forKey:@"out_trade_no"];//商戶訂單號(hào)
[orderParas setObject: [ZQDeVice deviceIPAdress] forKey:@"spbill_create_ip"];//發(fā)起支付的機(jī)器ip
[orderParas setObject: order_price forKey:@"total_fee"]; //訂單金額小染,單位為分
[orderParas setObject:attach forKey:@"attach"];//訂單詳細(xì)描述
4.2.2添加sign加密串 形成XMl格式字符串 paras 為封裝的字典(第一次加密)
NSString *sign;
NSMutableString *reqPars = [NSMutableString string];
//生成xml的package
NSArray *keys = [paras allKeys];
[reqPars appendString:@"<xml>\\n"];
for (NSString *categoryId in keys) {
[reqPars appendFormat:@"<%@>%@</%@>\\n", categoryId, [paras objectForKey:categoryId],categoryId];
}
//生成簽名,并將簽名添加到簽名包中
sign = [self createMd5Sign:paras];
[reqPars appendFormat:@"<sign>%@</sign>\\n</xml>", sign];
return [NSString stringWithString:reqPars];
4.2.3將獲取的xml串傳給微信獲取預(yù)支付ID 接口地址 @"https://api.mch.weixin.qq.com/pay/unifiedorder" send為XML串
//發(fā)送請(qǐng)求post xml數(shù)據(jù)
NSData *res = [ZQUtil httpSend:ZQPrePayURL method:@"POST" data:send];
ZQXMLHelper *xml = [[ZQXMLHelper alloc] init];
//開始解析
[xml startParse:res];
NSMutableDictionary *resParams = [xml getDict];
//判斷返回
NSString *return_code = [resParams objectForKey:@"return_code"];
NSString *result_code = [resParams objectForKey:@"result_code"];
NSString *codeDes = [resParams objectForKey:@"err_code_des"];
if ( [return_code isEqualToString:@"SUCCESS"] )
{
//生成返回?cái)?shù)據(jù)的簽名
NSString *sign = [self createMd5Sign:resParams];
NSString *send_sign =[resParams objectForKey:@"sign"] ;
//驗(yàn)證簽名正確性
if( [sign isEqualToString:send_sign]){
if( [result_code isEqualToString:@"SUCCESS"]) {
//驗(yàn)證業(yè)務(wù)處理狀態(tài)
prepayid = [resParams objectForKey:@"prepay_id"];
return_code = 0;
}
}
}
[dic setValue:prepayid forKey:@"prepay_id"];
[dic setValue:codeDes forKey:@"err_code_des"];
return dic;
4.2.4 將獲取的預(yù)支付id重新加密獲取新的sign 封裝成字典
//獲取到prepayid后進(jìn)行第二次簽名
NSString *package, *time_stamp, *nonce_str;
//設(shè)置支付參數(shù)
time_t now;
time(&now);
time_stamp = [NSString stringWithFormat:@"%ld", now];
nonce_str = [ZQUtil stringMd5WithString:time_stamp];
package = @"Sign=WXPay";
// 第二次簽名參數(shù)列表
NSMutableDictionary *signParas = [NSMutableDictionary dictionary];
[signParas setObject: ZQAppID forKey:@"appid"];
[signParas setObject: nonce_str forKey:@"noncestr"];
[signParas setObject: package forKey:@"package"];
[signParas setObject: ZQMchID forKey:@"partnerid"];
[signParas setObject: time_stamp forKey:@"timestamp"];
[signParas setObject: prepayID forKey:@"prepayid"];
// 生成簽名
NSString *sign = [self createMd5Sign:signParas];
// 添加簽名
[signParas setObject: sign forKey:@"sign"];
時(shí)間戳為新的時(shí)間戳 隨機(jī)數(shù)是通過時(shí)間戳MD5加密獲取的
4.2.5 至此加密結(jié)束 發(fā)起微信支付跳轉(zhuǎn)到微信進(jìn)行付款
PayReq* req = [[PayReq alloc] init];
req.openID = [paras objectForKey:@"appid"];
req.partnerId = [paras objectForKey:@"partnerid"];
req.prepayId = [paras objectForKey:@"prepayid"];
req.nonceStr = [paras objectForKey:@"noncestr"];
req.timeStamp = [[paras objectForKey:@"timestamp"] intValue];
req.package = [paras objectForKey:@"package"];
req.sign = [paras objectForKey:@"sign"];
// 發(fā)起微信支付
[WXApi sendReq:req];
5.微信支付成功以后 要通知服務(wù)端以及APP端 服務(wù)器是通過回調(diào)地址進(jìn)行操作,而對(duì)于App端通過Appdelegate中回調(diào)函數(shù)調(diào)用微信代理 步驟2中有說明。我就不再說了么么噠 (算了贮折,我再這里在重新嗶嗶一次吧)
//支付回調(diào)
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [WXApi handleOpenURL:url delegate:self];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [WXApi handleOpenURL:url delegate:self];
}
#pragma mark 微信回調(diào)的代理方法
- (void)onResp:(BaseResp *)resp {
if ([resp isKindOfClass:[PayResp class]]) {
PayResp *response = (PayResp *)resp;
NSString *message;
switch (response.errCode) {
case WXSuccess:
{ message=@"支付成功";
[[NSNotificationCenter defaultCenter] postNotificationName:APP_PAY_SUCCESS object:nil];
}
break;
case WXErrCodeCommon:
//普通錯(cuò)誤類型
message=@"支付錯(cuò)誤";
break;
case WXErrCodeUserCancel:
//用戶點(diǎn)擊取消并且返回
message=@"您取消了交易";
break;
case WXErrCodeSentFail:
//發(fā)送失敗
message=@"信息發(fā)送失敗";
break;
case WXErrCodeAuthDeny:
//授權(quán)失敗
message=@"授權(quán)失敗";
break;
case WXErrCodeUnsupport:
//微信不不支持
message=@"您的微信版本過低";
break;
default:
NSLog(@"failed");
break;
}
}
}
支付成功以后通過通知告知用戶支付情況
5.1 支付界面接收成功通知告知用戶(我這里是跳轉(zhuǎn)到新的界面)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appPaySuccess) name:APP_PAY_SUCCESS object:nil];
5.2通知方法
-(void)appPaySuccess{
ZQPaySuccessVC *paySuccessVC=[[ZQPaySuccessVC alloc]init];
[self.navigationController pushViewController:paySuccessVC animated:YES];
}
5.3移除通知(不移除會(huì)崩潰呦)
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:APP_PAY_SUCCESS object:nil];
}
6.支付完成裤翩!
歡迎小伙伴們給我補(bǔ)充,提意見 么么噠~~~
點(diǎn)我 獲取支付法寶
附:寶寶好累啊 關(guān)注本寶寶吧~~