iOS支付
iOS支付分為兩類,第三方支付和應(yīng)用內(nèi)支付(內(nèi)購)派继。
第三方支付包括:支付寶支付宾袜、微信支付、銀聯(lián)支付驾窟、百度錢包庆猫、京東支付等等。
應(yīng)用內(nèi)支付(In-App Purchase):在應(yīng)用程序內(nèi)購買虛擬商品绅络。如果你在App Store上銷售的應(yīng)用程序月培,將收到支付金額的70%。
第三方支付
彈出方式
網(wǎng)頁
有些第三方支付沒有安裝客戶端昨稼,可以直接彈出網(wǎng)頁進(jìn)行支付节视。(比如支付寶)
調(diào)用APP
手機(jī)中安裝了客戶端可以跳轉(zhuǎn)到APP中進(jìn)行支付拳锚。微信支付只能調(diào)用App進(jìn)行支付假栓。
支付寶支付
相關(guān)資料
支付寶開放平臺(tái)(SDK&開發(fā)文檔):https://open.alipay.com/platform/home.htm
移動(dòng)支付集成:https://doc.open.alipay.com/doc2/detail?treeId=59&articleId=103563&docType=1
商戶服務(wù)平臺(tái)(與支付寶簽約需要填寫的公司資料):https://b.alipay.com/newIndex.htm
支付流程
在商戶服務(wù)平臺(tái)先與支付寶簽約,獲得商戶ID(partner)和賬號(hào)ID(seller)霍掺,需要提供公司資質(zhì)或者營業(yè)執(zhí)照匾荆,個(gè)人無法申請(qǐng)。
文檔地址:https://doc.open.alipay.com/doc2/detail?treeId=58&articleId=103542&docType=1
生成并下載相應(yīng)的公鑰私鑰文件(加密簽名用)
文檔地址:https://doc.open.alipay.com/doc2/detail.htm?spm=0.0.0.0.POMYKl&treeId=58&articleId=103543&docType=1
下載支付寶SDK:https://doc.open.alipay.com/doc2/detail?treeId=54&articleId=103419&docType=1
生成訂單信息
調(diào)用支付寶客戶端杆烁,由支付寶客戶端跟支付寶安全服務(wù)器打交道
支付完畢后返回支付結(jié)果給商戶客戶端和服務(wù)器
SDK里有集成支付寶功能的一個(gè)Demo牙丽,集成支付功能的具體操作方式,可以參考Demo兔魂。
代碼集成流程
參考文檔地址:https://doc.open.alipay.com/doc2/detail.htm?spm=0.0.0.0.efmKDS&treeId=59&articleId=103676&docType=1
下載官方SDK
下載地址:https://doc.open.alipay.com/doc2/detail?treeId=54&articleId=103419&docType=1
本Demo使用的SDK是從官方Demo整理出來的烤芦,整理的SDK版本:201501022。
下載地址:http://7xooko.com1.z0.glb.clouddn.com/AlipaySDK.zip
目錄結(jié)構(gòu)如下:
├──AlipaySDK.bundle├──AlipaySDK.framework├──Order.h├──Order.m├──Util├──libcrypto.a├──libssl.a└──openssl
其中:
AlipaySDK.bundle和AlipaySDK.framework是支付寶SDK
Order類:定義訂單信息
Util析校、libcrypto.a构罗、libssl.a铜涉、openssl:數(shù)據(jù)簽名,對(duì)訂單信息進(jìn)行加密
添加依賴庫
其中遂唧,需要注意的是:
如果是Xcode 7.0之后的版本芙代,需要添加libc++.tbd、libz.tbd盖彭;
如果是Xcode 7.0之前的版本纹烹,需要添加libc++.dylib、libz.dylib召边。
創(chuàng)建prefix header filePCH文件铺呵,添加#import
在Build Settings中的prefix header設(shè)置pch文件路徑
在Build Settings中Header Search Paths添加頭文件引用路徑,[文件路徑]/AlipaySDK/
在需要調(diào)用AlipaySDK的文件中隧熙,增加頭文件引用陪蜻。
#import#import"Order.h"#import"DataSigner.h"
生成訂單信息及簽名
//將商品信息賦予AlixPayOrder的成員變量Order *order = [[Order alloc] init];order.partner= PartnerID;// 商戶IDorder.seller= SellerID;// 賬號(hào)IDorder.tradeNO=@"20150923";//訂單ID(由商家自行制定)order.productName=@"iPhone6s";//商品標(biāo)題order.productDescription=@"新年打折";//商品描述order.amount=@"0.01";//商品價(jià)格(單位:元)order.notifyURL=@"http://www.chaosky.me";//回調(diào)URL,支付成功或者失敗回調(diào)通知自己的服務(wù)器進(jìn)行訂單狀態(tài)變更order.service=@"mobile.securitypay.pay";order.paymentType=@"1";order.inputCharset=@"utf-8";order.itBPay=@"30m";order.showUrl=@"m.alipay.com";// 應(yīng)用注冊(cè)scheme,在AlixPayDemo-Info.plist定義URL typesNSString*appScheme =@"AliPayDemo";//將商品信息拼接成字符串NSString*orderSpec = [order description];NSLog(@"orderSpec = %@",orderSpec);//獲取私鑰并將商戶信息簽名,外部商戶可以根據(jù)情況存放私鑰和簽名,只需要遵循RSA簽名規(guī)范,并將簽名字符串base64編碼和UrlEncodeid signer = CreateRSADataSigner(PartnerPrivKey);NSString*signedString = [signer signString:orderSpec];//將簽名成功字符串格式化為訂單字符串,請(qǐng)嚴(yán)格按照該格式NSString*orderString =nil;if(signedString !=nil) {? ? orderString = [NSStringstringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"",? ? ? ? ? ? ? ? ?? orderSpec, signedString,@"RSA"];? ? [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary*resultDic) {NSLog(@"reslut = %@",resultDic);? ? }];}
Xcode設(shè)置URL scheme
iPhone SDK可以把你的App和一個(gè)自定義的URL Scheme綁定贱鼻。該URL Scheme可用來從瀏覽器或別的App啟動(dòng)你的App宴卖。
配置方法:打開info.plist文件,找到或者添加如圖所示的鍵值對(duì):
URL Scheme值為代碼中對(duì)應(yīng)的值邻悬,必須一致症昏。
配置支付寶客戶端返回url處理方法
AppDelegate.m文件中,增加引用代碼:
#import
在@implementation AppDelegate中增加如下代碼:
- (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation{//如果極簡開發(fā)包不可用父丰,會(huì)跳轉(zhuǎn)支付寶錢包進(jìn)行支付肝谭,需要將支付寶錢包的支付結(jié)果回傳給開發(fā)包if([url.hostisEqualToString:@"safepay"]) {? ? ? ? [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary*resultDic) {//【由于在跳轉(zhuǎn)支付寶客戶端支付的過程中,商戶app在后臺(tái)很可能被系統(tǒng)kill了蛾扇,所以pay接口的callback就會(huì)失效攘烛,請(qǐng)商戶對(duì)standbyCallback返回的回調(diào)結(jié)果進(jìn)行處理,就是在這個(gè)方法里面處理跟callback一樣的邏輯】NSLog(@"result = %@",resultDic);? ? ? ? }];? ? }if([url.hostisEqualToString:@"platformapi"]){//支付寶錢包快登授權(quán)返回authCode[[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary*resultDic) {//【由于在跳轉(zhuǎn)支付寶客戶端支付的過程中,商戶app在后臺(tái)很可能被系統(tǒng)kill了镀首,所以pay接口的callback就會(huì)失效坟漱,請(qǐng)商戶對(duì)standbyCallback返回的回調(diào)結(jié)果進(jìn)行處理,就是在這個(gè)方法里面處理跟callback一樣的邏輯】NSLog(@"result = %@",resultDic);? ? ? ? }];? ? }returnYES;}
微信支付
需要提供公司資質(zhì)或者營業(yè)執(zhí)照,個(gè)人無法申請(qǐng)更哄。
相關(guān)文檔
微信開放平臺(tái):https://open.weixin.qq.com
微信支付商戶平臺(tái):https://pay.weixin.qq.com/index.php
微信公眾平臺(tái):https://mp.weixin.qq.com
支付流程
向微信注冊(cè)你的應(yīng)用程序id
開發(fā)者應(yīng)用登記頁面進(jìn)行登記芋齿,登記并選擇移動(dòng)應(yīng)用進(jìn)行設(shè)置后,將獲得AppID成翩,可立即用于開發(fā)觅捆。但應(yīng)用登記完成后還需要提交審核,只有審核通過的應(yīng)用才能正式發(fā)布使用麻敌。
微信APP支付接入商戶服務(wù)中心
下載微信SDK文件栅炒,如果在項(xiàng)目中應(yīng)使用SDK的最新版。
本Demo使用的SDK是從官方Demo整理出來的,整理的SDK版本:1.6.1赢赊。
下載地址:http://7xooko.com1.z0.glb.clouddn.com/AlipaySDK.zip
目錄結(jié)構(gòu)如下:
├──SDKExport│?? ├──WXApi.h│?? ├──WXApiObject.h│?? ├──libWeChatSDK.a│?? └──read_me.txt└──lib├──ApiXml.h├──ApiXml.mm├──WXUtil.h├──WXUtil.mm├──payRequsestHandler.h└──payRequsestHandler.mm
其中:
SDKExport文件夾:SDK文件
lib文件夾:工具類
添加依賴庫
SystemConfiguration.frameworklibz.dyliblibsqlite3.dyliblibc++.dylibCoreTelephony.frameworkCoreGraphics.framework
Xcode設(shè)置URL scheme
在Xcode中棒呛,選擇你的工程設(shè)置項(xiàng),選中“TARGETS”一欄域携,在“info”標(biāo)簽欄的“URL type“添加“URL scheme”為你所注冊(cè)的應(yīng)用程序id(如下圖所示)簇秒。
在你需要使用微信終端API的文件中import WXApi.h 頭文件,并增加 WXApiDelegate 協(xié)議秀鞭。
// 微信所有的API接口#import"WXApi.h"http:// APP端簽名相關(guān)頭文件#import"payRequsestHandler.h"@interfaceAppDelegate()@end
要使你的程序啟動(dòng)后微信終端能響應(yīng)你的程序趋观,必須在代碼中向微信終端注冊(cè)你的id。(如下圖所示锋边,在 AppDelegate 的 didFinishLaunchingWithOptions 函數(shù)中向微信注冊(cè)id)皱坛。
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {// Override point for customization after application launch.//向微信注冊(cè)[WXApi registerApp:APP_ID withDescription:@"demo 2.0"];returnYES;}
重寫AppDelegate的handleOpenURL和openURL方法:
- (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];}
現(xiàn)在,你的程序要實(shí)現(xiàn)和微信終端交互的具體請(qǐng)求與回應(yīng)豆巨,因此需要實(shí)現(xiàn)WXApiDelegate協(xié)議的兩個(gè)方法:
-(void) onReq:(BaseReq*)req{if([req isKindOfClass:[GetMessageFromWXReq class]])? ? {// 微信請(qǐng)求App提供內(nèi)容剩辟, 需要app提供內(nèi)容后使用sendRsp返回NSString*strTitle = [NSStringstringWithFormat:@"微信請(qǐng)求App提供內(nèi)容"];NSString*strMsg =@"微信請(qǐng)求App提供內(nèi)容,App要調(diào)用sendResp:GetMessageFromWXResp返回給微信";UIAlertView*alert = [[UIAlertViewalloc] initWithTitle:strTitle message:strMsg delegate:selfcancelButtonTitle:@"OK"otherButtonTitles:nil,nil];? ? ? ? alert.tag=1000;? ? ? ? [alert show];? ? }elseif([req isKindOfClass:[ShowMessageFromWXReq class]])? ? {? ? ? ? ShowMessageFromWXReq* temp = (ShowMessageFromWXReq*)req;? ? ? ? WXMediaMessage *msg = temp.message;//顯示微信傳過來的內(nèi)容WXAppExtendObject *obj = msg.mediaObject;NSString*strTitle = [NSStringstringWithFormat:@"微信請(qǐng)求App顯示內(nèi)容"];NSString*strMsg = [NSStringstringWithFormat:@"標(biāo)題:%@ \n內(nèi)容:%@ \n附帶信息:%@ \n縮略圖:%lu bytes\n\n", msg.title, msg.description, obj.extInfo, msg.thumbData.length];UIAlertView*alert = [[UIAlertViewalloc] initWithTitle:strTitle message:strMsg delegate:selfcancelButtonTitle:@"OK"otherButtonTitles:nil,nil];? ? ? ? [alert show];? ? }elseif([req isKindOfClass:[LaunchFromWXReq class]])? ? {//從微信啟動(dòng)AppNSString*strTitle = [NSStringstringWithFormat:@"從微信啟動(dòng)"];NSString*strMsg =@"這是從微信啟動(dòng)的消息";UIAlertView*alert = [[UIAlertViewalloc] initWithTitle:strTitle message:strMsg delegate:selfcancelButtonTitle:@"OK"otherButtonTitles:nil,nil];? ? ? ? [alert show];? ? }}
onReq是微信終端向第三方程序發(fā)起請(qǐng)求往扔,要求第三方程序響應(yīng)贩猎。第三方程序響應(yīng)完后必須調(diào)用sendRsp返回。在調(diào)用sendRsp返回時(shí)萍膛,會(huì)切回到微信終端程序界面吭服。
-(void) onResp:(BaseResp*)resp {NSString*strMsg = [NSStringstringWithFormat:@"errcode:%d", resp.errCode];NSString*strTitle;if([resp isKindOfClass:[SendMessageToWXResp class]])? ?? {? ? ? ?? strTitle = [NSStringstringWithFormat:@"發(fā)送媒體消息結(jié)果"];? ?? }if([resp isKindOfClass:[PayResp class]]){//支付返回結(jié)果,實(shí)際支付結(jié)果需要去微信服務(wù)器端查詢strTitle = [NSStringstringWithFormat:@"支付結(jié)果"];switch(resp.errCode) {caseWXSuccess:? ? ? ? ? ? ? ?? strMsg =@"支付結(jié)果:成功蝗罗!";NSLog(@"支付成功-PaySuccess艇棕,retcode = %d", resp.errCode);break;default:? ? ? ? ? ? ? ?? strMsg = [NSStringstringWithFormat:@"支付結(jié)果:失敗串塑!retcode = %d, retstr = %@", resp.errCode,resp.errStr];NSLog(@"錯(cuò)誤沼琉,retcode = %d, retstr = %@", resp.errCode,resp.errStr);break;? ? ? ?? }? ?? }UIAlertView*alert = [[UIAlertViewalloc] initWithTitle:strTitle message:strMsg delegate:selfcancelButtonTitle:@"OK"otherButtonTitles:nil,nil];? ?? [alert show]; }
如果第三方程序向微信發(fā)送了sendReq的請(qǐng)求,那么onResp會(huì)被回調(diào)桩匪。sendReq請(qǐng)求調(diào)用后打瘪,會(huì)切到微信終端程序界面
應(yīng)用內(nèi)支付(In-App Purchase)
在應(yīng)用程序內(nèi)購買虛擬商品。如果你在App Store上銷售的應(yīng)用程序吸祟,將收到支付金額的70%瑟慈。
相關(guān)資料
沙盒測試賬號(hào):352135598@qq.com 密碼:Test1234phone
支付流程
配置App ID
為應(yīng)用建立建立一個(gè)不帶通配符的App ID
用該App ID生成和安裝相應(yīng)的Provisioning Profile文件。
配置iTunes Connect
填寫相關(guān)的稅務(wù)屋匕,銀行,聯(lián)系人信息
參考鏈接:iOS App提交指南(二)-協(xié)議借杰、稅務(wù)和銀行業(yè)務(wù)
添加一個(gè)用于在sandbox付費(fèi)的測試用戶
用該App ID創(chuàng)建一個(gè)新的應(yīng)用过吻。
創(chuàng)建應(yīng)用內(nèi)付費(fèi)項(xiàng)目,選擇付費(fèi)類型。
App 內(nèi)購買項(xiàng)目摘要填寫
主要代碼實(shí)現(xiàn)
在工程中引入StoreKit.framework和#import
獲得所有的付費(fèi)Product ID列表纤虽。這個(gè)可以用常量存儲(chǔ)在本地乳绕,也可以由自己的服務(wù)器返回。
//在內(nèi)購項(xiàng)目中創(chuàng)建的商品單號(hào)#defineProductID_IAP_FTHJ @"com.1000phone.IAPDemo.fthj_purple"http:// 方天畫戟 488元#defineProductID_IAP_XYJ @"com.1000phone.IAPDemo.xyj"http:// 軒轅劍 6,498元#defineProductID_IAP_JB @"com.1000phone.IAPDemo.jb"http:// 金幣 6元=6金幣
?
制作界面逼纸,展示所有的應(yīng)用內(nèi)付費(fèi)項(xiàng)目洋措。這些應(yīng)用內(nèi)付費(fèi)項(xiàng)目的價(jià)格和介紹信息可以從App Store服務(wù)器請(qǐng)求,也可以是自己的服務(wù)器返回杰刽。向App Store查詢速度非常慢菠发,通常需要2-3秒鐘,最好從服務(wù)器請(qǐng)求贺嫂。
- (void)createViews{NSArray* buttonNames = @[@"軒轅劍 6498元",@"方天畫戟 488元",@"金幣6元=6金幣"];? ? __weaktypeof(self) weakSelf =self;? ? [buttonNames enumerateObjectsUsingBlock:^(NSString* buttonName,NSUIntegeridx,BOOL* stop) {UIButton* button = [UIButtonbuttonWithType:UIButtonTypeSystem];? ? ? ? [weakSelf.viewaddSubview:button];? ? ? ? button.frame=CGRectMake(100,100+ idx?? *60,150,50);? ? ? ? button.titleLabel.font= [UIFontsystemFontOfSize:18];? ? ? ? [button setTitle:buttonName forState:UIControlStateNormal];// 設(shè)置tag值button.tag= PAY_BUTTON_BEGIN_TAG + idx;? ? ? ? [button addTarget:selfaction:@selector(buyProduct:) forControlEvents:UIControlEventTouchUpInside];? ? }];}- (void)buyProduct:(UIButton*) sender{}
?
當(dāng)用戶點(diǎn)擊了一個(gè)IAP項(xiàng)目滓鸠,我們先查詢用戶是否允許應(yīng)用內(nèi)付費(fèi)。
- (void)buyProduct:(UIButton*) sender{self.buyType= sender.tag- PAY_BUTTON_BEGIN_TAG;if([SKPaymentQueue canMakePayments]) {// 執(zhí)行下面提到的第5步:[selfrequestProductData];NSLog(@"允許程序內(nèi)付費(fèi)購買");? ? }else{NSLog(@"不允許程序內(nèi)付費(fèi)購買");UIAlertView*alerView =? [[UIAlertViewalloc] initWithTitle:@"提示"message:@"您的手機(jī)沒有打開程序內(nèi)付費(fèi)購買"delegate:nilcancelButtonTitle:NSLocalizedString(@"關(guān)閉",nil) otherButtonTitles:nil];? ? ? ? [alerView show];? ? }}
我們先通過該IAP的ProductID向AppStore查詢第喳,獲得SKPayment實(shí)例糜俗,然后通過SKPaymentQueue的 addPayment方法發(fā)起一個(gè)購買的操作。
// 下面的ProductId應(yīng)該是事先在itunesConnect中添加好的曲饱,已存在的付費(fèi)項(xiàng)目悠抹。否則查詢會(huì)失敗。- (void)requestProductData {NSLog(@"---------請(qǐng)求對(duì)應(yīng)的產(chǎn)品信息------------");NSArray*product =nil;switch(self.buyType) {case0:? ? ? ? ?? product = [NSArrayarrayWithObject:ProductID_IAP_XYJ];break;case1:? ? ? ? ?? product = [NSArrayarrayWithObject:ProductID_IAP_FTHJ];break;case2:? ? ? ? ?? product = [NSArrayarrayWithObject:ProductID_IAP_JB];break;?? }NSSet*nsset = [NSSetsetWithArray:product];?? SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];?? request.delegate=self;?? [request start];}#pragma mark - SKProductsRequestDelegate// 收到的產(chǎn)品信息回調(diào)- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{NSLog(@"-----------收到產(chǎn)品反饋信息--------------");NSArray*myProduct = response.products;if(myProduct.count==0) {NSLog(@"無法獲取產(chǎn)品信息扩淀,購買失敗锌钮。");return;?? }NSLog(@"產(chǎn)品Product ID:%@",response.invalidProductIdentifiers);NSLog(@"產(chǎn)品付費(fèi)數(shù)量: %d", (int)[myProduct count]);// populate UIfor(SKProduct *productinmyProduct){NSLog(@"product info");NSLog(@"SKProduct 描述信息%@", [product description]);NSLog(@"產(chǎn)品標(biāo)題 %@", product.localizedTitle);NSLog(@"產(chǎn)品描述信息: %@", product.localizedDescription);NSLog(@"價(jià)格: %@", product.price);NSLog(@"Product id: %@", product.productIdentifier);?? }?? SKPayment * payment = [SKPayment paymentWithProduct:myProduct[0]];NSLog(@"---------發(fā)送購買請(qǐng)求------------");?? [[SKPaymentQueue defaultQueue] addPayment:payment];}//彈出錯(cuò)誤信息- (void)request:(SKRequest *)request didFailWithError:(NSError*)error{NSLog(@"-------彈出錯(cuò)誤信息----------");UIAlertView*alerView =? [[UIAlertViewalloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? delegate:nilcancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil];?? [alerView show];}-(void) requestDidFinish:(SKRequest *)request{NSLog(@"----------反饋信息結(jié)束--------------");}
在viewDidLoad方法中,將購買頁面設(shè)置成購買的Observer引矩。
- (void)viewDidLoad {? ? [superviewDidLoad];? ? [selfcreateViews];// 監(jiān)聽購買結(jié)果[[SKPaymentQueue defaultQueue] addTransactionObserver:self];}- (void)dealloc{? ? [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];}
當(dāng)用戶購買的操作有結(jié)果時(shí)梁丘,就會(huì)觸發(fā)下面的回調(diào)函數(shù),相應(yīng)進(jìn)行處理即可旺韭。
#pragma mark - SKPaymentTransactionObserver// 處理交易結(jié)果- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray*)transactions {for(SKPaymentTransaction *transactionintransactions)? ? {switch(transaction.transactionState)? ? ? ? {caseSKPaymentTransactionStatePurchased://交易完成NSLog(@"transactionIdentifier = %@", transaction.transactionIdentifier);? ? ? ? ? ? ? ? [selfcompleteTransaction:transaction];break;caseSKPaymentTransactionStateFailed://交易失敗[selffailedTransaction:transaction];break;caseSKPaymentTransactionStateRestored://已經(jīng)購買過該商品[selfrestoreTransaction:transaction];break;caseSKPaymentTransactionStatePurchasing://商品添加進(jìn)列表NSLog(@"商品添加進(jìn)列表");break;default:break;? ? ? ? }? ? }}// 交易完成- (void)completeTransaction:(SKPaymentTransaction *)transaction {NSString* productIdentifier = transaction.payment.productIdentifier;//? ? NSString * receipt = [transaction.transactionReceipt base64EncodedString];if([productIdentifier length] >0) {// 向自己的服務(wù)器驗(yàn)證購買憑證}// Remove the transaction from the payment queue.[[SKPaymentQueue defaultQueue] finishTransaction: transaction];}// 交易失敗- (void)failedTransaction:(SKPaymentTransaction *)transaction {if(transaction.error.code!= SKErrorPaymentCancelled) {NSLog(@"購買失敗");? ? }else{NSLog(@"用戶取消交易");? ? }? ? [[SKPaymentQueue defaultQueue] finishTransaction: transaction];}// 已購商品- (void)restoreTransaction:(SKPaymentTransaction *)transaction {// 對(duì)于已購商品氛谜,處理恢復(fù)購買的邏輯[[SKPaymentQueue defaultQueue] finishTransaction: transaction];}
服務(wù)器驗(yàn)證憑證(Optional)。如果購買成功区端,我們需要將憑證發(fā)送到服務(wù)器上進(jìn)行驗(yàn)證值漫。考慮到網(wǎng)絡(luò)異常情況织盼,iOS端的發(fā)送憑證操作應(yīng)該進(jìn)行持久化杨何,如果程序退出,崩潰或網(wǎng)絡(luò)異常沥邻,可以恢復(fù)重試危虱。