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)資料
- 支付寶開放平臺(SDK&開發(fā)文檔):
https://open.alipay.com/platform/home.htm - 移動支付集成:
https://doc.open.alipay.com/doc2/detail?treeId=59&articleId=103563&docType=1 - 商戶服務(wù)平臺(與支付寶簽約需要填寫的公司資料):
https://b.alipay.com/newIndex.htm
支付流程
-
在商戶服務(wù)平臺先與支付寶簽約,獲得商戶ID(partner)和賬號ID(seller),需要提供公司資質(zhì)或者營業(yè)執(zhí)照,個人無法申請。
文檔地址:
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?0treeId=54&articleId=103419&docType=1生成訂單信息
調(diào)用支付寶客戶端,由支付寶客戶端跟支付寶安全服務(wù)器打交道
支付完畢后返回支付結(jié)果給商戶客戶端和服務(wù)器
SDK里有集成支付寶功能的一個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ù)簽名,對訂單信息進(jìn)行加密
-
-
添加依賴庫
其中,需要注意的是:
如果是Xcode 7.0之后的版本,需要添加libc++.tbd、libz.tbd;
如果是Xcode 7.0之前的版本,需要添加libc++.dylib、libz.dylib。
-
創(chuàng)建
prefix header file
PCH文件,添加#import <Foundation/Foundation.h>
在
Build Settings
中的prefix header
設(shè)置pch文件路徑 在
Build Settings
中Header Search Paths
添加頭文件引用路徑,[文件路徑]/AlipaySDK/
-
在需要調(diào)用AlipaySDK的文件中,增加頭文件引用。
#import <AlipaySDK/AlipaySDK.h> #import "Order.h" #import "DataSigner.h"
-
生成訂單信息及簽名
//將商品信息賦予AlixPayOrder的成員變量 Order *order = [[Order alloc] init]; order.partner = PartnerID; // 商戶ID order.seller = SellerID; // 賬號ID order.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)用注冊scheme,在AlixPayDemo-Info.plist定義URL types NSString *appScheme = @"AliPayDemo"; //將商品信息拼接成字符串 NSString *orderSpec = [order description]; NSLog(@"orderSpec = %@",orderSpec); //獲取私鑰并將商戶信息簽名,外部商戶可以根據(jù)情況存放私鑰和簽名,只需要遵循RSA簽名規(guī)范,并將簽名字符串base64編碼和UrlEncode id<DataSigner> signer = CreateRSADataSigner(PartnerPrivKey); NSString *signedString = [signer signString:orderSpec]; //將簽名成功字符串格式化為訂單字符串,請嚴(yán)格按照該格式 NSString *orderString = nil; if (signedString != nil) { orderString = [NSString stringWithFormat:@"%@&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和一個自定義的URL Scheme綁定。該URL Scheme可用來從瀏覽器或別的App啟動你的App。
配置方法:打開info.plist文件,找到或者添加如圖所示的鍵值對:
URL Scheme值為代碼中對應(yīng)的值,必須一致。
-
配置支付寶客戶端返回url處理方法
AppDelegate.m文件中,增加引用代碼:
#import <AlipaySDK/AlipaySDK.h>
在@implementation AppDelegate中增加如下代碼:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { //如果極簡開發(fā)包不可用,會跳轉(zhuǎn)支付寶錢包進(jìn)行支付,需要將支付寶錢包的支付結(jié)果回傳給開發(fā)包 if ([url.host isEqualToString:@"safepay"]) { [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary * resultDic) { //【由于在跳轉(zhuǎn)支付寶客戶端支付的過程中,商戶app在后臺很可能被系統(tǒng)kill了,所以pay接口的callback就會失效,請商戶對standbyCallback返回的回調(diào)結(jié)果進(jìn)行處理,就是在這個方法里面處理跟callback一樣的邏輯】 NSLog(@"result = %@",resultDic); }]; } if ([url.host isEqualToString:@"platformapi"]){//支付寶錢包快登授權(quán)返回authCode [[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary * resultDic) { //【由于在跳轉(zhuǎn)支付寶客戶端支付的過程中,商戶app在后臺很可能被系統(tǒng)kill了,所以pay接口的callback就會失效,請商戶對standbyCallback返回的回調(diào)結(jié)果進(jìn)行處理,就是在這個方法里面處理跟callback一樣的邏輯】 NSLog(@"result = %@",resultDic); }]; } return YES; }
微信支付
需要提供公司資質(zhì)或者營業(yè)執(zhí)照,個人無法申請。
相關(guān)文檔
- 微信開放平臺:https://open.weixin.qq.com
- 微信支付商戶平臺:https://pay.weixin.qq.com/index.php
- 微信公眾平臺:https://mp.weixin.qq.com
支付流程
-
向微信注冊你的應(yīng)用程序id
開發(fā)者應(yīng)用登記頁面 進(jìn)行登記,登記并選擇移動應(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.framework libz.dylib libsqlite3.dylib libc++.dylib CoreTelephony.framework CoreGraphics.framework
-
在需要調(diào)用WeChatSDK的文件中,增加頭文件引用。
#import "WXApi.h" #import "payRequsestHandler.h"
-
生成訂單信息及簽名
#pragma mark - 微信支付 - (void)wechatPayAction:(UIButton *) sender { // 判斷用戶是否安裝微信 if (![WXApi isWXAppInstalled]) { UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"請安裝微信客戶端" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil]; [alertView show]; return; } // 實(shí)現(xiàn)支付 [self sendPay_demo]; } - (void)sendPay_demo { //{{{ //本實(shí)例只是演示簽名過程, 請將該過程在商戶服務(wù)器上實(shí)現(xiàn) // 配置微信支付的參數(shù) //創(chuàng)建支付簽名對象 payRequsestHandler *req = [[payRequsestHandler alloc] init]; //初始化支付簽名對象 [req init:__WXappID mch_id:__WXmchID]; //設(shè)置密鑰 [req setKey:__WXpaySignKey]; //}}} //獲取到實(shí)際調(diào)起微信支付的參數(shù)后,在app端調(diào)起支付 NSMutableDictionary *dict = [req sendPay_demo]; if(dict == nil){ //錯誤提示 NSString *debug = [req getDebugifo]; [self alert:@"提示信息" msg:debug]; NSLog(@"%@\n\n",debug); }else{ NSLog(@"%@\n\n",[req getDebugifo]); //[self alert:@"確認(rèn)" msg:@"下單成功,點(diǎn)擊OK后調(diào)起支付!"]; NSMutableString *stamp = [dict objectForKey:@"timestamp"]; //調(diào)起微信支付 PayReq* req = [[PayReq alloc] init]; req.openID = [dict objectForKey:@"appid"]; 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"]; // 調(diào)用微信支付 [WXApi sendReq:req]; } } //客戶端提示信息 - (void)alert:(NSString *)title msg:(NSString *)msg { UIAlertView *alter = [[UIAlertView alloc] initWithTitle:title message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alter show]; }
?
-
Xcode設(shè)置URL scheme
在Xcode中,選擇你的工程設(shè)置項(xiàng),選中“TARGETS”一欄,在“info”標(biāo)簽欄的“URL type“添加“URL scheme”為你所注冊的應(yīng)用程序id(如下圖所示)。
-
在你需要使用微信終端API的文件中import WXApi.h 頭文件,并增加 WXApiDelegate 協(xié)議。
// 微信所有的API接口 #import "WXApi.h" // APP端簽名相關(guān)頭文件 #import "payRequsestHandler.h" @interface AppDelegate ()<WXApiDelegate> @end
-
要使你的程序啟動后微信終端能響應(yīng)你的程序,必須在代碼中向微信終端注冊你的id。(如下圖所示,在 AppDelegate 的 didFinishLaunchingWithOptions 函數(shù)中向微信注冊id)。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. //向微信注冊 [WXApi registerApp:APP_ID withDescription:@"demo 2.0"]; return YES; }
重寫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)和微信終端交互的具體請求與回應(yīng),因此需要實(shí)現(xiàn)WXApiDelegate協(xié)議的兩個方法:
-(void) onReq:(BaseReq*)req { if([req isKindOfClass:[GetMessageFromWXReq class]]) { // 微信請求App提供內(nèi)容, 需要app提供內(nèi)容后使用sendRsp返回 NSString * strTitle = [NSString stringWithFormat:@"微信請求App提供內(nèi)容"]; NSString * strMsg = @"微信請求App提供內(nèi)容,App要調(diào)用sendResp:GetMessageFromWXResp返回給微信"; UIAlertView * alert = [[UIAlertView alloc] initWithTitle:strTitle message:strMsg delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; alert.tag = 1000; [alert show]; } else if([req isKindOfClass:[ShowMessageFromWXReq class]]) { ShowMessageFromWXReq * temp = (ShowMessageFromWXReq*)req; WXMediaMessage * msg = temp.message; //顯示微信傳過來的內(nèi)容 WXAppExtendObject * obj = msg.mediaObject; NSString * strTitle = [NSString stringWithFormat:@"微信請求App顯示內(nèi)容"]; NSString * strMsg = [NSString stringWithFormat:@"標(biāo)題:%@ \n內(nèi)容:%@ \n附帶信息:%@ \n縮略圖:%lu bytes\n\n", msg.title, msg.description, obj.extInfo, msg.thumbData.length]; UIAlertView * alert = [[UIAlertView alloc] initWithTitle:strTitle message:strMsg delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; } else if([req isKindOfClass:[LaunchFromWXReq class]]) { //從微信啟動App NSString * strTitle = [NSString stringWithFormat:@"從微信啟動"]; NSString * strMsg = @"這是從微信啟動的消息"; UIAlertView * alert = [[UIAlertView alloc] initWithTitle:strTitle message:strMsg delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; } }
onReq是微信終端向第三方程序發(fā)起請求,要求第三方程序響應(yīng)。第三方程序響應(yīng)完后必須調(diào)用sendRsp返回。在調(diào)用sendRsp返回時,會切回到微信終端程序界面。
-(void) onResp:(BaseResp*)resp { NSString * strMsg = [NSString stringWithFormat:@"errcode:%d", resp.errCode]; NSString * strTitle; if([resp isKindOfClass:[SendMessageToWXResp class]]) { strTitle = [NSString stringWithFormat:@"發(fā)送媒體消息結(jié)果"]; } if([resp isKindOfClass:[PayResp class]]){ //支付返回結(jié)果,實(shí)際支付結(jié)果需要去微信服務(wù)器端查詢 strTitle = [NSString stringWithFormat:@"支付結(jié)果"]; switch (resp.errCode) { case WXSuccess: strMsg = @"支付結(jié)果:成功!"; NSLog(@"支付成功-PaySuccess,retcode = %d", resp.errCode); break; default: strMsg = [NSString stringWithFormat:@"支付結(jié)果:失敗!retcode = %d, retstr = %@", resp.errCode,resp.errStr]; NSLog(@"錯誤,retcode = %d, retstr = %@", resp.errCode,resp.errStr); break; } } UIAlertView * alert = [[UIAlertView alloc] initWithTitle:strTitle message:strMsg delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; }
如果第三方程序向微信發(fā)送了sendReq的請求,那么onResp會被回調(diào)。sendReq請求調(diào)用后,會切到微信終端程序界面。
應(yīng)用內(nèi)購買(In-App Purchase)
在應(yīng)用程序內(nèi)購買虛擬商品。如果你在App Store上銷售的應(yīng)用程序,將收到支付金額的70%。
相關(guān)資料
支付流程
配置App ID
- 為應(yīng)用建立建立一個不帶通配符的App ID
- 用該App ID生成和安裝相應(yīng)的Provisioning Profile文件。
配置iTunes Connect
-
填寫相關(guān)的稅務(wù),銀行,聯(lián)系人信息
-
添加一個用于在sandbox付費(fèi)的測試用戶
用該App ID創(chuàng)建一個新的應(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 <StoreKit/StoreKit.h>
-
獲得所有的付費(fèi)Product ID列表。這個可以用常量存儲在本地,也可以由自己的服務(wù)器返回。
//在內(nèi)購項(xiàng)目中創(chuàng)建的商品單號 #define ProductID_IAP_FTHJ @"com.1000phone.IAPDemo.fthj_purple" // 方天畫戟 488元 #define ProductID_IAP_XYJ @"com.1000phone.IAPDemo.xyj" // 軒轅劍 6,498元 #define ProductID_IAP_JB @"com.1000phone.IAPDemo.jb" // 金幣 6元=6金幣
?
-
制作界面,展示所有的應(yīng)用內(nèi)付費(fèi)項(xiàng)目。這些應(yīng)用內(nèi)付費(fèi)項(xiàng)目的價(jià)格和介紹信息可以從App Store服務(wù)器請求,也可以是自己的服務(wù)器返回。向App Store查詢速度非常慢,通常需要2-3秒鐘,最好從服務(wù)器請求。
- (void)createViews { NSArray * buttonNames = @[@"軒轅劍 6498元", @"方天畫戟 488元", @"金幣6元=6金幣"]; __weak typeof(self) weakSelf = self; [buttonNames enumerateObjectsUsingBlock:^(NSString * buttonName, NSUInteger idx, BOOL * stop) { UIButton * button = [UIButton buttonWithType:UIButtonTypeSystem]; [weakSelf.view addSubview:button]; button.frame = CGRectMake(100, 100 + idx * 60, 150, 50); button.titleLabel.font = [UIFont systemFontOfSize:18]; [button setTitle:buttonName forState:UIControlStateNormal]; // 設(shè)置tag值 button.tag = PAY_BUTTON_BEGIN_TAG + idx; [button addTarget:self action:@selector(buyProduct:) forControlEvents:UIControlEventTouchUpInside]; }]; } - (void)buyProduct:(UIButton *) sender { }
?
-
當(dāng)用戶點(diǎn)擊了一個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步: [self requestProductData]; NSLog(@"允許程序內(nèi)付費(fèi)購買"); } else { NSLog(@"不允許程序內(nèi)付費(fèi)購買"); UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"您的手機(jī)沒有打開程序內(nèi)付費(fèi)購買" delegate:nil cancelButtonTitle:NSLocalizedString(@"關(guān)閉",nil) otherButtonTitles:nil]; [alerView show]; } }
-
我們先通過該IAP的ProductID向AppStore查詢,獲得SKPayment實(shí)例,然后通過SKPaymentQueue的 addPayment方法發(fā)起一個購買的操作。
// 下面的ProductId應(yīng)該是事先在itunesConnect中添加好的,已存在的付費(fèi)項(xiàng)目。否則查詢會失敗。 - (void)requestProductData { NSLog(@"---------請求對應(yīng)的產(chǎn)品信息------------"); NSArray *product = nil; switch (self.buyType) { case 0: product = [NSArray arrayWithObject:ProductID_IAP_XYJ]; break; case 1: product = [NSArray arrayWithObject:ProductID_IAP_FTHJ]; break; case 2: product = [NSArray arrayWithObject:ProductID_IAP_JB]; break; } NSSet *nsset = [NSSet setWithArray: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 UI for(SKProduct *product in myProduct){ 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ā)送購買請求------------"); [[SKPaymentQueue defaultQueue] addPayment:payment]; } //彈出錯誤信息 - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{ NSLog(@"-------彈出錯誤信息----------"); UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription] delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil]; [alerView show]; } -(void) requestDidFinish:(SKRequest *)request { NSLog(@"----------反饋信息結(jié)束--------------"); }
-
在viewDidLoad方法中,將購買頁面設(shè)置成購買的Observer。
- (void)viewDidLoad { [super viewDidLoad]; [self createViews]; // 監(jiān)聽購買結(jié)果 [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; } - (void)dealloc { [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; }
-
當(dāng)用戶購買的操作有結(jié)果時,就會觸發(fā)下面的回調(diào)函數(shù),相應(yīng)進(jìn)行處理即可。
#pragma mark - SKPaymentTransactionObserver // 處理交易結(jié)果 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { switch (transaction.transactionState) { case SKPaymentTransactionStatePurchased://交易完成 NSLog(@"transactionIdentifier = %@", transaction.transactionIdentifier); [self completeTransaction:transaction]; break; case SKPaymentTransactionStateFailed://交易失敗 [self failedTransaction:transaction]; break; case SKPaymentTransactionStateRestored://已經(jīng)購買過該商品 [self restoreTransaction:transaction]; break; case SKPaymentTransactionStatePurchasing: //商品添加進(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 { // 對于已購商品,處理恢復(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ù)重試。
參考鏈接
蘋果支付(? Pay)
蘋果支付是一種在應(yīng)用內(nèi)運(yùn)行的具有隱秘性和安全性非接觸式的支付方式。它允許觸摸付款,你可以用來購買實(shí)體商品和服務(wù)。
Apple 不會存儲或共享客戶的實(shí)際信用卡和借記卡卡號,因此商家和 App 開發(fā)者無需負(fù)責(zé)管理和保護(hù)實(shí)際的信用卡和借記卡卡號。


先決條件
除了使用 PassKit 框架實(shí)施 Apple Pay 之外,您還必須:
通過付款處理機(jī)構(gòu)或網(wǎng)關(guān)設(shè)置一個帳戶。
通過“證書、標(biāo)識符和描述文件”(“Certificates, Identifiers & Profiles”)注冊一個商家 ID。
生成一個 Apple Pay 證書,用于加密和解密付款令牌。
在您的 App 中包括一個 Apple Pay 授權(quán)。
遵循“應(yīng)用審核準(zhǔn)則”的第 29 節(jié)中列出的要求。
遵循《App 審核準(zhǔn)則》(“App Review Guidelines”)第 29 節(jié)中列出的要求。
參考資料
? Pay VS In-App Purchase
? Pay | In-App Purchase | |
---|---|---|
框架 | PassKit | StoreKit |
適用范圍 | 實(shí)體商品(如食品雜貨、服裝和電器)和服務(wù)(如俱樂部會員、酒店預(yù)訂和活動門票) | 銷售虛擬商品,如適用于您的 App 的優(yōu)質(zhì)內(nèi)容及訂閱數(shù)字內(nèi)容;程序內(nèi)的內(nèi)容和功能性;程序內(nèi)貨幣服務(wù);數(shù)碼訂閱 |
支付處理 | 自己的支付平臺處理付款 | 蘋果公司處理付款 |