【引用】IAP超級詳解,偷懶了,不用自己去翻譯了
本文轉載自papa_ln《IAP超級詳解,偷懶了,不用自己去翻譯了》
一、In App Purchase概覽
Store Kit代表App和App Store之間進行通信。程式將從App Store接收那些你想要提供的產品的資訊,並將它們顯示出來供使用者購買。
當使用者需要購買某件產品時,程式調用StoreKit來收集購買資訊。
Store Kit的API只是為程式添加In App Purchase功能的一小部分。你需要決定如何去記錄那些你想要提交的產品,如何在程式中將商店功能展現給使用者,
還要考慮如何將使用者購買的產品提交。本章的剩餘部分會展示整個流程。
Products
產品可以是任意一項你想要出售的特性。產品在iTunes Connect中被組織,這和你添加一個新的App是一樣的。支援的產品種類共有四種:
1. 內容型。包括電子書,電子雜誌,照片,插圖,遊戲關卡,遊戲角色,和其他的數位內容。
2. 擴展功能。這些功能已經包含在App內部。在未購買之前被鎖定。例如,你可以在一個遊戲程式中包含若干個小遊戲,使用者可以分別來購買這些遊戲。
3. 服務。允許程式對單次服務收費。比如錄音服務。
4. 訂閱。支援對內容或服務的擴展訪問。例如,你的程式可以每週提供財務資訊或遊戲入口網站的資訊。應該設定一個合理的更新週期,以避免過於頻繁的
提示困擾使用者。要記住:你將負責跟蹤訂閱的過期資訊,並且管理續費。App Store不會替你監視訂閱的週期,也不提供自動收費的機制。
In App Purchase為創建產品提供了一種通用的機制,如何操作將由你負責。當你設計程式的時候,有以下幾點需要注意:
1. 你必須提供電子類產品和服務。不要使用In App Purchase 去出售實物和實際服務。
2. 不能提供代表仲介貨幣的物品,因為讓使用者知曉他們購買的商品和服務是很重要的。
Store Kit代表App和App Store之間進行通信。程式將從App Store接收那些你想要提供的產品的資訊,並將它們顯示出來供使用者購買。
當使用者需要購買某件產品時,程式調用StoreKit來收集購買資訊。
Store Kit的API只是為程式添加In App Purchase功能的一小部分。你需要決定如何去記錄那些你想要提交的產品,如何在程式中將商店功能展現給使用者,
還要考慮如何將使用者購買的產品提交。本章的剩餘部分會展示整個流程。
Products
產品可以是任意一項你想要出售的特性。產品在iTunes Connect中被組織,這和你添加一個新的App是一樣的。支援的產品種類共有四種:
1. 內容型。包括電子書,電子雜誌,照片,插圖,遊戲關卡,遊戲角色,和其他的數位內容。
2. 擴展功能。這些功能已經包含在App內部。在未購買之前被鎖定。例如,你可以在一個遊戲程式中包含若干個小遊戲,使用者可以分別來購買這些遊戲。
3. 服務。允許程式對單次服務收費。比如錄音服務。
4. 訂閱。支援對內容或服務的擴展訪問。例如,你的程式可以每週提供財務資訊或遊戲入口網站的資訊。應該設定一個合理的更新週期,以避免過於頻繁的
提示困擾使用者。要記住:你將負責跟蹤訂閱的過期資訊,並且管理續費。App Store不會替你監視訂閱的週期,也不提供自動收費的機制。
In App Purchase為創建產品提供了一種通用的機制,如何操作將由你負責。當你設計程式的時候,有以下幾點需要注意:
1. 你必須提供電子類產品和服務。不要使用In App Purchase 去出售實物和實際服務。
2. 不能提供代表仲介貨幣的物品,因為讓使用者知曉他們購買的商品和服務是很重要的。
通過App Store註冊產品
每個你想要出售的產品都必須先通過iTunes Connect在App Store註冊。你需提供產品的名稱,描述,價格和其他在程式中用到的中繼資料。
需為產品指定唯一的識別碼。當你的程式利用Store Kit和App Store通信時,會使用產品標識來取回產品的資訊。如果使用者購買某個商品時,程式可以用該標識來將產品標注為「已購買」。
App Store將前面提到過的產品種類簡化為以下三種:
1. 消耗性商品。 該類商品在需要時被單次購買。比如,單次服務。
2. 非消耗性商品。 該類商品只需被某個使用者購買一次,一旦被購買,和該使用者iTunes 帳戶關聯的設備都可以使用此商品。Store Kit為在多個設備上重新存儲非消耗性商品提供了內置的支援。
3. 訂閱類。訂閱類商品擁有以上兩種類型的特性。和消耗性商品一樣,訂閱類商品可以被多次購買; 你可以在程式內部加入自己的訂閱計畫更新機制。 另外,訂閱類商品必須提供給和某一使用者關聯的所有設備。In App Purchase期望訂閱類商品可以通過外部伺服器交付。你必須為多個設備的訂閱服務提供相應的支援。
關於註冊產品的詳細資訊,請參考iTunes Connect Developer Guide文檔。
交付方式
交付機制在程式In App Purchase的設計和實現種有很重要的意義。有兩種基本的模型可以用來交付產品:內置類型(Built-in model)和伺服器類型(Server model)。 不管使用那種模型,你都需要維護產品清單,並保證當使用者購買後,成功的交付產品。
1. 內置產品類型
使用這種模型。 需要交付的產品已經在程式內部。 這種方式通常用在一些被鎖定的功能上。 也可以用來交付在程式束(App Bundle)中的內容。 該方式的一個重要的優點是你可以及時的給客戶交付產品,大多數的內置產品應為非消耗性商品。
注意:In App Purchase不提供購買補丁的功能。 如果需要更改app的bundle,你必須向App Store提交新的app版本。
為了標識產品,程式要在bundle中存儲產品的識別碼。內置模式下,Apple建議使用plist來紀錄產品的識別碼。 內容類別應用可以使用折衷方式很方便的添加新的內容,而不改動程式本身。(原話為: Content-driven applications can use this to add new content without modifying the source for your application,不是很懂,感覺應該是說類似是用plist來管理產品清單,因此就不需要在添加新產品的時候改動程式了。再議。。。)
當成功購買產品後,程式應將鎖定的功能解鎖,提供給使用者。 解鎖的最簡單方式是修改程式偏好設置(Application Preferences)。 當使用者備份手機資料的時候,程式偏好設置也會隨之備份。 程式可能需要建議使用者在購買產品後備份手機以免丟失購買的內容。
圖1-2顯示了交付內置型產品的流程。
1. 程式通過bundle存儲的plist檔得到產品識別碼的清單。
2. 程式向App Store發送請求,得到產品的資訊。
3. App Store返回產品資訊。
4. 程式把返回的產品資訊顯示給使用者(App的store介面)
5. 使用者選擇某個產品
6. 程式向App Store發送支付請求
7. App Store處理支付請求並返回交易完成資訊。
8. App獲取資訊並提供內容給使用者。
每個你想要出售的產品都必須先通過iTunes Connect在App Store註冊。你需提供產品的名稱,描述,價格和其他在程式中用到的中繼資料。
需為產品指定唯一的識別碼。當你的程式利用Store Kit和App Store通信時,會使用產品標識來取回產品的資訊。如果使用者購買某個商品時,程式可以用該標識來將產品標注為「已購買」。
App Store將前面提到過的產品種類簡化為以下三種:
1. 消耗性商品。 該類商品在需要時被單次購買。比如,單次服務。
2. 非消耗性商品。 該類商品只需被某個使用者購買一次,一旦被購買,和該使用者iTunes 帳戶關聯的設備都可以使用此商品。Store Kit為在多個設備上重新存儲非消耗性商品提供了內置的支援。
3. 訂閱類。訂閱類商品擁有以上兩種類型的特性。和消耗性商品一樣,訂閱類商品可以被多次購買; 你可以在程式內部加入自己的訂閱計畫更新機制。 另外,訂閱類商品必須提供給和某一使用者關聯的所有設備。In App Purchase期望訂閱類商品可以通過外部伺服器交付。你必須為多個設備的訂閱服務提供相應的支援。
關於註冊產品的詳細資訊,請參考iTunes Connect Developer Guide文檔。
交付方式
交付機制在程式In App Purchase的設計和實現種有很重要的意義。有兩種基本的模型可以用來交付產品:內置類型(Built-in model)和伺服器類型(Server model)。 不管使用那種模型,你都需要維護產品清單,並保證當使用者購買後,成功的交付產品。
1. 內置產品類型
使用這種模型。 需要交付的產品已經在程式內部。 這種方式通常用在一些被鎖定的功能上。 也可以用來交付在程式束(App Bundle)中的內容。 該方式的一個重要的優點是你可以及時的給客戶交付產品,大多數的內置產品應為非消耗性商品。
注意:In App Purchase不提供購買補丁的功能。 如果需要更改app的bundle,你必須向App Store提交新的app版本。
為了標識產品,程式要在bundle中存儲產品的識別碼。內置模式下,Apple建議使用plist來紀錄產品的識別碼。 內容類別應用可以使用折衷方式很方便的添加新的內容,而不改動程式本身。(原話為: Content-driven applications can use this to add new content without modifying the source for your application,不是很懂,感覺應該是說類似是用plist來管理產品清單,因此就不需要在添加新產品的時候改動程式了。再議。。。)
當成功購買產品後,程式應將鎖定的功能解鎖,提供給使用者。 解鎖的最簡單方式是修改程式偏好設置(Application Preferences)。 當使用者備份手機資料的時候,程式偏好設置也會隨之備份。 程式可能需要建議使用者在購買產品後備份手機以免丟失購買的內容。
圖1-2顯示了交付內置型產品的流程。
1. 程式通過bundle存儲的plist檔得到產品識別碼的清單。
2. 程式向App Store發送請求,得到產品的資訊。
3. App Store返回產品資訊。
4. 程式把返回的產品資訊顯示給使用者(App的store介面)
5. 使用者選擇某個產品
6. 程式向App Store發送支付請求
7. App Store處理支付請求並返回交易完成資訊。
8. App獲取資訊並提供內容給使用者。
2. 伺服器類型
使用這種方式,要提供另外的伺服器將產品發送給程式。 伺服器交付適用于訂閱、內容類別商品和服務,因為商品可以作為資料發送,而不需改動程式束。 例如,一個遊戲提供的新的內容(關卡等)。 Store Kit不會對伺服器端的設計和交互做出定義,這方面工作需要你來完成。 而且,Store Kit不提供驗證使用者身份的機制,你需要來設計。 如果你的程式需要以上功能,例如,紀錄特定使用者的訂閱計畫, 你需要自己來設計和實現。
圖1-3 展示了伺服器類型的購買過程。
1. 程式向伺服器發送請求,獲得一份產品清單。
2. 伺服器返回包含產品識別碼的清單。
3. 程式向App Store發送請求,得到產品的資訊。
4. App Store返回產品資訊。
5. 程式把返回的產品資訊顯示給使用者(App的store介面)
6. 使用者選擇某個產品
7. 程式向App Store發送支付請求
8. App Store處理支付請求並返回交易完成資訊。
9. 程式從資訊中獲得資料,併發送至伺服器。
10. 伺服器紀錄資料,並進行審(我們的)查。
11. 伺服器將資料發給App Store來驗證該交易的有效性。
12. App Store對收到的資料進行解析,返回該資料和說明其是否有效的標識。
13. 伺服器讀取返回的資料,確定使用者購買的內容。
14. 伺服器將購買的內容傳遞給程式。
Apple建議在伺服器端存儲產品標識,而不要將其存儲在plist中。 這樣就可以在不升級程式的前提下添加新的產品。
在伺服器模式下, 你的程式將獲得交易(transaction)相關的資訊,並將它發送給伺服器。伺服器可以驗證收到的資料,並將其解碼以確定需要交付的內容。 這個流程將在「驗證store收據」一節討論。
對於伺服器模式,我們有安全性和可靠性方面的顧慮。 你應該測試整個環境來避免威脅。《Secure Coding Guide》文檔中有相關的提示說明。
雖然非消耗性商品可以用內置模式來恢復,訂閱類商品必須通過伺服器來恢復。你要負責紀錄訂閱資訊、恢復資料。
消耗類商品也可以通過伺服器方式來紀錄。例如,由伺服器提供的一項服務, 你可能需要使用者在多個設備上重新獲得結果。
使用這種方式,要提供另外的伺服器將產品發送給程式。 伺服器交付適用于訂閱、內容類別商品和服務,因為商品可以作為資料發送,而不需改動程式束。 例如,一個遊戲提供的新的內容(關卡等)。 Store Kit不會對伺服器端的設計和交互做出定義,這方面工作需要你來完成。 而且,Store Kit不提供驗證使用者身份的機制,你需要來設計。 如果你的程式需要以上功能,例如,紀錄特定使用者的訂閱計畫, 你需要自己來設計和實現。
圖1-3 展示了伺服器類型的購買過程。
1. 程式向伺服器發送請求,獲得一份產品清單。
2. 伺服器返回包含產品識別碼的清單。
3. 程式向App Store發送請求,得到產品的資訊。
4. App Store返回產品資訊。
5. 程式把返回的產品資訊顯示給使用者(App的store介面)
6. 使用者選擇某個產品
7. 程式向App Store發送支付請求
8. App Store處理支付請求並返回交易完成資訊。
9. 程式從資訊中獲得資料,併發送至伺服器。
10. 伺服器紀錄資料,並進行審(我們的)查。
11. 伺服器將資料發給App Store來驗證該交易的有效性。
12. App Store對收到的資料進行解析,返回該資料和說明其是否有效的標識。
13. 伺服器讀取返回的資料,確定使用者購買的內容。
14. 伺服器將購買的內容傳遞給程式。
Apple建議在伺服器端存儲產品標識,而不要將其存儲在plist中。 這樣就可以在不升級程式的前提下添加新的產品。
在伺服器模式下, 你的程式將獲得交易(transaction)相關的資訊,並將它發送給伺服器。伺服器可以驗證收到的資料,並將其解碼以確定需要交付的內容。 這個流程將在「驗證store收據」一節討論。
對於伺服器模式,我們有安全性和可靠性方面的顧慮。 你應該測試整個環境來避免威脅。《Secure Coding Guide》文檔中有相關的提示說明。
雖然非消耗性商品可以用內置模式來恢復,訂閱類商品必須通過伺服器來恢復。你要負責紀錄訂閱資訊、恢復資料。
消耗類商品也可以通過伺服器方式來紀錄。例如,由伺服器提供的一項服務, 你可能需要使用者在多個設備上重新獲得結果。
取得產品資訊
要在程式內部顯示「商店」,需要從App Store得到資訊來購建介面。 本章詳細講解如何從App Store獲取產品資訊。
向App Store發送請求
Store Kit提供了從App Store上請求資料的通用機制。 程式可以創建並初始化一個request物件, 為其附加delegate, 然後啟動請求過程。請求將被發送到App Store,在那裡被處理。 處理完成時, request物件的delegate方法將被非同步調用,以獲得請求的結果。 圖2-1顯示了請求的資料模型。
如果程式在請求期間退出,則需要重新發送請求。
下面講解請求過程中用到的類:
SKRequest
SKRequest為request的抽象根類。
SKRequestDelegate
SKRequestDelegate是一個protocol, 實現用以處理請求結果的方法,比如請求成功,或請求失敗。
發送獲得產品資訊的請求
程式使用products request來獲得產品的資訊。 要完成這一過程,程式需創建一個request物件,其中會包含一個產品標識的清單。之前提到過,你的程式既可以內置產品清單,又可以通過外部伺服器來獲得。
當發送請求時,產品標識會傳送到App Store,App Store將會返回當地語系化資訊(這些資訊事先已經在iTunes Connect中設置好了),你將使用這些資訊來購建內置商店的介面(顯示商品名,描述,等等)。 圖2-2顯示了請求的過程。
SKProductsRequest
用來請求商品的資訊。 創建時,我們將需要顯示的商品清單加入該物件。
SKProductsRequestDelegate
該protocol定義了處理App Store回應的方法。
SKProductsResponse
SKProductsResponse物件為App Store返回的回應資訊。裡面包含兩個清單(當然是NSArray了):一是經過驗證有效的商品,
@property(nonatomic, readonly) NSArray *products
另外一個是無法被識別的商品資訊:
@property(nonatomic, readonly) NSArray * invalidProductIdentifiers
有幾種原因將造成商品標識無法被識別,如拼寫錯誤(當然),被標記為不可出售(unavailable for sale),或是對商品資訊的改變沒有傳送到所***** Store的伺服器。(這個原因不是很清楚,再議)。
SKProduct
SKProduct物件包含了在App Store上註冊的商品的當地語系化資訊。
要在程式內部顯示「商店」,需要從App Store得到資訊來購建介面。 本章詳細講解如何從App Store獲取產品資訊。
向App Store發送請求
Store Kit提供了從App Store上請求資料的通用機制。 程式可以創建並初始化一個request物件, 為其附加delegate, 然後啟動請求過程。請求將被發送到App Store,在那裡被處理。 處理完成時, request物件的delegate方法將被非同步調用,以獲得請求的結果。 圖2-1顯示了請求的資料模型。
如果程式在請求期間退出,則需要重新發送請求。
下面講解請求過程中用到的類:
SKRequest
SKRequest為request的抽象根類。
SKRequestDelegate
SKRequestDelegate是一個protocol, 實現用以處理請求結果的方法,比如請求成功,或請求失敗。
發送獲得產品資訊的請求
程式使用products request來獲得產品的資訊。 要完成這一過程,程式需創建一個request物件,其中會包含一個產品標識的清單。之前提到過,你的程式既可以內置產品清單,又可以通過外部伺服器來獲得。
當發送請求時,產品標識會傳送到App Store,App Store將會返回當地語系化資訊(這些資訊事先已經在iTunes Connect中設置好了),你將使用這些資訊來購建內置商店的介面(顯示商品名,描述,等等)。 圖2-2顯示了請求的過程。
SKProductsRequest
用來請求商品的資訊。 創建時,我們將需要顯示的商品清單加入該物件。
SKProductsRequestDelegate
該protocol定義了處理App Store回應的方法。
SKProductsResponse
SKProductsResponse物件為App Store返回的回應資訊。裡面包含兩個清單(當然是NSArray了):一是經過驗證有效的商品,
@property(nonatomic, readonly) NSArray *products
另外一個是無法被識別的商品資訊:
@property(nonatomic, readonly) NSArray * invalidProductIdentifiers
有幾種原因將造成商品標識無法被識別,如拼寫錯誤(當然),被標記為不可出售(unavailable for sale),或是對商品資訊的改變沒有傳送到所***** Store的伺服器。(這個原因不是很清楚,再議)。
SKProduct
SKProduct物件包含了在App Store上註冊的商品的當地語系化資訊。
購買商品
當使用者準備購買商品時,程式向App Store請求支付資訊,然後App Store將會創建持久化的交易資訊,並繼續處理支付流程,即使使用者重啟程序,這個過程亦是如此。App Store同步待定交易的清單到程式中,並在交易狀態發生改變時向程式發送更新的資料。
收集支付資訊
要收集支付資訊, 你的程式可以創建一個payment的物件,將它放到支付佇列中,如圖3-1所示。
1. 一個SKPayment的物件,包含了"Sword"的商品標識,並且制定購買數量為1。
2. 使用addPayment:方法將SKPayment的物件添加到SKPaymentQueue裡。
3. SKPaymentmentQueue包含的所有請求商品,
4. 使用SKPaymentTransactionObserver的paymentQueue: updatedTransactions: 方法來檢測所有完成的購買,併發送購買的商品。
5. 最後,使用finishTransaction:方法完成交易。
當payment的物件被添加到支付佇列中的時候, 會創建一個持久保存的transaction物件來存放它。 當支付被處理後,transaction被更新。 程式中將實現一個觀察者(observer)物件來獲取transaction更新的消息。 觀察者應該為使用者提供購買的商品,然後將transaction從佇列中移除。
下面介紹在購買過程中用到的幾個類:
SKPayment
要收集支付資訊,先要瞭解一下支付物件。 支付物件包含了商品的標識(identifier)和要購買商品的數量(quantity)(數量可選)。你可以把同一個支付物件重複放入支付佇列,,每一次這樣的動作都相當於一次獨立的支付請求。
使用者可以在Settings程式中禁用購買的功能。 因此在請求支付之前,程式應該首先檢查支付是否可以被處理。 調用SKPaymentQueue的canMakePayments方法來檢查。
SKPaymentQueue
支付佇列用以和App Store之間進行通信。 當新的支付物件被添加到佇列中的時候, Store Kit向App Store發送請求。 Store Kit將會彈出對話方塊詢問使用者是否確定購買。 完成的交易將會返回給程式的observer物件。
SKPaymentTransaction
transaction物件在每次添加新的payment到佇列中的時候被創建。 transaction物件包含了一些屬性,可以讓程式確定當前的交易狀態。
程式可以從支付佇列那裡得到一份審核中的交易清單,但更常用的做法還是等待支付佇列告知交易狀態的更新。
SKPaymentTransactionObserver
在程式中實現SKPaymentTransactionObserver的協定,然後把它作為SKPaymentQueue物件的觀察者。該觀察者的主要職責是:檢查完成的交易,交付購買的內容,和把完成後的交易對象從佇列中移除。
在程式一啟動,就應該為支付佇列指定對應的觀察者物件,而不是等到使用者想要購買商品的時候。 Transaction物件在程式退出時不會丟失。程式重啟時, Store Kit繼續執行未完成的交易。 在程式初始化的時候添加觀察者物件,可以保證所有的交易都被程式接收(也就時說,如果有未完成的transaction,如果程式重啟,就重新開始了,如果稍候再添加觀察者,就可能會漏掉部分交易的資訊)。
恢復交易資訊(Transactions)
當transaction被處理並從佇列移除之後,正常情況下,程式就再也看不到它們了。 如果你的程式提供的是非消耗性的或是訂閱類的商品,就必須提供restore的功能,使使用者可以在其他設備上重新存儲購買資訊。
Store Kit提供內建的功能來重新存儲非消耗商品的交易資訊。 調用SKPaymentQueue的restoreCompletedTransactions的方法來重新存儲。對於那些之前已經完成交易的非消耗性商品,Apple Store生成新的,用於恢復的交易資訊。 它包含了原始的交易資訊。你的程式可以拿到這個資訊,然後繼續為購買的功能解鎖。 當之前所有的交易都被恢復時, 就會調用觀察者物件的paymentQueueRestoreCompletedTransactionsFinished方法。
如果使用者試圖購買已經買過的非消耗性商品,程式會收到一個常規的交易資訊,而不是恢復的交易資訊。但是使用者不會被再次收費。程式 應把這類交易和原始的交易同等對待。
訂閱類服務和消耗類商品不會被Store Kit自動復原。 要恢復這些商品,你必須在使用者購買這些商品時,在你自己的伺服器上記錄這些交易資訊, 並且為使用者的設備提供恢復交易資訊的機制。
當使用者準備購買商品時,程式向App Store請求支付資訊,然後App Store將會創建持久化的交易資訊,並繼續處理支付流程,即使使用者重啟程序,這個過程亦是如此。App Store同步待定交易的清單到程式中,並在交易狀態發生改變時向程式發送更新的資料。
收集支付資訊
要收集支付資訊, 你的程式可以創建一個payment的物件,將它放到支付佇列中,如圖3-1所示。
1. 一個SKPayment的物件,包含了"Sword"的商品標識,並且制定購買數量為1。
2. 使用addPayment:方法將SKPayment的物件添加到SKPaymentQueue裡。
3. SKPaymentmentQueue包含的所有請求商品,
4. 使用SKPaymentTransactionObserver的paymentQueue: updatedTransactions: 方法來檢測所有完成的購買,併發送購買的商品。
5. 最後,使用finishTransaction:方法完成交易。
當payment的物件被添加到支付佇列中的時候, 會創建一個持久保存的transaction物件來存放它。 當支付被處理後,transaction被更新。 程式中將實現一個觀察者(observer)物件來獲取transaction更新的消息。 觀察者應該為使用者提供購買的商品,然後將transaction從佇列中移除。
下面介紹在購買過程中用到的幾個類:
SKPayment
要收集支付資訊,先要瞭解一下支付物件。 支付物件包含了商品的標識(identifier)和要購買商品的數量(quantity)(數量可選)。你可以把同一個支付物件重複放入支付佇列,,每一次這樣的動作都相當於一次獨立的支付請求。
使用者可以在Settings程式中禁用購買的功能。 因此在請求支付之前,程式應該首先檢查支付是否可以被處理。 調用SKPaymentQueue的canMakePayments方法來檢查。
SKPaymentQueue
支付佇列用以和App Store之間進行通信。 當新的支付物件被添加到佇列中的時候, Store Kit向App Store發送請求。 Store Kit將會彈出對話方塊詢問使用者是否確定購買。 完成的交易將會返回給程式的observer物件。
SKPaymentTransaction
transaction物件在每次添加新的payment到佇列中的時候被創建。 transaction物件包含了一些屬性,可以讓程式確定當前的交易狀態。
程式可以從支付佇列那裡得到一份審核中的交易清單,但更常用的做法還是等待支付佇列告知交易狀態的更新。
SKPaymentTransactionObserver
在程式中實現SKPaymentTransactionObserver的協定,然後把它作為SKPaymentQueue物件的觀察者。該觀察者的主要職責是:檢查完成的交易,交付購買的內容,和把完成後的交易對象從佇列中移除。
在程式一啟動,就應該為支付佇列指定對應的觀察者物件,而不是等到使用者想要購買商品的時候。 Transaction物件在程式退出時不會丟失。程式重啟時, Store Kit繼續執行未完成的交易。 在程式初始化的時候添加觀察者物件,可以保證所有的交易都被程式接收(也就時說,如果有未完成的transaction,如果程式重啟,就重新開始了,如果稍候再添加觀察者,就可能會漏掉部分交易的資訊)。
恢復交易資訊(Transactions)
當transaction被處理並從佇列移除之後,正常情況下,程式就再也看不到它們了。 如果你的程式提供的是非消耗性的或是訂閱類的商品,就必須提供restore的功能,使使用者可以在其他設備上重新存儲購買資訊。
Store Kit提供內建的功能來重新存儲非消耗商品的交易資訊。 調用SKPaymentQueue的restoreCompletedTransactions的方法來重新存儲。對於那些之前已經完成交易的非消耗性商品,Apple Store生成新的,用於恢復的交易資訊。 它包含了原始的交易資訊。你的程式可以拿到這個資訊,然後繼續為購買的功能解鎖。 當之前所有的交易都被恢復時, 就會調用觀察者物件的paymentQueueRestoreCompletedTransactionsFinished方法。
如果使用者試圖購買已經買過的非消耗性商品,程式會收到一個常規的交易資訊,而不是恢復的交易資訊。但是使用者不會被再次收費。程式 應把這類交易和原始的交易同等對待。
訂閱類服務和消耗類商品不會被Store Kit自動復原。 要恢復這些商品,你必須在使用者購買這些商品時,在你自己的伺服器上記錄這些交易資訊, 並且為使用者的設備提供恢復交易資訊的機制。
在程式中添加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"];
本章為添加購買功能的指導
詳細流程:
準備工作當然是添加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"];
No comments:
Post a Comment