iOS內購(IAP)流程記錄(業務篇)
之前已經寫過內購前期準備資料的文章,這篇文章梳理下業務實現邏輯。
前期需求:公司是有自己的訂單系統,所以我們需要在發起支付的時候需要先去后臺獲取訂單號,拿到訂單號后再調用蘋果內購流程,最后把訂單號和支付憑證返回給后臺,由后臺去和蘋果再次校驗交易結果,最后返回訂單支付結果給我們。(這是正常流程,內購存在漏單,異常訂單稍后講)。
支付流程圖:
支付流程圖
了解流程之后,我們就開始編寫代碼了,我這邊是把內購的代碼封裝了一個單例
準備:
需導入庫:
StoreKit
頭文件需要引用:
#import <StoreKit/StoreKit.h>
代理添加:
<SKPaymentTransactionObserver,SKProductsRequestDelegate>
代碼實現:
1.先去拿到后臺訂單號,有了后臺訂單號之后再判斷是否有購買權限
[SKPaymentQueue canMakePayments]
2.如果有購買權限,則通過產品id去獲取內購項目信息
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
request.delegate = self;
[request start];
3.通過蘋果內購回調函數去處理
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
// 商品數組
NSArray *productArr = response.products;
if (productArr.count > 0) {
SKProduct *product = nil;
for (SKProduct *p in productArr) {
if ([p.productIdentifier isEqualToString:_productID]) {
product = p;
break;
}
}
// 發起內購
SKPayment *payMent = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payMent];
} else {
//項目id錯誤
}
}
4.判斷交易狀態:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
// 獲取結果
// 驗證成功與否都注銷交易,否則會出現虛假憑證信息一直驗證不通過,每次進程序都得輸入蘋果賬號
for (SKPaymentTransaction *trans in transactions) {
switch (trans.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(@"商品添加進列表");
break;
case SKPaymentTransactionStatePurchased:
NSLog(@"交易完成");
//自己可添加驗證
[self completeTransaction:trans];
[[SKPaymentQueue defaultQueue] finishTransaction:trans];
break;
case SKPaymentTransactionStateFailed:
NSLog(@"交易失敗");
[self failedTransaction:trans];//處理失敗邏輯
[[SKPaymentQueue defaultQueue] finishTransaction:trans];
break;
case SKPaymentTransactionStateRestored:
NSLog(@"已經購買過商品");
[[SKPaymentQueue defaultQueue] finishTransaction:trans]; //消耗型商品不用寫
break;
case SKPaymentTransactionStateDeferred:
break;
default:
break;
}
}
}
5.收到支付成功后把訂單號和交易憑證拋給后臺:
- (void) completeTransaction:(SKPaymentTransaction *)transaction{
//這里要把SKPaymentTransaction整個對象給后臺,記得攜帶訂單號,先驗證正式服務器,如果正式服務器返回21007再去蘋果測試服務器驗證,沙盒測試環境蘋果用的是測試服務器
//正式環境:https://buy.itunes.apple.com/verifyReceipt
//沙箱環境:https://sandbox.itunes.apple.com/verifyReceipt
}
整合好之后,拿到后臺返回的訂單號每次發起內購調用下面這個函數就可以了
- (void)startIAPWithProductID:(NSString *)productID andOrderNo:(NSString *)orderNo completeHandle: (IAPCompletionHandle)handle{
_handle = handle;
_orderNo = orderNo;
if(productID && productID.length > 0) {
if ([SKPaymentQueue canMakePayments]) {
// 允許內購
_productID = productID;
NSSet *set = [NSSet setWithObjects:productID, nil];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
request.delegate = self;
// 獲取內購項目信息
[request start];
} else {
// 不允許內購
}
} else {
NSLog(@"內購項目ID錯誤");
}
}
不出意外,正常流程就是這樣了,但是為了防止漏單的情況,所以增加了漏單機制。
異常訂單處理
我的處理邏輯是把蘋果返回成功但是后臺返回失敗的訂單存到異常隊列,每次啟動APP的時候把異常隊列輪詢一次,就是把訂單數據再發送給后臺,讓后臺再去校驗,如果校驗成功,則在隊列中移除異常訂單,后臺添加購買數據,更新訂單狀態。
//array是異常數組,包含訂單號、交易憑據
-(void)anomalyOrderVerify:(NSMutableArray * )array{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
for (int i = array.count; i > 0 ; i-- ) {
//循環判斷,通過信號量控制
dispatch_semaphore_signal(semaphore);
}
}
這只是一種異常訂單處理方法,還有其他的暫時沒有添加,網上大神這么多,我也在借鑒他們漏單處理的方式,后面也還會再完善這方面內容,畢竟涉及到支付。