一、介紹:
在個人開發的app上架到AppStore后,蘋果官方允許我們將自己的app在appstore上進行付費使用,也就是所謂的內購。其中,支付方式規定的必須是蘋果的支付方式:應用內支付。
二、流程:
1、后台設置
(1)配置Developer.apple.com,為應用建立一個不帶通配符的App ID
(2)用該應用的App ID生成和安裝相應的Provisioning Profile文件
2、配置iTunes Connect
(1)用該App ID創建一個新的應用;
(2)在該應用中,創建應用內付費項目,選擇付費類型,通常可選的是可重復消費的(Consumenable)和永久有效的(Non-Consumenable)兩種,然后設置好價格、Product ID、購買介紹和截圖,這里的Product ID是必須記住的,后面開發的時候要用到;
(3)添加一個用於在sandbox付費的測試用戶,注意蘋果對測試用戶的密碼要求和正是賬號一樣,至少8位,並且包包含數字和大小寫字母;
(4)填寫相關的稅務。銀行和聯系人
3、iOS端開發
(1)在工程中引入storeKit.framework和#import <storeKit/storeKit.h>;
(2)獲取所有的付費Product ID列表。這個可以用常量存儲到本地,也可以由自己的服務器返回;
(3)制作一個界面(如tableView),顯示所有的應用內付費項目。這些應用內付費項目的價格和介紹信息可以是自己的服務器返回。但如果是不帶服務器的單機游戲應用或者工具類應用,則可以通過向App Store查詢所得;
(4)當用戶點擊一個IAP項目,我們需要先查詢用戶是否允許應用內付費,如果不允許則不進行接下來的步驟;
(5)先通過該IAP的ProductID向AppStore查詢,獲取SKPayment實例,然后通過SKPaymentQueue的addPayment方法發起一個購買的操作;
(6)在ViewdidLoad方法中,將購買頁面設置成購買額observe;
(7)當用戶購買的操作有結果時,就會觸發調用回調函數,相應的進行處理;
(8)服務器驗證憑證(可選項)。如果購買成功,我們需要將憑證發送到服務器上進行驗證。考慮到網路異常情況,iOS端的發送憑證操作應該可以持久化,如果程序退出、崩潰或者網絡異常,可以恢復重試。
4、服務端開發
(1)接收iOS端發過來的購買憑證;
(2)判斷憑證是否已經存在,是否驗證過,然后進行存儲;
(3)將該憑證發送到蘋果的服務器驗證,並將結果返回給客戶端;
(4)如果需要,修改用戶相應的會員權限。
注意:考慮到網絡異常的情況,服務器的驗證應該是一個可恢復的隊列,如果失敗了,應該進行重試。
蘋果AppStore線上的購買憑證驗證地址:https://buy.itunes.apple.com/verifyreceipt
測試的驗證地址:https://sandbox.itunes.apple.com/verifyreceipt
三、iOS基本代碼如下:
// ViewController.m // // Created by 夏遠全 on 16/11/20. // Copyright © 2016年 廣州市東德網絡科技有限公司. All rights reserved. // #import "ViewController.h" #import <StoreKit/StoreKit.h> @interface ViewController ()<SKProductsRequestDelegate,SKPaymentTransactionObserver> @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //監聽購買結果 [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; } -(void)dealloc{ //移除購買監聽 [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; } //用戶點擊一個IAP項目時,首先查詢用戶是否允許應用內付費(tableViewCell點擊時,傳遞內購商品ProductId,ProductID可以提前存儲到本地,用到時直接獲取即可) -(void)validateIsCanBought{ if ([SKPaymentQueue canMakePayments]) { [self getProductInfo:@[@"ProductIds"]]; }else{ NSLog(@"失敗,用戶禁止應用內付費購買"); } } //通過該IAP的Product ID向App Store查詢,獲取SKPayment實例,接着通過SKPaymentQueue的addPayment方法發起一個購買的操作 //下面的ProductId應該是事先在itunesConnect中添加好的,已存在的付費項目,否則會查詢失敗 -(void)getProductInfo:(NSArray *)productIds{ NSSet *set = [NSSet setWithArray:productIds]; SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set]; request.delegate = self; [request start]; } #pragma mark - SKProductsRequestDelegate //查詢的回調函數 -(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{ //獲取到的所有內購商品 NSArray *myProducts = response.products; //判斷個數 if (myProducts.count==0) { NSLog(@"無法獲取產品信息,購買失敗。"); return; } //發起一個購買操作 SKPayment *payment = [SKPayment paymentWithProduct:myProducts[0]]; [[SKPaymentQueue defaultQueue] addPayment:payment]; } #pragma mark - SKPaymentTransactionObserver //當用戶購買的操作有結果時,就會觸發下面的回調函數,相應進行處理 -(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)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: //已經購買過該商品 [self restoreTransaction:transaction]; break; case SKPaymentTransactionStatePurchasing: //商品添加進列表 NSLog(@"商品添加進列表"); break; default: break; } } } //交易完成后的操作 -(void)completeTransaction:(SKPaymentTransaction *)transaction{ NSString *productIdentifier = transaction.payment.productIdentifier; NSData *transactionReceiptData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]]; NSString *receipt = [transactionReceiptData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; if ([productIdentifier length]>0) { //向自己的服務器驗證購買憑證 NSLog(@"%@",receipt); } //移除transaction購買操作 [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; } //交易失敗后的操作 -(void)failedTransaction:(SKPaymentTransaction *)transaction{ if (transaction.error.code != SKErrorPaymentCancelled) { NSLog(@"購買失敗"); }else{ NSLog(@"用戶取消交易"); } //移除transaction購買操作 [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; } //已經購買過該商品 -(void)restoreTransaction:(SKPaymentTransaction *)transaction{ //對於已購買商品,處理恢復購買的邏輯 //移除transaction購買操作 [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; } @end
三、個人參考demo
https://github.com/xiayuanquan/AppleStoreKitDemo.git
效果圖:
打印日志:
2017-02-28 18:21:08.009166 StoreKit[18455:370113] [MC] Reading from private effective user settings. 2017-02-28 18:21:08.012 StoreKit[18455:370113] ---------請求對應的產品信息------------ 2017-02-28 18:21:08.015 StoreKit[18455:370113] 允許程序內付費購買 2017-02-28 18:21:09.193 StoreKit[18455:370113] -----------收到產品反饋信息-------------- 2017-02-28 18:21:09.193 StoreKit[18455:370113] 產品Product ID:( ) 2017-02-28 18:21:09.194 StoreKit[18455:370113] 產品付費數量: 1 2017-02-28 18:21:09.194 StoreKit[18455:370113] product info 2017-02-28 18:21:09.194 StoreKit[18455:370113] SKProduct 描述信息<SKProduct: 0x600000004950> 2017-02-28 18:21:09.194 StoreKit[18455:370113] 產品標題 1元=10金幣 2017-02-28 18:21:09.195 StoreKit[18455:370113] 產品描述信息: 通過虛擬金幣充值,獲取會員資格 2017-02-28 18:21:09.195 StoreKit[18455:370113] 價格: 0.99 2017-02-28 18:21:09.195 StoreKit[18455:370113] Product id: www.biaojiepay.com.StoreKit01 2017-02-28 18:21:09.195 StoreKit[18455:370113] ---------發送購買請求------------ 2017-02-28 18:21:09.196 StoreKit[18455:370113] -----paymentQueue-------- 2017-02-28 18:21:09.196 StoreKit[18455:370113] -----商品添加進列表 -------- 2017-02-28 18:21:09.196 StoreKit[18455:370113] ----------反饋信息結束-------------- 2017-02-28 18:21:10.125470 StoreKit[18455:370288] subsystem: com.apple.BackBoardServices.fence, category: Observer, enable_level: 1, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 0, privacy_setting: 0, enable_private_data: 0 2017-02-28 18:21:10.127183 StoreKit[18455:370113] subsystem: com.apple.BackBoardServices.fence, category: Workspace, enable_level: 1, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 0, privacy_setting: 0, enable_private_data: 0 2017-02-28 18:21:10.127707 StoreKit[18455:370113] subsystem: com.apple.BackBoardServices.fence, category: Trace, enable_level: 1, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 0, privacy_setting: 0, enable_private_data: 0 2017-02-28 18:21:12.044 StoreKit[18455:370113] -----paymentQueue-------- 2017-02-28 18:21:12.045 StoreKit[18455:370113] 失敗 2017-02-28 18:21:12.048 StoreKit[18455:370113] -----交易失敗 --------