iOS - 支付詳解
在iOS開發中,常常會涉及到支付功能,這裡對常見的支付做一下詳細說明
1. 支付1.1 開放平台帳號的註冊
開放平台(支付需要付費的,註冊成功後使用的主要為AppKey/SecretKey,其中SecrectKey交由後台完成整合)
開放平台是商戶APP接入支付開放介面的申請入口,通過此平台可申請APP支付。
1.2 項目的修改與設定
1)首先應該下載SDK並匯入項目(這裡以友盟內建支付說明,具體內容相似)
如果項目中使用了友盟社會化分享SDK,那麼你將不需要重複匯入SDK,友盟中已經整合了支付。具體SDK如下:
如果你的項目沒有使用友盟,請到開放平台下載最新的SDK,然後倒入您的項目。具體的SDK如下:
2)在添加完SDK後需要添加相應的庫以及檔案
3)然後是添加對應的url用於調起
4) 添加白名單、關閉Bitcode(對於http/https適配iOS9.0自行修改)
1.3 SDK的註冊與回調
在完成了上面的操作之後,我們所匯入的SDK就可以使用了,很簡單
1) 首先我們要進行註冊
匯入#import “WXApi.h”
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. ViewController *userGuideViewController = [[ViewController alloc] init]; self.window.rootViewController = userGuideViewController; [WXApi registerApp:@"這裡添加APPKey"]; return YES;}
2)接著我們要寫一個調起
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options{ // 跳轉到URL scheme中配置的地址 //NSLog(@"跳轉到URL scheme中配置的地址-->%@",url); return [WXApi handleOpenURL:url delegate:(id)self];}
3)然後是回調
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{ // NSLog(@"****************url.host -- %@",url.host); if ([url.scheme isEqualToString:@"這裡添加AppKey"]) { return [WXApi handleOpenURL:url delegate:(id)self]; } return YES;}- (void) onResp:(BaseResp*)resp{ NSString *strMsg = [NSString stringWithFormat:@"errcode:%d", resp.errCode]; NSString *strTitle = @"支付結果"; if([resp isKindOfClass:[PayResp class]]){ switch (resp.errCode) { case WXSuccess: strMsg = @"支付結果:成功!"; break; case WXErrCodeUserCancel: strMsg = @"支付結果:使用者點擊取消!"; break; case WXErrCodeSentFail: strMsg = @"支付結果:發送失敗!"; break; case WXErrCodeAuthDeny: strMsg = @"支付結果:授權失敗!"; break; default: strMsg = @"支付結果:不支援!"; break; } UIAlertView *alert = [[UIAlertView alloc] initWithTitle:strTitle message:strMsg delegate:self cancelButtonTitle:@"確定" otherButtonTitles:nil, nil]; [alert show]; }}
- (void) onResp:(BaseResp*)resp{ NSString *strMsg = [NSString stringWithFormat:@"errcode:%d", resp.errCode]; NSString *strTitle = @"支付結果"; if([resp isKindOfClass:[PayResp class]]){ switch (resp.errCode) { case WXSuccess: strMsg = @"支付結果:成功!"; break; case WXErrCodeUserCancel: strMsg = @"支付結果:使用者點擊取消!"; break; case WXErrCodeSentFail: strMsg = @"支付結果:發送失敗!"; break; case WXErrCodeAuthDeny: strMsg = @"支付結果:授權失敗!"; break; default: strMsg = @"支付結果:不支援!"; break; } UIAlertView *alert = [[UIAlertView alloc] initWithTitle:strTitle message:strMsg delegate:self cancelButtonTitle:@"確定" otherButtonTitles:nil, nil]; [alert show]; }}
1.4 SDK的使用
1) 最後是在項目中需要進行支付的地方使用支付(這是完成整個支付流程中最重要的一部分,也是最需要注意的地方)
首先要進行一次網路請求,後台介面,將你的商品資訊發送到後台,產生訂單後返回,返回資訊中最少要包含六個參數,通過這些參數調起支付。
匯入#import “WXApi.h”
//返回參數調起支付PayReq* req = [[PayReq alloc] init]; NSMutableDictionary *dict=[result objectForKey:@"resultCode"]; req.openID = [dict objectForKey:@"appid"]; req.partnerId = [dict objectForKey:@"mch_id"]; req.prepayId = [dict objectForKey:@"prepay_id"]; req.nonceStr = [self md5:time_stamp]; req.timeStamp = [time_stamp intValue]; req.package = @"Sign=WXpay"; //簽名(這個簽名可以自己進行簽名,也可以後台操作,由後台返回) NSMutableDictionary *signParams=[[NSMutableDictionary alloc] init]; [signParams setObject: req.openID forKey:@"appid"]; [signParams setObject: req.nonceStr forKey:@"noncestr"]; [signParams setObject: req.package forKey:@"package"]; [signParams setObject: req.partnerId forKey:@"partnerid"]; [signParams setObject: time_stamp forKey:@"timestamp"]; [signParams setObject: req.prepayId forKey:@"prepayid"]; req.sign = [self createMd5Sign:signParams]; //調起支付(**參數有一個錯誤,將不能完成調起**) [WXApi sendReq:req];
2) 自行加密處理(這部分可以由後台完成)
//支付加密-(NSString *) md5:(NSString *)str{ const char *cStr = [str UTF8String]; unsigned char digest[CC_MD5_DIGEST_LENGTH]; CC_MD5( cStr, (unsigned int)strlen(cStr), digest ); NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) [output appendFormat:@"%02X", digest[i]]; return output;}-(NSString*) createMd5Sign:(NSMutableDictionary*)dict{ NSMutableString *contentString =[NSMutableString string]; NSArray *keys = [dict allKeys]; //按字母順序排序 NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { return [obj1 compare:obj2 options:NSNumericSearch]; }]; //拼接字串 for (NSString *categoryId in sortedArray) { if (![[dict objectForKey:categoryId] isEqualToString:@""] && ![categoryId isEqualToString:@"sign"] && ![categoryId isEqualToString:@"key"] ) { [contentString appendFormat:@"%@=%@&", categoryId, [dict objectForKey:categoryId]]; } } //添加key欄位 [contentString appendFormat:@"key=%@", @"這裡添加SecretKey"]; NSString *md5Sign =[WXUtil md5:contentString]; return md5Sign;}
1.5常見異常Bug處理
1) 常見問題為支付調起不成功,每次調起只能調起一個帶有你返回確認按鈕的頁面。
原因:參數錯誤,特別注意參數(簽名),背景返回的參數不正確。
解決方案:逐個校正參數,簽名可以本地加密處理,不要依賴背景返回簽名,有的時候後台返回的是不正確的。