In-App Purchase(iap)快速指南


 

 

點擊IOS IAP APP內支付 Java服務端代碼直接跳轉到示例點擊直接跳轉到示例

iap簡介

 
在應用中內嵌Store,在iOS應用中使用Store Kit framework來實現In-App Purchase。Store Kit會連接App Store,代替應用安全地完成用戶支付。Store Kit提示用戶授權支付,然后通知應用“用戶已經完成支付”,這樣應用就可以提供用戶購買的東西。
 
使用iap可以為應用的增強功能,或額外內容進行收費,如以下場景:
  • 基礎版本的應用,購買額外的特性
  • 書籍閱讀器應用,允許用戶購買和下載新的書籍
  • 游戲,提供新的環境(場景、關卡、等級等)
  • 在線游戲,允許玩家購買虛擬財產(金幣、道具、裝備等)
  • 數字雜志或newsletter訂閱

Products
 
可在iTunes Connect中定義,iap支持四種類型的product:
  • Content(內容):包括數字圖書、雜志、照片、封面、游戲等級、游戲角色、以及其它應用可交付的數字內容
  • Functionality(功能):解鎖或擴展應用當前已交付的特性。例如游戲中的多個小游戲,用戶可單獨購買
  • Service(服務):允許應用提供收費的一次性服務,每次使用服務都需要單獨購買
  • Subscription(訂閱):以擴展的方式,提供用戶對內容或服務的訪問。如應用提供每月財報或在線門戶網站訪問
所有的Product都必須先在App Store中通過iTunes Connect注冊,你需要提供一個唯一的product identifier,以及許多其它信息
應用使用Store Kit與App Store通信時;以及用戶購買后,應用處理這個購買並提供product,都使用這個ID進行標識
 
product還可以分為以下類型:
  • 消耗型,每次用戶需要該產品時都需要購買。一次性服務通常都是消耗型
  • 非消耗型,每個用戶只需要購買一次,一旦購買,用戶賬號相關聯的所有設備都可以使用。Store Kit提供內建的支持,可在多個設備中使用非消耗型產品
  • 自動再生訂閱,和非消耗型一樣遞送至用戶的所有設備。但是自動再生訂閱在iTunes Connect中需指定訂閱的持續時間。App Store在過期后自動更新該訂閱。如果用戶選擇不允許訂閱自動更新,在訂閱過期后將自動取消,用戶不能再訪問該產品。應用負責驗證某個訂閱當前是否有效,並且可以獲得最近交易的receipt
  • 免費訂閱,在Newsstand中提供免費訂閱。用戶一旦注冊了免費訂閱,賬號相關的所有設備都可以訪問該訂閱的內容。免費訂閱不會過期,而且只能在啟用Newsstand的應用中提供
  • 非自動再生訂閱,創建受限持續時間訂閱的舊機制,應使用自動再生訂閱代替該機制。與自動再生訂閱的區別有三點:
    • iTunes Connect中不指定訂閱協議,應用負責提供這個信息給用戶
    • 可以被購買多次,App Store不會自動更新該訂閱。應用負責實現訂閱更新,檢測過期,提示用戶重新購買。
    • 應用必須將非自動再生訂閱遞送至用戶的所有設備。Store Kit不會進行自動同步。

如何交付已購買的iap特性
 
應用需要設計和實現提供iap產品給用戶的交付機制。目前主要有兩種:內建模型、服務器模型。
在這兩種模型中,你都必須跟蹤Store中已提供的products列表,並交付給用戶使用。
 
 
內建模型
所有需要交付的products都已經包含在應用中。這個模型主要用於應用解鎖相關的功能。也可以使用這個模型來交付應用Bundle中已經提供的內容。
 
內建模型的主要優點是可以快速地交付products給用戶,多數內建型Products都應該是非消耗型的
 
應用可以在Application Bundle中存儲Product Identifier,從而標識出相應的iap product。蘋果推薦使用plist來記錄所有內建特性的product ID。基於內容的應用可以使用這個技術來增加新的內容,而不需要修改應用的代碼。
 
在用戶成功購買product之后,應用必須解鎖該特性,並且交付給用戶使用。解鎖特性最簡單的方法是修改應用參數。應用參數在用戶備份iOS設備時會自動備份,應用在用戶購買product之后可以考慮推薦用戶進行備份操作。
 
內建模型示意圖:
 
  1. 應用從Bundle中獲取product ID列表
  2. 應用向App Store發送請求,以獲取products的信息
  3. App Store返回Products信息
  4. 應用使用這些信息來顯示一個Store給用戶
  5. 用戶從顯示的Store中選擇一項
  6. 應用向App Store發送payment請求
  7. App Store處理這個payment,並返回一個完成的transaction
  8. 應用讀取transaction信息,並交付用戶已購買的內容
 
 
服務器模型
在服務器模型中,我們提供一個獨立的服務器,來交付Products給iOS應用。服務器交付適合於訂閱、服務、內容,因為這些Products可以按數據來交付,而不需要修改iOS應用bundle。游戲也可以使用服務器來交付新的游戲環境(謎題、等級、或關卡)。Store Kit不管你的服務器與iOS應用之間如何交互;Store Kit也不提供標識特定用戶的機制。你需要自己提供一個用戶機制,來標識你iOS應用的用戶(例如你提供訂閱服務,需要與用戶相關聯,就需要自己實現用戶機制)。
 
服務器模型示意圖:
 
  1. 應用發送請求到服務器,獲取所有的Products ID列表
  2. 服務器返回Products ID列表
  3. 應用發送請求至App Store,獲取Products的信息
  4. App Store返回Product信息
  5. 應用使用這些信息,向用戶顯示一個Store界面
  6. 用戶從Store中選擇一項
  7. 應用向App Store發送payment請求
  8. App Store處理該payment,並返回完成的transaction
  9. 應用從transaction中獲取receipt數據,並將其發送給服務器
  10. 服務器記錄receipt數據,並建立一個audit trail(審查跟蹤)
  11. 服務器發送receipt數據到App Store,以驗證是否合法的transaction
  12. App Store解析receipt數據,並返回receipt,以及驗證結果(是否合法)
  13. 服務器讀取返回的receipt數據,並確定哪個用戶已經完成購買
  14. 服務器交付已購買的內容至iOS應用
 
應用最好通過你的服務器來獲取Products標識,而不是直接存放在plist文件中。這樣可以增加新Products,而無需更新應用。
 
在服務器模型中,應用獲取transaction相關聯的簽名receipt,並且發送給服務器。服務器然后驗證該receipt並對其進行解碼,以確定需要向應用交付什么內容。
 
非消耗型products可以使用Store Kit內建的功能恢復,但是非自動再生訂閱必須由你的服務器來還原。你負責記錄非自動再生訂閱的信息,並且還原給用戶使用。消耗型Products也可以在服務器中記錄,例如允許用戶在多個設備上獲取服務的結果。

 
獲取Product信息
 
應用在顯示Store給用戶時,必須在界面上顯示App Store中獲取的信息。
 
 
向App Store發送請求
Store Kit提供通用的機制,向App Store發送請求。應用創建和初始化請求對象,指定一個delegate,就可以發起請求。App Store處理請求后,會異步地調用delegate來通知應用請求結果。如下圖所示:
 
 
SKRequest
SKRequest是一個抽象基類,用於向Store發送請求
 
SKRequestDelegate
SKRequestDelegate是一個protocol,應用實現該接口,來處理Store成功或失敗的結果
 
 
獲取Products的信息
應用使用Products請求來獲取本地化的product信息。應用創建一個請求,包含products ID字符串的列表。發起請求后,products ID會傳輸至App Store。App Store會返回你之前在iTunes Connect中注冊的本地化的products信息。應用使用這些信息來顯示Store
 
允許用戶購買products之前,必須先使用該product ID向App Store查詢詳細的信息,這樣才能確保product ID合法,而且在iTunes Connect中標記為可以銷售。
 
SKProductsRequest
SKProductsRequest對象使用一組product ID來創建,這些是你想要顯示給用戶的product列表
 
SKProductsRequestDelegate
SKProductsRequestDelegate協議需要應用來實現,用於獲取Store的響應信息。請求成功處理后,會異步地接收App Store的響應信息
 
SKProductsResponse
SKProductsResponse對象是返回的結果信息,請求列表中的每個合法的product ID都有一個相應的SKProduct對象;同時還包含Store不能識別的一組product ID列表。不能識別的原因有許多:ID拼寫錯誤、標記為不可銷售、iTunes Connect中的修改還沒有傳送到其它App Store服務器等
 
SKProduct
SKProduct對象提供你在App Store中注冊的product的詳細本地化信息

 
Purchase(購買)
 
當用戶准備好購買product時,應用請求App Store來完成支付。App Store會創建一個持久化的transaction,即使用戶退出和重新啟動應用,也會繼續地處理該支付交易。App Store將未決交易列表同步給應用,並且在任何交易狀態變化時,遞送更新信息給應用。
 
 
收集支付
應用創建一個payment對象,並將其添加到payment隊列中,如下圖所示:
 
 
payment添加到隊列中時,會創建一個持久化的交易來保存它。在payment處理完之后,交易會更新為收集支付之后的狀態信息。應用實現observer來接收交易更新信息。observer負責提供已購買內容給用戶,並且從payment隊列中移除該交易
 
SKPayment
使用payment對象來收集支付。payment對象包含一個product ID,以及一個可選的購買數量。你可以把同一個payment對象排隊多次,每排隊一次都將導致一次單獨的請求。
 
用戶可以在"設置"中禁用應用中購買。在排隊一個購買請求之前,應用需要首先確認payment能夠被處理,調用payment隊列的canMakePayments方法。
 
SKPaymentQueue
payment隊列用來與App Store通信。當payment添加到隊列中時,Store Kit傳輸這個請求到App Store。Store Kit會顯示對話框詢問用戶授權支付。完成的transaction會返回到應用的observer,以便應用處理。
 
SKPaymentTransaction
每個payment被添加到隊列時,都會創建一個相應的transaction。每個transaction都有一些屬性,允許應用確定該交易的狀態。當支付收集完成后,transaction對象還包含額外的交易成功詳細信息。
 
雖然應用可以從payment隊列中獲取未決交易的列表,更通用的做法是應用等待,直到payment隊列主動通知observer,並傳遞更新交易的列表。
 
SKPaymentTransactionObserver
應用的某個對象實現SKPaymentTransactionObserver協議,並把該對象添加為payment隊列的observer。observer的主要責任是檢查已完成的交易;遞送已經成功購買的product;然后將這些完成交易從payment隊列中移除。
 
應用應該在啟動時就關聯observer到payment隊列,而不是等到用戶試圖購買時才關聯。transaction在應用終止后並不會丟失,下次應用啟動時,Store Kit會繼續處理這些交易。在應用初始化階段添加observer,可確保所有交易都成功傳遞到應用。
 
 
還原交易
一旦交易處理完成,並從隊列中移除,應用通常不會再看到它。但是如果應用支持的product類型必須可還原,你就必須包含一個接口,允許用戶還原這些購買。這個接口允許用戶把已購買的product添加到其它設備,或者原始設備重置后,也需還原交易。
 
Store Kit提供內建的機制,用於還原非消耗型、自動再生訂閱、免費訂閱等product的交易。應用調用payment隊列的restoreCompletedTransactions方法,payment隊列就會發送一個請求到App Store來還原交易。而App Store則對所有之前已經完成的交易生成一個新的還原交易。還原交易對象的originalTransaction屬性保存了原始的交易。應用對還原交易進行處理,從中獲取原始交易,然后使用這個原始交易對象來解鎖用戶已購買的內容。在Store Kit還原了之前完成的交易時,會通知payment隊列的observer對象,並調用它的paymentQueueRestoreCompletedTransactionsFinished: 方法。
 
如果用戶試圖購買一個可還原的product(而不是使用你實現的還原接口),應用會接收到一個正常的交易,而不是可還原交易。但是用戶不需要再次為這個product支付。應用應該把這些交易當作原始交易一樣來處理。
 
非自動再生訂閱和可消耗型product不會被Store Kit自動還原。但是非自動再生訂閱又必須可還原,因此在購買這些product時,你必須在自己的服務器上記錄這些交易,並提供自己的機制來還原這些交易給用戶的所有設備。

 
應用中添加Store(內建模型)
 
首先確保項目鏈接了StoreKit.framework,應用中添加Store的詳細步驟如下:
 
1. 定義應用需要遞送的products。
Store Kit對products有一些限制,不允許應用對自己打補丁,或者下載額外的代碼。products要么已經在應用的現有代碼中,要么從遠程服務器下載數據文件來實現。如果應用增加特性需要修改現有代碼,必須發布一個新版本的應用。

2. 在iTunes Connect中為每個product注冊詳細信息
每次應用Store要增加一個新的product,都需要先在iTunes Connect中進行注冊。每個product都需要一個唯一的ID字符串。App Store使用這個字符串來查找product信息以及處理支付請求。product ID特定於iTunes Connect賬號,注冊的方式與注冊應用類似。

3. 確定系統能夠處理支付
用戶可以禁止應用內購買,因此你的應用需要先檢查當前是否支持應用內購買。應用可以在顯示Store給用戶之前,或者在實際發起購買請求之前,進行這項檢查。后者允許用戶查看能夠購買的products,即使應用內購買當前被禁止。
 
if ([SKPaymentQueue canMakePayments])
{
   ... // 向用戶顯示Store
}
else
{
   ... // 警告用戶當前禁止應用內購買
}

4. 獲取products的信息
應用創建一個SKProductsRequest對象,並初始化為一組你想要銷售的product ID,添加一個delegate處理請求返回結果,然后就可以發起這個請求。響應結果保存了所有合法的products的本地化信息。應用必須首先獲得product的信息,然后才能創建payment請求。
 
- (void) requestProductData
{
   SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject: kMyFeatureIdentifier]];
   request.delegate = self;
   [request start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray *myProduct = response.products;
    // 把信息顯示到Store界面
    [request autorelease];
}

5. 增加一個用戶界面,顯示products給用戶
Store Kit不提供用戶界面類,如何顯示Store給用戶是應用的事情。

6. 注冊一個transaction observer到payment隊列
應用實例化一個transaction observer,並將其注冊到payment隊列。
 
MyStoreObserver *observer = [[MyStoreObserver alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
 
如前所述,應用最好在啟動時注冊observer。交易完成之前應用退出,App Store也仍然記得這些交易。啟動時注冊observer確保所有之前排隊交易的結果都能夠被應用接收到。

7. 在應用的MyStoreObserver對象中實現paymentQueue:updatedTransactions: 方法
observer的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. observer在用戶成功購買后提供相應的product
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
// 應用需要實現這兩個方法:記錄交易、提供內容
    [self recordTransaction: transaction];
    [self provideContent: transaction.payment.productIdentifier];
// 從payment隊列中刪除交易
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
 
成功的交易包含一個transactionIdentifier屬性和一個transactionReceipt屬性,記錄了已處理支付的詳細信息。應用不需要對這些信息做任何處理。當然你可能希望記錄這些信息並為交易建立一個審查跟蹤(audit trail)。如果使用服務器來遞送內容,應用可以把receipt發送到服務器,然后由服務器向App Store驗證該交易。
 
一旦你完成交付product給用戶,應用必須調用finishTransaction: 來完成交易,交易將從payment隊列中移除。為了確保products不會丟失,應用應該在調用finishTransaction: 之前交付內容。

9. 處理還原購買,結束交易
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
    [self recordTransaction: transaction];
    [self provideContent: transaction.originalTransaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
這個方法類似於上面的購買。還原購買是一個新的交易,擁有不同的transaction ID和receipt。你可以單獨保存這些信息,並建立審查跟蹤。但是當完成交易時,你還是要還原原始的交易,那里面保存了實際的payment對象和product ID。

10. 處理失敗購買,結束交易
- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        // 可以顯示一個錯誤(可選的)
    }
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
通常交易失敗都是用戶決定不購買。應用可以讀取失敗交易的error域,從而了解為何交易失敗。
對於失敗的交易,應用唯一需要做的是從隊列中移除它。如果應用在交易失敗后顯示一個對話框告訴用戶交易出錯,應該避免在用戶主動取消時也顯示該錯誤。

11. 做完上面所有以后,你就可以顯示用戶界面。當用戶在Store中選擇一項時,應用就創建一個payment對象,並將其添加到payment隊列中。

SKPayment *payment = [SKPayment paymentWithProductIdentifier:kMyFeatureIdentifier];
[[SKPaymentQueue defaultQueue] addPayment:payment];
 
如果Store提供一次購買多個product的功能,你可以創建一個payment對象,並指定quantity屬性
SKMutablePayment *payment = [SKMutablePayment paymentWithProductIdentifier:kMyFeatureIdentifier];
payment.quantity = 3;
[[SKPaymentQueue defaultQueue] addPayment:payment];
 
 
以上的代碼示例主要用於內建product模型。如果你的應用使用服務器來交付內容,你需要設計和實現iOS應用與服務器之間通信的協議。你的服務器還需要在交付products給應用之前,先驗證receipts。

 
驗證Store receipt
 
應該接收到Apple Store Kit的receipt后,應該執行額外的receipt檢查,來驗證交易的合法性。如果應用依賴於獨立的服務器來提供訂閱、服務、可下載內容,驗證receipt就非常重要。服務器驗證receipt可確保iOS應用向服務器的請求是合法的。
 
Store receipt的內容和格式是私有的,並且有可能變化。應用不能試圖直接解析receipt數據。使用下面描述的機制來驗證receipt,並獲得receipt中存儲的信息。
 
向App Store驗證一個Receipt
當Store Kit返回一個完成的購買到payment隊列的observer時,交易的transactionReceipt屬性包含一個簽名的receipt,記錄了所有關鍵的交易信息。服務器可以post這個receipt到App Store,來驗證receipt是合法的,沒有被篡改。向App Store查詢使用JSON dictionary直接發送和接收,由RFC 4627定義。
 
執行以下步驟,來驗證receipt:
1. 從transaction的transactionReceipt屬性獲取receipt數據,並使用Base64對其進行編碼
2. 創建一個JSON對象,只有一個名為"receipt-data"的鍵,它的值是步驟1創建的字符串。JSON對象如下:
{
    "receipt-data" : "(actual receipt bytes here)"
}
3. 使用HTTP POST請求,Post這個JSON對象到App Store,URL為:https://buy.itunes.apple.com/verifyReceipt
4. 從App Store接收到的響應也是一個JSON對象,有兩個鍵:status和receipt。如下所示:
{
    "status" : 0,
    "receipt" : { ... }
}
如果status的值為0,表示是一個合法的receipt。否則receipt非法。
 
 
Store Receipt
你發送給App Store的receipt數據編碼了交易的信息。當App Store驗證receipt時,會先解碼receipt數據,並在響應中返回。receipt響應是一個JSON dictionary,包含了應用中SKPaymentTransaction對象的所有信息。因此服務器可以查詢這些JSON域,來獲取用戶購買的詳細信息。蘋果推薦iOS應用只發送receipt數據給服務器,不發送交易數據給服務器,然后服務器再到App Store去驗證receipt。App Store會驗證receipt數據沒有被篡改。服務器從App Store響應的receipt數據中獲取交易信息,而不是由iOS應用直接發送交易信息給服務器,會更加安全。
 
下表列出了你可以從響應receipt中獲取的信息,許多鍵直接對應於SKPaymentTransaction類的屬性。表中沒有指定的鍵都被蘋果保留,不得使用。
描述
quantity 購買的數量,對應於transaction.payment.quantity屬性
product_id product ID標識,對應於transaction.payment.productIdentifier屬性
transaction_id transaction ID標識,對應於transaction.transactionIdentifier屬性
purchase_date 交易發生的日期和時間,對應於transaction.transactionDate屬性
original_transaction_id 對於還原交易,這個值保存了原始交易ID
original_purchase_date 對於還原交易,這個值保存了原始交易日期
app_item_id 字符串,App Store用來唯一地標識一個創建了支付交易的iOS應用。如果你的服務器支持多個iOS應用,你可以使用這個值來區分不同的應用。在sandbox中運行的應用沒有app_item_id,因此這個鍵也不存在
version_external_identifier 唯一標識你的應用修訂版本的任意數值。sandbox應用沒有這個鍵
bid iOS應用的Bundle ID
bvrs iOS應用的版本號
 

 
測試Store
 
在開發過程中,你需要測試應用Store來確保正常工作。但是又不能進行實際的用戶支付,因此需要使用蘋果提供的sandbox Store測試。Store Kit不能在iOS模擬器中使用,測試Store必須在真機上進行。
 
Sandbox環境
從Xcode啟動應用時,Store Kit不會連接到App Store。相反會連接到特殊的Sandbox Store環境。Sandbox環境使用了App Store的基礎架構,但是不會發生實際的支付。Sandbox環境返回成功的支付,就好像實際上購買了一樣。Sandbox環境使用特殊的iTunes Connect賬號,只能用於測試In-App Purchase。不能使用普通的iTunes Connect賬號在Sandbox中測試。
 
你需要在iTunes Connect中創建一個或多個特殊的測試賬號,至少每個本地化區域需要一個單獨的測試賬號。詳細的信息可參考iTunes Connect Developer Guide.
 
Testing in the Sandbox
按以下步驟,在Sandbox中進行測試:
1. 在測試的iOS設備中退出當前iTunes賬號
在測試應用之前,必須首先退出普通的iTunes賬號。iOS 3.0在設置程序中包含了一個Store類別,你可以在里面退出當前賬號
切記:不要在設置中登錄你的測試賬號,否則測試賬號將失效
 
2. 運行你的應用
一旦你退出了普通賬號,就可以在Xcode中運行你的應用。在應用中提交支付時,Store Kit會提示你授權交易。使用測試賬號登錄並同意支付。這時候不會發生扣款,但是交易會正常完成。
 
在Sandbox中驗證Receipts
你也可以在Sandbox中驗證receipt,執行驗證的代碼和普通App Store是一樣的,但是Sandbox環境的URL不一樣:
NSURL *sandboxStoreURL = [[NSURL alloc] initWithString: @"https://sandbox.itunes.apple.com/verifyReceipt"];

Auto-Renewable訂閱
 
In-App Purchase提供標准化的方式,來實現自動再生訂閱。自動再生訂閱擁有以下特性:
1. 在iTunes Connect中配置自動再生訂閱時,需要指定訂閱的持續時間,以及其它選項。
2. Auto-renewable訂閱會自動還原,而且和非消耗型product一樣,都使用相同的Store Kit函數。原始交易,和每次的再生交易都會發送到應用。
3. 服務器向App Store驗證receipt時,如果訂閱活躍,並且被App Store自動再生過,App Store會返回一個更新的receipt
 
添加自動再生訂閱到Store
按以下步驟實現auto-renewable訂閱:
1. 連接到iTunes Connect,並創建一個新的"shared secret"。shared secret是一個密碼,服務器在驗證auto-renewable訂閱的receipt時必須提供此密碼。這樣在與App Store之間就增加了一層額外的安全保護。
2. 在iTunes Connect中新增並配置一項新的auto-renewable訂閱類型
3. 修改服務器的receipt驗證代碼,在發送到App Store的receipt JSON數據中增加shared secret。服務器的驗證代碼必須解析App Store的響應數據,以確定訂閱是否過期。如果訂閱被用戶更新,App Store會返回最新的receipt給你的服務器。
 
設計你的iOS客戶端應用
多數情況下,iOS應用只需要很小的修改,就能支持auto-renewable訂閱。實際上,客戶端應用現在變得更加簡單,因為你可以使用相同的代碼還原auto-renewable訂閱,做法和還原非消耗型product一樣:應用在訂閱更新時,會接收到獨立的transaction,應用只需單獨驗證每個receipt即可。
 
驗證Auto-renewable訂閱Receipt
和前面驗證Store Receipts幾乎相同。創建JSON對象,並POST到App Store。唯一的區別是增加第二個域:shared secret,也就是你在iTunes Connect創建的那個
shared secret的具體位置:
進入iTunes- 應用 - manage In-App Purchases - 點擊下方的 View or generate a shared secret
 
 
{
    "receipt-data" : "(actual receipt bytes here)"
    "password"     : "(shared secret bytes here)"
}
響應包含一個status域,表示receipt是否通過驗證
{
    "status" : 0,
    "receipt" : { ... }
    "latest_receipt" : "(base-64 encoded receipt)"
    "latest_receipt_info" : { ... }
}
 
如果用戶的receipt合法,而且是活躍的訂閱,status域為0,receipt域包含解碼后的receipt數據。如果服務器接收到的status為非0值,可對應以下錯誤代碼,來解析相應的錯誤。
Status 描述
21000 App Store不能讀取你提供的JSON對象
21002 receipt-data域的數據有問題
21003 receipt無法通過驗證
21004 提供的shared secret不匹配你賬號中的shared secret
21005 receipt服務器當前不可用
21006 receipt合法,但是訂閱已過期。服務器接收到這個狀態碼時,receipt數據仍然會解碼並一起發送
21007 receipt是Sandbox receipt,但卻發送至生產系統的驗證服務
21008 receipt是生產receipt,但卻發送至Sandbox環境的驗證服務
 
注意:這里的狀態碼只能用於Auto-renewable訂閱,其它類型的product不能使用這些狀態碼進行判斷
 
App Store返回給你的服務器的JSON對象的receipt數據中,除了前面說過的幾個鍵,增加或修改了以下幾個鍵:
描述
expires_date 訂閱receipt的過期日期,GMT至今的秒數,還原交易時不包含這個鍵
original_transaction_id 最初購買時的transaction ID,隨后的訂閱更新和還原都共享這個ID
original_purchase_date 最初購買的日期,表示訂閱的起始日期
purchase_date 交易支付發生的日期,對於renewable訂閱,這也可能是最近一次訂閱更新的日期。
 
另外JSON還包含兩個額外的域:latest_receipt、latest_expired_receipt_info,這兩個都是receipt對象,你的服務器可以使用這兩個域來記錄最近的訂閱更新。
 
還原Auto-Renewable訂閱
App Store在每次更新訂閱時都會創建獨立的transaction。你的應用還原之前的購買時,Store Kit會把所有transaction都傳遞給應用。因此應用需要組合每個transaction的購買日期與訂閱長度,然后確定該receipt是否合法。

 
 
上面內容基本來自iOS Developer Library的《In-App Purchase Programming Guide》
 
這里再附上一篇CocoaChina論壇版主lvyile寫的《關於IAP防止破解的幾點》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM