1. 程式人生 > >OS——內購支付詳解程式碼部分(二)

OS——內購支付詳解程式碼部分(二)

一、程式碼及業務邏輯
  業務邏輯
    1.    獲取內購列表(從App內讀取或從自己伺服器讀取)
    2.    App Store請求可用的內購列表
    3.    向用戶展示內購列表
    4.    使用者選擇了內購列表,再發個購買請求,收到購買完成的回撥(購買完成後會把錢打給申請內購的銀行卡內)
    5.    購買流程結束後, 向伺服器發起驗證憑證以及支付結果的請求
    6.    自己的伺服器將支付結果資訊返回給前端併發放虛擬產品
    7.    服務端的工作比較簡單,分4步:
    1.    接收ios端發過來的購買憑證。
    2.    判斷憑證是否已經存在或驗證過,然後儲存該憑證。
    3.    將該憑證傳送到蘋果的伺服器驗證,並將驗證結果返回給客戶端。
    4.    如果需要,修改使用者相應的會員許可權。
    8.    考慮到網路異常情況,伺服器的驗證應該是一個可恢復的佇列,如果網路失敗了,應該進行重試。 簡單來說就是將該購買憑證用Base64編碼,然後POST給蘋果的驗證伺服器,蘋果將驗證結果以JSON形式返回。

程式碼如下 :
/*注意事項:
1.沙盒環境測試appStore內購流程的時候,請使用沒越獄的裝置。
2.請務必使用真機來測試,一切以真機為準。
3.專案的Bundle identifier需要與您申請AppID時填寫的bundleID一致,不然會無法請求到商品資訊。
4.如果是你自己的裝置上已經綁定了自己的AppleID賬號請先登出掉,否則你哭爹喊娘都不知道是怎麼回事。
5.訂單校驗 蘋果稽核app時,仍然在沙盒環境下測試,所以需要先進行正式環境驗證,如果發現是沙盒環境則轉到沙盒驗證。
識別沙盒環境訂單方法:
 1.根據欄位 environment = sandbox。
 2.根據驗證介面返回的狀態碼,如果status=21007,則表示當前為沙盒環境。
 蘋果反饋的狀態碼:
 21000App Store無法讀取你提供的JSON資料
 21002 訂單資料不符合格式
 21003 訂單無法被驗證
 21004 你提供的共享金鑰和賬戶的共享金鑰不一致
 21005 訂單伺服器當前不可用
 21006 訂單是有效的,但訂閱服務已經過期。當收到這個資訊時,解碼後的收據資訊也包含在返回內容中
 21007 訂單資訊是測試用(sandbox),但卻被髮送到產品環境中驗證
 21008 訂單資訊是產品環境中使用,但卻被髮送到測試環境中驗證
 */
 
#import <Foundation/Foundation.h>
 
typedef enum {
    SIAPPurchSuccess = 0,       // 購買成功
    SIAPPurchFailed = 1,        // 購買失敗
    SIAPPurchCancle = 2,        // 取消購買
    SIAPPurchVerFailed = 3,     // 訂單校驗失敗
    SIAPPurchVerSuccess = 4,    // 訂單校驗成功
    SIAPPurchNotArrow = 5,      // 不允許內購
}SIAPPurchType;
 
typedef void (^IAPCompletionHandle)(SIAPPurchType type,NSData *data);
 
 
@interface STRIAPManager : NSObject
+ (instancetype)shareSIAPManager;
//開始內購
- (void)startPurchWithID:(NSString *)purchID completeHandle:(IAPCompletionHandle)handle;
@end
.m
#import "STRIAPManager.h"
#import <StoreKit/StoreKit.h>
@interface STRIAPManager()<SKPaymentTransactionObserver,SKProductsRequestDelegate>{
   NSString           *_purchID;
   IAPCompletionHandle _handle;
}
@end
@implementation STRIAPManager
 
#pragma mark - ♻️life cycle
+ (instancetype)shareSIAPManager{
     
    static STRIAPManager *IAPManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
        IAPManager = [[STRIAPManager alloc] init];
    });
    return IAPManager;
}
- (instancetype)init{
    self = [super init];
    if (self) {
        // 購買監聽寫在程式入口,程式掛起時移除監聽,這樣如果有未完成的訂單將會自動執行並回調 paymentQueue:updatedTransactions:方法
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    }
    return self;
}
 
- (void)dealloc{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
 
 
#pragma mark -