1. 程式人生 > >IAP(In App Purchase)流程總結

IAP(In App Purchase)流程總結

在程式中新增Store功能
本章為新增購買功能的指導

詳細流程:

準備工作當然是新增StoreKit.framework了。
然後是具體的步驟:

1. 決定在程式內出售的商品的型別。
之前提到過,程式內可以出售的新feature型別是有限制的。 Store Kit不允許我們下載新的程式碼。 你的商品要麼可以通過當前的程式碼工作(bundle型別),要麼可以通過伺服器下載(當然,這裡下載的為資料檔案,程式碼是不可以的)。 如果要修改原始碼,就只能老實的升級了。

2. 通過iTunes Connect註冊商品
每次新增新商品的時候都需要執行這一步驟。 每個商品都需要一個唯一的商品標識。 App Store通過這個標識來查詢商品資訊並處理支付流程。 註冊商品標識的方法和註冊程式的方法類似。

要了解如何建立和註冊商品資訊,請參考“iTunes Connect Developer Guide”文件。

3. 檢測是否可以進行支付
使用者可以禁用在程式內部支付的功能。在傳送支付請求之前,程式應該檢查該功能是否被開啟。程式可在顯示商店介面之前就檢查該設定(沒啟用就不顯示商店介面了),也可以在使用者傳送支付請求前再檢查,這樣使用者就可以看到可購買的商品列表了。

例子:
if([SKPaymentQueue canMakePayments])
{
    ...//Display a store to the user
}
else
{
    ...//Warn the user that purchases are disabled.
}

4. 獲得商品的資訊
程式建立SKProductsRequest物件,用想要出售的商品的標識來初始化, 然後附加上對應的委託物件。 該請求的響應包含了可用商品的本地化資訊。

//這裡傳送請求
- (void)requestProductData
{
    SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:
    [NSSet setWithObject: kMyFeatureIdentifier]];
    
    request.delegate = self;
    [request start];
}

//這個是響應的delegate方法
- (void)productsRequest: (SKProductsRequest *)request
didReceiveResponse: (SKProductsResponse *)response
{
    NSArray *myProduct = response.products;

    //生成商店的UI
    [request autorelease];
}

5. 新增一個展示商品的介面
Store Kit不提供介面的類。 這個介面需要我們自己來設計並實現。

6. 為支付佇列(payment queue)註冊一個觀察者物件
你的程式需要初始化一個transaction observer物件並把它指定為payment queue的觀察者。

上程式碼:

MyStoreObserver *observer = [[MyStoreObserver alloc]init];
[[SKPaymentQueue defaultQueue]addTransactionObserver: observer];

應該在程式啟動的時候就新增好觀察者,原因前面說過,重啟後程序會繼續上次未完的交易,這時就新增觀察者物件就不會漏掉之前的交易資訊。

7. 在MyStoreObserver類中執行paymentQueue: updatedTransactions: 方法。
這個方法會在有新的交易被建立,或者交易被更新的時候被呼叫。

- (void)paymentQueue: (SKPaymentQueue *)queue updatedTransactions: (NSArray *)transactions
{
    for(SKPaymentTransaction * transaction in transactions)
    {
        switch(transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction: transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction: transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction: transaction];
            default:
                break;
        }
    }
}

上面的函式針對不同的交易返回狀態,呼叫對應的處理函式。

8. 觀察者物件在使用者成功購買一件商品時,提供相應的內容,以下是在交易成功後呼叫的方法
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
    //你的程式需要實現這兩個方法
    [self recordTransaction: transaction];
    [self provideContent: transaction.payment.productIdentifier];
    
    //將完成後的交易資訊移出佇列
    [[SKPaymentQueue defaultQueue]finishTransaction: transaction];
}

交易成功的資訊包含transactionIdentifier和transactionReceipt的屬性。其中,transactionReceipt記錄了支付的詳細資訊,這個資訊可以幫助你跟蹤、審(我們的)查交易,如果你的程式是用伺服器來交付內容,transactionReceipt可以被傳送到伺服器,然後通過App Store驗證交易。(之前提到的server模式,可以參考以前的圖)

9. 如果交易是恢復過來的(restore),我們用這個方法來處理:
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
    [self recordTransaction: transaction];
    [self provideContent: transaction.payment.productIdentifier];

    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
這個過程完成購買的過程類似。 恢復的購買內容提供一個新的交易資訊,這個資訊包含了新的transaction的標識和receipt資料。 如果需要的話,你可以把這些資訊單獨儲存下來,供追溯審(我們的)查之用。但更多的情況下,在交易完成時,你可能需要覆蓋原始的transaction資料,並使用其中的商品標識。

10. 交易過程失敗的話,我們呼叫如下的方法:
- (void)failedTransaction: (SKPaymentTransaction *)transaction
{
    if(transaction.error.code != SKErrorPaymentCancelled)
    {
        //在這類顯示除使用者取消之外的錯誤資訊
    }

    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

通常情況下,交易失敗的原因是取消購買商品的流程。 程式可以從error中讀出交易失敗的詳細資訊。

顯示錯誤資訊不是必須的,但在上面的處理方法中,需要將失敗的交易從支付佇列中移除。 一般來說,我們用一個對話方塊來顯示錯誤資訊,這時就應避免將使用者取消購買這個error顯示出來。

11. 組織好程式內“商店”的UI。當用戶選擇一件商品時, 建立一個支付物件,並放到佇列中。
SKPayment *payment = [SKPayment paymentWithProductIdentifier: kMyFeatureIdentifier];
[[SKPaymentQueue defaultQueue] addPayment: payment];

如果你的商店支援選擇同一件商品的數量,你可以設定支付物件的quantity屬性
SKMutablePayment *payment = [SKMutablePayment paymentWithProductIdentifier: kMyFeatureIdentifier];
payment.quantity = 3;
[[SKPaymentQueue defaultQueue] addPayment: payment];


下一步:
本章中所示程式碼可用於內建型商品模式(Built-in)。 如果你的程式要使用伺服器來發布商品,你需要負責設計和執行iPhone程式和你的伺服器之間的通訊。伺服器應該驗證資料併為程式提供內容。

驗證store的收據

使用伺服器來交付內容,我們還需要做些額外的工作來驗證從Store Kit傳送的收據資訊。

重要資訊:來自Store的收據資訊的格式是專用的。 你的程式不應直接解析這類資料。可使用如下的機制來取出其中的資訊。

驗證App Store返回的收據資訊
當交易完成時,Store Kit告知payment observer這個訊息,並返回完成的transaction。 SKPaymentTransaction的transactionReceipt屬性就包含了一個經過簽名的收據資訊,其中記錄了交易的關鍵資訊。你的伺服器要負責提交收據資訊來確定其有效性,並保證它未經過篡改。 這個過程中,資訊被以JSON資料格式傳送給App Store,App Store也以JSON的格式返回資料。
(大家可以先了解一下JSON的格式)

驗證收據的過程:

1. 從transaction的transactionReceipt屬性中得到收據的資料,並以base64方式編碼。
2. 建立JSON物件,字典格式,單鍵值對,鍵名為"receipt-data", 值為上一步編碼後的資料。效果為:
{
    "receipt-data"    : "(編碼後的資料)"
}

3. 傳送HTTP POST的請求,將資料傳送到App Store,其地址為:
https://buy.itunes.apple.com/verfyReceipt


4. App Store的返回值也是一個JSON格式的物件,包含兩個鍵值對, status和receipt:
{
    "status"    : 0,
    "receipt"    : { … }
}

如果status的值為0, 就說明該receipt為有效的。 否則就是無效的。

App Store的收據
傳送給App Store的收據資料是通過對transaction中對應的資訊編碼而建立的。 當App Store驗證收據時, 將從其中解碼出資料,並以"receipt"的鍵返回。 返回的響應資訊是JSON格式,被包含在SKPaymentTransaction的物件中(transactionReceipt屬性)。Server可通過這些值來了解交易的詳細資訊。 Apple建議只發送receipt資料到伺服器並使用receipt資料驗證和獲得交易詳情。 因為App Store可驗證收據資訊,返回資訊,保證資訊不被篡改,這種方式比同時提交receipt和transaction的資料要安全。(這段得再看看)

表5-1為交易資訊的所有鍵,很多的鍵都對應SKPaymentTransaction的屬性。
備註:一些鍵取決於你的程式是連結到App Store還是測試用的Sandbox環境。更多關於sandbox的資訊,請檢視"Testing a Store"一章。

Table 5-1 購買資訊的鍵:

鍵名        描述
quantity     購買商品的數量。對應SKPayment物件中的quantity屬性
product_id    商品的標識,對應SKPayment物件的productIdentifier屬性。
transaction_id        交易的標識,對應SKPaymentTransaction的transactionIdentifier屬性
purchase_date    交易的日期,對應SKPaymentTransaction的transactionDate屬性
original_-transaction_id    對於恢復的transaction物件,該鍵對應了原始的transaction標識
original_purchase_-date    對於恢復的transaction物件,該鍵對應了原始的交易日期
app_item_id    App Store用來標識程式的字串。一個伺服器可能需要支援多個server的支付功能,可以用這個標識來區分程式。連結sandbox用來測試的程式的不到這個值,因此該鍵不存在。
version_external_-identifier    用來標識程式修訂數。該鍵在sandbox環境下不存在
bid    iPhone程式的bundle標識
bvrs    iPhone程式的版本號

測試Store功能
開發過程中,我們需要測試支付功能以保證其工作正常。然而,我們不希望在測試時對使用者收費。 Apple提供了sandbox的環境供我們測試。

備註:Store Kit在模擬器上無法執行。 當在模擬器上執行Store Kit的時候,訪問payment queue的動作會打出一條警告的log。測試store功能必須在真機上進行。

Sandbox環境
使用Sandbox環境的話,Store Kit並沒有連結到真實的App Store,而是連結到專門的Sandbox環境。 SandBox的內容和App Store一致,只是它不執行真實的支付動作。 它會返回交易成功的資訊。 Sandbox使用專門的iTunes Connect測試 賬戶。不能使用正式的iTunes Connect賬戶來測試。

要測試程式,需要建立一個專門的測試賬戶。你至少需要為程式的每個區域建立至少一個測試賬戶。詳細資訊,請檢視iTunes Connect Developer Guide文件。

在Sandbox環境中測試
步驟:
1. 在測試的iPhone上退出iTunes賬戶
Settings中可能會記錄之前登入的賬戶,進入並退出。

重要資訊:不能在Settings 程式中通過測試賬戶登入。

2. 執行程式
當你在程式的store中購買商品後,Store kit提示你去驗證交易。用測試賬戶登入,並批准支付。 這樣虛擬的交易就完成了。

在Sandbox中驗證收據
驗證的URL不同了:
NSURL *sandboxStoreURL = [[NSURL alloc]initWithString: 
@"https://sandbox.itunes.apple.com/verifyReceipt"];