In App Purchases(IAP 應用程序內購買): 徹底攻略

http://www.cocoachina.com/bbs/read.php?tid=69165&keyword=IAP%3C/p%3E

原文: http://troybrant.net/blog/2010/01/in-app-purchases-a-full-walkthrough/
參考: http://www.cocoachina.com/bbs/read.php?tid-11357.html
新: http://www.cocoachina.com/gamedev/misc/2012/0409/4129.html     demo
第一印象以爲In-App Purchase(簡稱IAP)很是簡單。Apple提供的大量文檔應該讓開發者很快熟悉地熟悉。那麼,爲什麼在你的應用中集成IAP特性就如此使人生厭呢?

這是由於在開發過程當中不可避免會出現一些錯誤。而但這些錯誤發生的時候,你就抓瞎了。雖然Apple提供了有關IAP的大量文檔,但他們並未說起集成IAP的詳細步驟。並且對StoreKit集成過程當中出現的問題也沒有一個核對清單。另外對於爲什麼諸如產品ID非法之類的問題也沒有提供NSError之類的對象來告訴你緣由。

在試用了各類可能的解決方桉後,你只能身心疲憊,彷徨無助。

爲了提升你的效率和減小你的痛苦,我覺定利用此文來介紹一下實現IAP的詳細步驟。本文很詳細,有點長。甚至可能太長了,但不像Apple的文檔,它提供了爲實現IAP的每個步驟。

廢話少說,咱們直入主題吧。


概況
IAP能正常工做的祕訣:分紅兩個步驟:

建立及提取產品描述
購買產品
第一個步驟是你可能遇到問題的部分。一旦你在代碼中成功地獲取了產品描述,編寫購買產品的代碼不過是小菜一碟。

咱們先看看步驟1。

建立及提取產品描述
下面是有關建立產品及提取其描述的很是粗略的步驟:

建立惟一的App ID
生成及安裝新的provisioning profile文件
在Xcode中更新 bundle ID 及 code signing profile
若是還沒作的話,請在iTunes Connect中提交有關你程序的 metadata
若是還沒作的話,請在iTunes Connect中提交你程序的二進制碼
爲IAP添加新產品
編寫提取產品描述的代碼
等待幾小時
提取產品描述的代碼很是簡單,但其餘步驟則很容易錯。

注意: 爲提取產品描述,你並不須要在iTunes Connect中建立IAP測試用戶。



1. 建立惟一的App ID
爲支持IAP,你的App ID不能包括通配符(「*」)。爲肯定你的App Id是否包括通配符,請登陸 http://developer.apple.com/iphone ,在 iPhone Developer Program Portal中選擇左邊菜單中的 「App IDs」檢查你的 App ID。

下面是一個惟一的App ID:

7DW89RZKLY.com.runmonster.runmonsterfree

下面不是一個惟一的 App ID:

7DW89RZKLY.com.runmonster.*

若是你尚未一個惟一的App ID,按以下步驟建立一個:

在developer portal中的 App IDs 部分,選擇「New App ID」
填寫下列信息:
Display name(顯示名): 選取一個不一樣的App ID的名稱。你不能編輯或刪除舊的App ID,因此你必須爲你的App ID提供一個新名稱以免溷淆。
Prefix(前綴): 生成一個新的前綴,或者若是你的程序是經過Keychain Services API分享數據的系列程序中之一的話,則選用已存在的前綴。
Suffix(後綴): com.companyname.appname (這是通用格式 – 注意沒有使用通配符)。
按 「Save」
按 App ID旁的「Configure」 連接
選取 「Enable In App Purchase」選擇框
按「Done」
2. 建立一個新的Provisioning Profile文件
在建立了新的App ID後,你須要生成一個指向這個App ID的新provisioning profile。

下面就是使人痛苦的生成和安裝新provisioning profile的詳細步驟:

在 iPhone Developer Portal中, 選擇左邊的Provisioning部分
確保你處於Development 標籤下, 按下右上角的 「New Profile」
填入所需信息並指向你剛建立的惟一的App ID
若是你在Actions條目下看到 「Pending」,那麼請按下「Development」標籤標題進行刷新
點擊 「Download」 下載新的profile文件
將profile文件拖入到Dock中Xcode圖標上進行安裝
若是你想在硬盤上保存provisioning profile,那麼你能夠按以下步驟手工安裝profile:
在Xcode中, 選擇 Window > Organizer
選擇左邊 「Provisioning Profiles」 分類
Ctrl-按下profile > Reveal in Finder
將新profile拖入到 profile Finder 窗口
3. 更新Xcode 設置
在Xcode中安裝了 profile 文件後,你須要對使用此provisiong profile的項目進行一些編輯工做:

編輯項目 .plist 文件使其 Bundle ID 與 App ID 匹配。忽略ID開始部分的字母數字序列。例如,在Developer Portal中你的App ID爲「7DW89RZKLY.com.runmonster.runmonsterfree」,那麼在Bundle ID中你只需輸入「com.runmonster.runmonsterfree」 。
編輯項目的 target 信息以使用新的provisioning profile:
選取 Project > Edit Active Target
選取頂部「Build」 標籤
選取須要的 configuration (一般爲 Debug)
在Code Signing Identity中選擇新的provisioning profile
在Code Signing Identity之下的行中(可能名爲 Any iPhone OS Device)選擇新的provisioning profile
4. 添加你的應用程序
若是你的程序已經發表到App Store了,那麼能夠略過此步驟。

在你將產品添加到 iTunes Connect以前,你必須添加此產品所需的程序。若是你的程序尚未100%完成也無需擔憂,你能夠先提交具備部分數據的程序,最後再提交真實的程序。

注意: 只有 SKU 和 version(版本)部分是之後不可修改的

登陸到  http://developer.apple.com/iphone
點擊右邊連接進入 iTunes Connect
注意:你必須先登陸到developer.apple.com,不然會有不測發生(譯者注:具體是什麼不測我也不太清楚,膽大的請本身試一下)
在 iTunes Connect主頁點擊 「Manage Your Applications」
在右上角點擊「Create New Application」
填寫程序所需的一切信息。當要求程序二進制碼時,請選擇稍後上傳選項。
5. 提交程序二進制碼
Apple的文檔中沒有任何地方說起詳情,但它倒是必須的步驟。要成功測IAP功能,你必須提交程序的二進制碼。即便你的程序尚未100%完成,你仍然須要提交二進制碼。然而,你也能夠當即擯棄你的二進制碼,使其不會進入審覈階段。

下面這些步驟很是關鍵,我但是由於少作了某些步驟而度過了一段很是痛苦的時間:

生成App Store發佈版程序
若是你不知怎麼作,請在 iPhone Developer Portal 中點擊左方的 Distribution標籤,並選擇 「Prepare App」 標籤。而後,根據藍色連接的指示:
獲取iPhone發行許可證
建立並下載在App Store發行所需的iPhone Distribution Provisioning Profile
在Xcode中生成程序的發行版
在iTunes Connect中進入程序頁
選擇 「Upload Binary」
上傳.zip壓縮程序
若是你的程序尚未100%完成以進行審覈,那麼請點擊iTunes Connect中你程序首頁中的 「Reject Binary」連接。程序的狀態應該更新爲 「Developer Rejected」.
不用擔憂,因爲程序的狀態是「Developer Rejected」,Apple是不會對其進行審覈的。你能夠在任什麼時候候提交程序的新版本並使其狀態爲「Developer Rejected」,這不會對之後程序正式提交的等待時間有任何影響。

6. 添加產品
完成了以上全部步驟後,咱們最終能夠向iTunes Connect中添加產品了。

確保登陸到  http://developer.apple.com/iphone
進入 iTunes Connect 主頁
點擊「Manage Your Applications」
點擊剛建好的程序 點擊view details
點擊 「Manage in-App Purchases」 連接
點擊 「Create New」
填寫下列產品信息:
Reference Name(參考名稱): 產品的通用名稱。好比,我使用的是 「Pro Upgrade」。此名稱是不容許進行編輯的,它不會顯示於App Store中。
Product ID(產品ID): 你產品的惟一id。一般格式是 com.company.appname.product,但它能夠說任何形式。它並不要求以程序的App ID做爲前綴。
Type(類型): 有三種選擇
Non-consumable(非消耗品): 僅需付費一次 (例如你但願將出現從免費版升級爲專業版)
Consumable(消耗品): 每次下載都須要付費
Subscription(預訂): 循環反覆
Price Tier(價格等級): 產品價格。參見不一樣等級的價格列表。
Cleared for Sale(等待銷售): 必定要選取此項,不然的話,測試時會發生非法產品ID的錯誤。
Language to Add(增長的語言): 選一項。下列兩項將出現:
Displayed Name(顯示名稱): 用戶看到的產品名稱。好比我選擇 「Upgrade to Pro」。
Description(描述): 對產品進行描述。此處輸入的文本將與Displayed Name 及 Price 一塊兒在你代碼中提取 SKProduct時出現。
Screenshot(截屏): 展現你產品的截屏。儘管屏幕上會顯示「提交截屏會觸發產品審覈過程」之類的文字(我的拙見,這是很是糟糕的設計),你仍是能夠安全地提交截屏而不會使產品進入審覈過程。存儲後,選擇「Submit with app binary」 (隨程序二進制碼一塊兒提交)選項。是產品與程序二進制綁定在一塊兒,因此在你最後正式提交100%完成的程序二進制碼時,產品也會隨之提交。
點擊 「Save」
最後必定不要忘了回到view details  編輯In-App Purchases
選擇剛剛添加的iap版本
7. 編寫代碼
下面咱們開始編寫代碼對剛加入到iTunes Connect中的產品信息進行提取。我訪問產品數據,咱們須要使用 StoreKit framework。

注意: StoreKit 沒法在模擬器上工做。你必須在真機上進行測試。

1.添加 StoreKit framework 到你的項目中。
2.添加SKProduct引用到你的 .h 文件中:

複製代碼
  1. // InAppPurchaseManager.h
  2. #import <StoreKit/StoreKit.h>
  3. #define kInAppPurchaseManagerProductsFetchedNotification @"kInAppPurchaseManagerProductsFetchedNotification"
  4. @interface InAppPurchaseManager : NSObject <SKProductsRequestDelegate>
  5. {
  6.     SKProduct *proUpgradeProduct;
  7.     SKProductsRequest *productsRequest;
  8. }

注意: InAppPurchaseManager 是一個單例類,它處理程序中全部IAP任務。它是本文中的示例程序。

3.產品請求,並在相應.m文件中實現代理協議:
複製代碼
  1. // InAppPurchaseManager.m
  2. - (void)requestProUpgradeProductData
  3. {
  4.     NSSet *productIdentifiers = [NSSet setWithObject:@"com.runmonster.runmonsterfree.upgradetopro" ];
  5.     productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
  6.     productsRequest.delegate = self;
  7.     [productsRequest start];
  8.     
  9.     // we will release the request object in the delegate callback
  10. }
  11. #pragma mark -
  12. #pragma mark SKProductsRequestDelegate methods
  13. - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
  14. {
  15.     NSArray *products = response.products;
  16.     proUpgradeProduct = [products count] == 1 ? [[products firstObject] retain] : nil;
  17.     if (proUpgradeProduct)
  18.     {
  19.         NSLog(@"Product title: %@" , proUpgradeProduct.localizedTitle);
  20.         NSLog(@"Product description: %@" , proUpgradeProduct.localizedDescription);
  21.         NSLog(@"Product price: %@" , proUpgradeProduct.price);
  22.         NSLog(@"Product id: %@" , proUpgradeProduct.productIdentifier);
  23.     }
  24.     
  25.     for (NSString *invalidProductId in response.invalidProductIdentifiers)
  26.     {
  27.         NSLog(@"Invalid product id: %@" , invalidProductId);
  28.     }
  29.     
  30.     // finally release the reqest we alloc/init’ed in requestProUpgradeProductData
  31.     [productsRequest release];
  32.     
  33.     [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
  34. }

上面代碼有幾點須要注意:

指定產品id時,你必須使用完整產品id。例如,上例中使用 「com.runmonster.runmonsterfree.upgradetopro」。僅使用 「upgradetopro」 將不會正常工做。
若是在productsRequest:didReceiveResponse:中response.products 爲 nil,而你的產品id出現於 response.invalidProductIdentifers 數組中時,那麼請作好心理準備開始一場徒勞的搜索戰吧。 StoreKit API沒有提供任何幫助,也沒有任何指示關於爲什麼你的id是無效的。很可愛,不是嗎?
SKProduct類提供了有關程序標題和描述的本地化版本,可是價格則沒有本地化版本。下面是針對此疏忽提供的代碼:
複製代碼
  1. // SKProduct+LocalizedPrice.h
  2. #import <Foundation/Foundation.h>
  3. #import <StoreKit/StoreKit.h>
  4. @interface SKProduct (LocalizedPrice)
  5. @property (nonatomic, readonly) NSString *localizedPrice;
  6. @end

複製代碼
  1. // SKProduct+LocalizedPrice.m
  2. #import "SKProduct+LocalizedPrice.h"
  3. @implementation SKProduct (LocalizedPrice)
  4. - (NSString *)localizedPrice
  5. {
  6.     NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
  7.     [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
  8.     [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
  9.     [numberFormatter setLocale:self.priceLocale];
  10.     NSString *formattedString = [numberFormatter stringFromNumber:self.price];
  11.     [numberFormatter release];
  12.     return formattedString;
  13. }
  14. @end

加入上述代碼,測試一下。你應該在控制檯窗口中看見產品信息了。然而更大的多是,你獲得了一個無效的產品id。我下一篇文章將介紹怎樣對這個問題進行調試。可是,下面的步驟8有多是阻礙你前進的障礙。

8. 等待幾小時
遵循了上述全部步驟,可是你的產品仍然是無效的?你是否兩次,三次,四次不懈努力地確認你是否遵循了上面提到的每一個步驟?你是否已經對網上IAP信息少得可憐而感到絕望?

那麼,你應該等待。

你的產品要進入iTunes Connect使得Apple準備好沙箱環境須要一些時間。對於我而言,我是通過了無數次產品無效錯誤的絕望。而在24小時後,我沒有修改任何一行代碼,但產品id變爲有效。我認爲要使產品發佈到Apple的網絡系統須要幾個小時的時間,但若是你有時間的話,你能夠像我同樣等上24個小時。

購買產品
至此你應該已經成功地獲取了 SKProduct 描述。比較而言,支持購買產品相對簡單些。僅需下面三個步驟:

編寫代碼支持事務(transaction)
在iTunes Connect中添加程序測試用戶
在設備中登陸你的 iTunes Store 賬號
購買測試
咱們從編寫支持事務所需代碼開始。

1. 編寫代碼支持事務
首先注意:你將負責開發產品購買的用戶界面。StoreKit 未提供任何與用戶界面相關的元素。若是你但願你的購買用戶界面與App Store同樣,那麼你要本身完成。

下面全部代碼都是有關事務處理的後臺部分。這是一個單獨的類只有一條簡單的API以供外部類(好比view controller)調用進行購買。若是你找到將其集成到你程序的購買部分的方法,那麼我推薦你使用相似方桉。

首先,須要遵循 SKPaymentTransactionObserver 協議:


上面咱們定義了兩個新的notification,它們將做爲購買事務的結果被髮送。在上例中咱們仍然使用與獲取產品描述同一個InAppPurchaseManager類。

要測試上面的新代碼,你還須要編寫調用 loadStore, canMakePurchases 以及 purchaseProUpgrade 方法的代碼。

有關上述代碼的詳細解釋,請參考官方 In App Purchase Programming Guide (IAP編程指南)

上述代碼有幾個部分是針對個人程序的。例如,在 provideContent:中,NSUserDefaults 中的@」isProUpgradePurchased」 BOOL 字段被設定爲 YES。程序的其餘部分將檢查此BOOL值以肯定是否須要啓動專業版功能。若是你正好也要實現免費升級專業版的功能,那麼你可使用一樣的方法。

2. 添加測試用戶
爲測試上述代碼,你須要在 iTunes Connect 中建立測試用戶以對IAP功能進行測試。你可使用測試賬號購買產品而不被Apple收取費用。

按如下步驟建立測試用戶:

登陸到  http://developer.apple.com/iphone
進入 iTunes Connect
選擇iTunes Connect首頁中的 「Manage Users」
選擇 「In App Purchase Test User」
選擇 「Add New User」
填入用戶信息. 全部信息都沒必要是合法的。建議使用虛假簡短的email地址及簡短的密碼。
選擇 「Save」
測試時你須要輸入這些email地址和密碼。

3. 在你的設備中退出登陸
在進行程序購買功能測試前,你必須在你的設備中退出iTunes Store。遵循如下步驟:

打開Settings App
點擊 「Store」 行
點擊 「Sign Out」
4. 購買測試
如今,終於能夠開始進行IAP功能的測試了。測試很簡單:

運行你設備中的程序
進行購買
當程序提示輸入用戶名和密碼時,輸入參數用戶的信息
若是你使用同一帳戶進行購買時,系統將提示你已經購買了此產品。按「Yes」就能夠再次下載此產品。

總結
實現IAP功能比想象的要複雜許多。我但是通過無數痛苦的經歷才完成個人程序。但願可以幫助其餘開發者減輕他們的痛苦。應用程序內購買
相關文章
相關標籤/搜索