精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

iOS應(yīng)用內(nèi)置付費(fèi):In-App Purchases完全攻略

移動(dòng)開(kāi)發(fā) iOS
實(shí)現(xiàn)IAP功能比想象的要復(fù)雜許多。我可是經(jīng)過(guò)無(wú)數(shù)痛苦的經(jīng)歷才完成我的程序。希望能夠幫助其他開(kāi)發(fā)者減輕他們的痛苦。第一印象覺(jué)得In-App Purchase(簡(jiǎn)稱IAP)非常簡(jiǎn)單。Apple提供的大量文檔應(yīng)該讓開(kāi)發(fā)者很快熟悉地熟悉。為什麼在你的應(yīng)用中集成IAP特性就如此令人生厭呢?

參考:iOS應(yīng)用內(nèi)置付費(fèi)In-App Purchase 個(gè)人使用總結(jié)

 

新:In-App Purchases入門    demo下載:http://down.51cto.com/data/941246

第一印象覺(jué)得In-App Purchase(簡(jiǎn)稱IAP)非常簡(jiǎn)單。Apple提供的大量文檔應(yīng)該讓開(kāi)發(fā)者很快熟悉地熟悉。那麼,為什麼在你的應(yīng)用中集成IAP特性就如此令人生厭呢?

這是因?yàn)樵陂_(kāi)發(fā)過(guò)程中不可避免會(huì)出現(xiàn)一些錯(cuò)誤。而但這些錯(cuò)誤發(fā)生的時(shí)候,你就抓瞎了。雖然Apple提供了有關(guān)IAP的大量文檔,但他們并未提及集成IAP 的詳細(xì)步驟。而且對(duì)StoreKit集成過(guò)程中出現(xiàn)的問(wèn)題也沒(méi)有一個(gè)核對(duì)清單。另外對(duì)于為什麼諸如產(chǎn)品ID非法之類的問(wèn)題也沒(méi)有提供NSError之類的 對(duì)象來(lái)告訴你原因。

在試用了各種可能的解決方桉后,你只能身心疲憊,彷徨無(wú)助。

為了提高你的效率和減少你的痛苦,我覺(jué)定利用此文來(lái)介紹一下實(shí)現(xiàn)IAP的詳細(xì)步驟。本文很詳細(xì),有點(diǎn)長(zhǎng)。甚至可能太長(zhǎng)了,但不像Apple的文檔,它提供了為實(shí)現(xiàn)IAP的每一個(gè)步驟。

廢話少說(shuō),我們直入主題吧。

概況

IAP能正常工作的秘訣:分成兩個(gè)步驟:

創(chuàng)建及提取產(chǎn)品描述

購(gòu)買產(chǎn)品

第一個(gè)步驟是你可能遇到問(wèn)題的部分。一旦你在代碼中成功地獲取了產(chǎn)品描述,編寫(xiě)購(gòu)買產(chǎn)品的代碼不過(guò)是小菜一碟。

我們先看看步驟1。

創(chuàng)建及提取產(chǎn)品描述

下面是有關(guān)創(chuàng)建產(chǎn)品及提取其描述的非常粗略的步驟:

創(chuàng)建唯一的App ID

生成及安裝新的provisioning profile文件

在Xcode中更新 bundle ID 及 code signing profile

如果還沒(méi)做的話,請(qǐng)?jiān)趇Tunes Connect中提交有關(guān)你程序的 metadata

如果還沒(méi)做的話,請(qǐng)?jiān)趇Tunes Connect中提交你程序的二進(jìn)制碼

為IAP添加新產(chǎn)品

編寫(xiě)提取產(chǎn)品描述的代碼

等待幾小時(shí)

提取產(chǎn)品描述的代碼非常簡(jiǎn)單,但其他步驟則很容易錯(cuò)。

注意:為提取產(chǎn)品描述,你并不需要在iTunes Connect中創(chuàng)建IAP測(cè)試用戶。

1. 創(chuàng)建唯一的App ID

為支持IAP,你的App ID不能包括通配符(“*”)。為確定你的App Id是否包括通配符,請(qǐng)登錄http://developer.apple.com/iphone,在 iPhone Developer Program Portal中選擇左邊菜單中的 “App IDs”檢查你的 App ID。

下面是一個(gè)唯一的App ID:

7DW89RZKLY.com.runmonster.runmonsterfree

下面不是一個(gè)唯一的 App ID:

7DW89RZKLY.com.runmonster.*

如果你還沒(méi)有一個(gè)唯一的App ID,按如下步驟創(chuàng)建一個(gè):

在developer portal中的 App IDs 部分,選擇“New App ID”

填寫(xiě)下列信息:

Display name(顯示名): 選取一個(gè)不同的App ID的名稱。你不能編輯或刪除舊的App ID,所以你必須為你的App ID提供一個(gè)新名稱以避免溷淆。

Prefix(前綴): 生成一個(gè)新的前綴,或者如果你的程序是通過(guò)Keychain Services API分享數(shù)據(jù)的系列程序中之一的話,則選用已存在的前綴。

Suffix(后綴): com.companyname.appname (這是通用格式 – 注意沒(méi)有使用通配符)。

按 “Save”

按 App ID旁的“Configure” 鏈接

選取 “Enable In App Purchase”選擇框

按“Done”

2. 創(chuàng)建一個(gè)新的Provisioning Profile文件

在創(chuàng)建了新的App ID后,你需要生成一個(gè)指向這個(gè)App ID的新provisioning profile。

下面就是令人痛苦的生成和安裝新provisioning profile的詳細(xì)步驟:

在 iPhone Developer Portal中, 選擇左邊的Provisioning部分

確保你處于Development 標(biāo)籤下, 按下右上角的 “New Profile”

填入所需信息并指向你剛創(chuàng)建的唯一的App ID

如果你在Actions條目下看到 “Pending”,那麼請(qǐng)按下“Development”標(biāo)籤標(biāo)題進(jìn)行刷新

點(diǎn)擊 “Download” 下載新的profile文件

將profile文件拖入到Dock中Xcode圖標(biāo)上進(jìn)行安裝

如果你想在硬盤上保存provisioning profile,那麼你可以按如下步驟手工安裝profile:

在Xcode中, 選擇 Window > Organizer

選擇左邊 “Provisioning Profiles” 分類

Ctrl-按下profile > Reveal in Finder

將新profile拖入到 profile Finder 窗口

3. 更新Xcode 設(shè)置

在Xcode中安裝了 profile 文件后,你需要對(duì)使用此provisiong profile的項(xiàng)目進(jìn)行一些編輯工作:

編 輯項(xiàng)目 .plist 文件使其 Bundle ID 與 App ID 匹配。忽略ID開(kāi)始部分的字母數(shù)字序列。例如,在Developer Portal中你的App ID為“7DW89RZKLY.com.runmonster.runmonsterfree”,那麼在Bundle ID中你只需輸入“com.runmonster.runmonsterfree” 。

編輯項(xiàng)目的 target 信息以使用新的provisioning profile:

選取 Project > Edit Active Target

選取頂部“Build” 標(biāo)籤

選取需要的 configuration (通常為 Debug)

在Code Signing Identity中選擇新的provisioning profile

在Code Signing Identity之下的行中(可能名為 Any iPhone OS Device)選擇新的provisioning profile

4. 添加你的應(yīng)用程序

如果你的程序已經(jīng)發(fā)表到App Store了,那麼可以略過(guò)此步驟。

在你將產(chǎn)品添加到 iTunes Connect之前,你必須添加此產(chǎn)品所需的程序。如果你的程序還沒(méi)有100%完成也無(wú)需擔(dān)心,你可以先提交具有部分?jǐn)?shù)據(jù)的程序,最后再提交真實(shí)的程序。

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

登錄到 http://developer.apple.com/iphone

點(diǎn)擊右邊鏈接進(jìn)入 iTunes Connect

注意:你必須先登錄到developer.apple.com,否則會(huì)有不測(cè)發(fā)生(譯者注:具體是什麼不測(cè)我也不太清楚,膽大的請(qǐng)自己試一下)

在 iTunes Connect主頁(yè)點(diǎn)擊 “Manage Your Applications”

在右上角點(diǎn)擊“Create New Application”

填寫(xiě)程序所需的一切信息。當(dāng)要求程序二進(jìn)制碼時(shí),請(qǐng)選擇稍后上傳選項(xiàng)。

5. 提交程序二進(jìn)制碼

Apple的文檔中沒(méi)有任何地方提及詳情,但它卻是必須的步驟。要成功測(cè)IAP功能,你必須提交程序的二進(jìn)制碼。即使你的程序還沒(méi)有100%完成,你仍然需要提交二進(jìn)制碼。然而,你也可以立即擯棄你的二進(jìn)制碼,使其不會(huì)進(jìn)入審核階段。

下面這些步驟非常關(guān)鍵,我可是因?yàn)樯僮隽四承┎襟E而度過(guò)了一段非常痛苦的時(shí)間:

生成App Store發(fā)佈版程序

如果你不知怎麼做,請(qǐng)?jiān)?iPhone Developer Portal 中點(diǎn)擊左方的 Distribution標(biāo)籤,并選擇 “Prepare App” 標(biāo)籤。然后,根據(jù)藍(lán)色鏈接的指示:

獲取iPhone發(fā)行許可證

創(chuàng)建并下載在App Store發(fā)行所需的iPhone Distribution Provisioning Profile

在Xcode中生成程序的發(fā)行版

在iTunes Connect中進(jìn)入程序頁(yè)

選擇 “Upload Binary”

上傳.zip壓縮程序

如果你的程序還沒(méi)有100%完成以進(jìn)行審核,那麼請(qǐng)點(diǎn)擊iTunes Connect中你程序首頁(yè)中的 “Reject Binary”鏈接。程序的狀態(tài)應(yīng)該更新為 “Developer Rejected”.

不用擔(dān)心,由于程序的狀態(tài)是“Developer Rejected”,Apple是不會(huì)對(duì)其進(jìn)行審核的。你可以在任何時(shí)候提交程序的新版本并使其狀態(tài)為“Developer Rejected”,這不會(huì)對(duì)以后程序正式提交的等待時(shí)間有任何影響。

6. 添加產(chǎn)品

完成了以上所有步驟后,我們最終可以向iTunes Connect中添加產(chǎn)品了。

確保登錄到 http://developer.apple.com/iphone

進(jìn)入 iTunes Connect 主頁(yè)

點(diǎn)擊“Manage Your Applications”

點(diǎn)擊剛建好的程序 點(diǎn)擊view details

點(diǎn)擊 “Manage in-App Purchases” 鏈接

點(diǎn)擊 “Create New”

填寫(xiě)下列產(chǎn)品信息:

Reference Name(參考名稱): 產(chǎn)品的通用名稱。比如,我使用的是 “Pro Upgrade”。此名稱是不允許進(jìn)行編輯的,它不會(huì)顯示于App Store中。

Product ID(產(chǎn)品ID): 你產(chǎn)品的唯一id。通常格式是 com.company.appname.product,但它可以說(shuō)任何形式。它并不要求以程序的App ID作為前綴。

Type(類型): 有三種選擇

Non-consumable(非消耗品): 僅需付費(fèi)一次 (例如你希望將出現(xiàn)從免費(fèi)版升級(jí)為專業(yè)版)

Consumable(消耗品): 每次下載都需要付費(fèi)

Subscription(預(yù)訂): 循環(huán)反覆

Price Tier(價(jià)格等級(jí)): 產(chǎn)品價(jià)格。參見(jiàn)不同等級(jí)的價(jià)格列表。

Cleared for Sale(等待銷售): 一定要選取此項(xiàng),否則的話,測(cè)試時(shí)會(huì)發(fā)生非法產(chǎn)品ID的錯(cuò)誤。

Language to Add(增加的語(yǔ)言): 選一項(xiàng)。下列兩項(xiàng)將出現(xiàn):

Displayed Name(顯示名稱): 用戶看到的產(chǎn)品名稱。比如我選擇 “Upgrade to Pro”。

Description(描述): 對(duì)產(chǎn)品進(jìn)行描述。此處輸入的文本將與Displayed Name 及 Price 一起在你代碼中提取 SKProduct時(shí)出現(xiàn)。

Screenshot(截 屏): 展示你產(chǎn)品的截屏。儘管屏幕上會(huì)顯示“提交截屏?xí)|發(fā)產(chǎn)品審核過(guò)程”之類的文字(個(gè)人拙見(jiàn),這是非常糟糕的設(shè)計(jì)),你還是可以安全地提交截屏而不會(huì)使產(chǎn)品 進(jìn)入審核過(guò)程。存儲(chǔ)后,選擇“Submit with app binary” (隨程序二進(jìn)制碼一起提交)選項(xiàng)。是產(chǎn)品與程序二進(jìn)制綁定在一起,所以在你最后正式提交100%完成的程序二進(jìn)制碼時(shí),產(chǎn)品也會(huì)隨之提交。

點(diǎn)擊 “Save”

最后一定不要忘了回到view details  編輯In-App Purchases

選擇剛剛添加的iap版本

別走開(kāi),下頁(yè)內(nèi)容更精彩

#p#

7. 編寫(xiě)代碼

下面我們開(kāi)始編寫(xiě)代碼對(duì)剛加入到iTunes Connect中的產(chǎn)品信息進(jìn)行提取。我訪問(wèn)產(chǎn)品數(shù)據(jù),我們需要使用 StoreKit framework。

注意: StoreKit 無(wú)法在模擬器上工作。你必須在真機(jī)上進(jìn)行測(cè)試。

1)添加 StoreKit framework 到你的項(xiàng)目中。

2)添加SKProduct引用到你的 .h 文件中:

  1. // InAppPurchaseManager.h 
  2. #import <StoreKit/StoreKit.h> 
  3. #define kInAppPurchaseManagerProductsFetchedNotification @"kInAppPurchaseManagerProductsFetchedNotification" 
  4. @interface InAppPurchaseManager : NSObject <SKProductsRequestDelegate> 
  5.     SKProduct *proUpgradeProduct; 
  6.     SKProductsRequest *productsRequest; 

注意: InAppPurchaseManager 是一個(gè)單例類,它處理程序中所有IAP任務(wù)。它是本文中的示例程序。

3)產(chǎn)品請(qǐng)求,并在相應(yīng).m文件中實(shí)現(xiàn)代理協(xié)議:

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

上面代碼有幾點(diǎn)需要注意:

指定產(chǎn)品id時(shí),你必須使用完整產(chǎn)品id。例如,上例中使用 “com.runmonster.runmonsterfree.upgradetopro”。僅使用 “upgradetopro” 將不會(huì)正常工作。

如果在productsRequest:didReceiveResponse:中response.products 為 nil,而你的產(chǎn)品id出現(xiàn)于 response.invalidProductIdentifers 數(shù)組中時(shí),那麼請(qǐng)做好心理準(zhǔn)備開(kāi)始一場(chǎng)徒勞的搜索戰(zhàn)吧。 StoreKit API沒(méi)有提供任何幫助,也沒(méi)有任何指示關(guān)于為什麼你的id是無(wú)效的。很可愛(ài),不是嗎?

SKProduct類提供了有關(guān)程序標(biāo)題和描述的本地化版本,但是價(jià)格則沒(méi)有本地化版本。下面是針對(duì)此疏忽提供的代碼:

  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.     NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; 
  6.     [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; 
  7.     [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 
  8.     [numberFormatter setLocale:self.priceLocale]; 
  9.     NSString *formattedString = [numberFormatter stringFromNumber:self.price]; 
  10.     [numberFormatter release]; 
  11.     return formattedString; 
  12. @end 

加入上述代碼,測(cè)試一下。你應(yīng)該在控制臺(tái)窗口中看見(jiàn)產(chǎn)品信息了。然而更大的可能是,你得到了一個(gè)無(wú)效的產(chǎn)品id。我下一篇文章將介紹怎樣對(duì)這個(gè)問(wèn)題進(jìn)行調(diào)試。但是,下面的步驟8有可能是阻礙你前進(jìn)的障礙。

8. 等待幾小時(shí)

遵循了上述所有步驟,但是你的產(chǎn)品仍然是無(wú)效的?你是否兩次,三次,四次不懈努力地確認(rèn)你是否遵循了上面提到的每個(gè)步驟?你是否已經(jīng)對(duì)網(wǎng)上IAP信息少得可憐而感到絕望?那麼,你應(yīng)該等待。你的產(chǎn)品要進(jìn)入iTunes Connect使得Apple準(zhǔn)備好沙箱環(huán)境需要一些時(shí)間。對(duì)于我而言,我是經(jīng)過(guò)了無(wú)數(shù)次產(chǎn)品無(wú)效錯(cuò)誤的絕望。而在24小時(shí)后,我沒(méi)有修改任何一行代碼, 但產(chǎn)品id變?yōu)橛行?。我認(rèn)為要使產(chǎn)品發(fā)佈到Apple的網(wǎng)絡(luò)系統(tǒng)需要幾個(gè)小時(shí)的時(shí)間,但如果你有時(shí)間的話,你可以像我一樣等上24個(gè)小時(shí)。

購(gòu)買產(chǎn)品

至此你應(yīng)該已經(jīng)成功地獲取了 SKProduct 描述。比較而言,支持購(gòu)買產(chǎn)品相對(duì)簡(jiǎn)單些。僅需下面三個(gè)步驟:

編寫(xiě)代碼支持事務(wù)(transaction)

在iTunes Connect中添加程序測(cè)試用戶

在設(shè)備中登錄你的 iTunes Store 帳號(hào)

購(gòu)買測(cè)試

我們從編寫(xiě)支持事務(wù)所需代碼開(kāi)始。

1)編寫(xiě)代碼支持事務(wù)

首先注意:你將負(fù)責(zé)開(kāi)發(fā)產(chǎn)品購(gòu)買的用戶界面。StoreKit 未提供任何與用戶界面相關(guān)的元素。如果你希望你的購(gòu)買用戶界面與App Store一樣,那麼你要自己完成。

下面所有代碼都是有關(guān)事務(wù)處理的后臺(tái)部分。這是一個(gè)單獨(dú)的類只有一條簡(jiǎn)單的API以供外部類(比如view controller)調(diào)用進(jìn)行購(gòu)買。如果你找到將其集成到你程序的購(gòu)買部分的方法,那麼我推薦你使用類似方桉。

首先,需要遵循 SKPaymentTransactionObserver 協(xié)議:

  1. // InAppPurchaseManager.h 
  2. // add a couple notifications sent out when the transaction completes 
  3. #define kInAppPurchaseManagerTransactionFailedNotification @"kInAppPurchaseManagerTransactionFailedNotification" 
  4. #define kInAppPurchaseManagerTransactionSucceededNotification @"kInAppPurchaseManagerTransactionSucceededNotification" 
  5. … 
  6. @interface InAppPurchaseManager : NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver> 
  7.     … 
  8. // public methods 
  9. - (void)loadStore; 
  10. - (BOOL)canMakePurchases; 
  11. - (void)purchaseProUpgrade; 
  12. @end 

上面我們定義了兩個(gè)新的notification,它們將作為購(gòu)買事務(wù)的結(jié)果被發(fā)送。在上例中我們?nèi)匀皇褂门c獲取產(chǎn)品描述同一個(gè)InAppPurchaseManager類。

  1. // InAppPurchaseManager.m 
  2. #define kInAppPurchaseProUpgradeProductId @"com.runmonster.runmonsterfree.upgradetopro" 
  3. … 
  4. #pragma - 
  5. #pragma Public methods 
  6. // 
  7. // call this method once on startup 
  8. // 
  9. - (void)loadStore 
  10.     // restarts any purchases if they were interrupted last time the app was open 
  11.     [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; 
  12.      
  13.     // get the product description (defined in early sections) 
  14.     [self requestProUpgradeProductData]; 
  15. // 
  16. // call this before making a purchase 
  17. // 
  18. - (BOOL)canMakePurchases 
  19.     return [SKPaymentQueue canMakePayments]; 
  20. // 
  21. // kick off the upgrade transaction 
  22. // 
  23. - (void)purchaseProUpgrade 
  24.     SKPayment *payment = [SKPayment paymentWithProductIdentifier:kInAppPurchaseProUpgradeProductId]; 
  25.     [[SKPaymentQueue defaultQueue] addPayment:payment]; 
  26. #pragma - 
  27. #pragma Purchase helpers 
  28. // 
  29. // saves a record of the transaction by storing the receipt to disk 
  30. // 
  31. - (void)recordTransaction:(SKPaymentTransaction *)transaction 
  32.     if ([transaction.payment.productIdentifier isEqualToString:kInAppPurchaseProUpgradeProductId]) 
  33.     { 
  34.         // save the transaction receipt to disk 
  35.         [[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"proUpgradeTransactionReceipt" ]; 
  36.         [[NSUserDefaults standardUserDefaults] synchronize]; 
  37.     } 
  38. // 
  39. // enable pro features 
  40. // 
  41. - (void)provideContent:(NSString *)productId 
  42.     if ([productId isEqualToString:kInAppPurchaseProUpgradeProductId]) 
  43.     { 
  44.         // enable the pro features 
  45.         [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isProUpgradePurchased" ]; 
  46.         [[NSUserDefaults standardUserDefaults] synchronize]; 
  47.     } 
  48. // 
  49. // removes the transaction from the queue and posts a notification with the transaction result 
  50. // 
  51. - (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful 
  52.     // remove the transaction from the payment queue. 
  53.     [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; 
  54.      
  55.     NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil]; 
  56.     if (wasSuccessful) 
  57.     { 
  58.         // send out a notification that we’ve finished the transaction 
  59.         [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionSucceededNotification object:self userInfo:userInfo]; 
  60.     } 
  61.     else 
  62.     { 
  63.         // send out a notification for the failed transaction 
  64.         [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo]; 
  65.     } 
  66. // 
  67. // called when the transaction was successful 
  68. // 
  69. - (void)completeTransaction:(SKPaymentTransaction *)transaction 
  70.     [self recordTransaction:transaction]; 
  71.     [self provideContent:transaction.payment.productIdentifier]; 
  72.     [self finishTransaction:transaction wasSuccessful:YES]; 
  73. // 
  74. // called when a transaction has been restored and and successfully completed 
  75. // 
  76. - (void)restoreTransaction:(SKPaymentTransaction *)transaction 
  77.     [self recordTransaction:transaction.originalTransaction]; 
  78.     [self provideContent:transaction.originalTransaction.payment.productIdentifier]; 
  79.     [self finishTransaction:transaction wasSuccessful:YES]; 
  80. // 
  81. // called when a transaction has failed 
  82. // 
  83. - (void)failedTransaction:(SKPaymentTransaction *)transaction 
  84.     if (transaction.error.code != SKErrorPaymentCancelled) 
  85.     { 
  86.         // error! 
  87.         [self finishTransaction:transaction wasSuccessful:NO]; 
  88.     } 
  89.     else 
  90.     { 
  91.         // this is fine, the user just cancelled, so don’t notify 
  92.         [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; 
  93.     } 
  94. #pragma mark - 
  95. #pragma mark SKPaymentTransactionObserver methods 
  96. // 
  97. // called when the transaction status is updated 
  98. // 
  99. - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions 
  100.     for (SKPaymentTransaction *transaction in transactions) 
  101.     { 
  102.         switch (transaction.transactionState) 
  103.         { 
  104.             case SKPaymentTransactionStatePurchased: 
  105.                 [self completeTransaction:transaction]; 
  106.                 break
  107.             case SKPaymentTransactionStateFailed: 
  108.                 [self failedTransaction:transaction]; 
  109.                 break
  110.             case SKPaymentTransactionStateRestored: 
  111.                 [self restoreTransaction:transaction]; 
  112.                 break
  113.             default
  114.                 break
  115.         } 
  116.     } 

要測(cè)試上面的新代碼,你還需要編寫(xiě)調(diào)用 loadStore, canMakePurchases 以及 purchaseProUpgrade 方法的代碼。

有關(guān)上述代碼的詳細(xì)解釋,請(qǐng)參考官方 In App Purchase Programming Guide (IAP編程指南)

上述代碼有幾個(gè)部分是針對(duì)我的程序的。例如,在 provideContent:中,NSUserDefaults 中的@”isProUpgradePurchased” BOOL 字段被設(shè)定為 YES。程序的其他部分將檢查此BOOL值以確定是否需要啟動(dòng)專業(yè)版功能。如果你正好也要實(shí)現(xiàn)免費(fèi)升級(jí)專業(yè)版的功能,那麼你可以使用同樣的方法。

2)添加測(cè)試用戶

為測(cè)試上述代碼,你需要在 iTunes Connect 中創(chuàng)建測(cè)試用戶以對(duì)IAP功能進(jìn)行測(cè)試。你可以使用測(cè)試帳號(hào)購(gòu)買產(chǎn)品而不被Apple收取費(fèi)用。

按以下步驟創(chuàng)建測(cè)試用戶:

登錄到 http://developer.apple.com/iphone

進(jìn)入 iTunes Connect

選擇iTunes Connect首頁(yè)中的 “Manage Users”

選擇 “In App Purchase Test User”

選擇 “Add New User”

填入用戶信息. 所有信息都不必是合法的。建議使用虛假簡(jiǎn)短的email地址及簡(jiǎn)短的密碼。

選擇 “Save”

測(cè)試時(shí)你需要輸入這些email地址和密碼。

3)在你的設(shè)備中退出登錄

在進(jìn)行程序購(gòu)買功能測(cè)試前,你必須在你的設(shè)備中退出iTunes Store。遵循以下步驟:

打開(kāi)Settings App

點(diǎn)擊 “Store” 行

點(diǎn)擊 “Sign Out”

4)購(gòu)買測(cè)試

現(xiàn)在,終于可以開(kāi)始進(jìn)行IAP功能的測(cè)試了。測(cè)試很簡(jiǎn)單:

運(yùn)行你設(shè)備中的程序

進(jìn)行購(gòu)買

當(dāng)程序提示輸入用戶名和密碼時(shí),輸入?yún)?shù)用戶的信息

如果你使用同一賬戶進(jìn)行購(gòu)買時(shí),系統(tǒng)將提示你已經(jīng)購(gòu)買了此產(chǎn)品。按“Yes”就可以再次下載此產(chǎn)品。

總結(jié)

實(shí)現(xiàn)IAP功能比想象的要復(fù)雜許多。我可是經(jīng)過(guò)無(wú)數(shù)痛苦的經(jīng)歷才完成我的程序。希望能夠幫助其他開(kāi)發(fā)者減輕他們的痛苦。

責(zé)任編輯:閆佳明 來(lái)源: cocoachina
相關(guān)推薦

2013-09-05 15:12:09

iOS應(yīng)用內(nèi)置付費(fèi)In-App Purc

2013-09-09 13:57:27

iOS應(yīng)用內(nèi)置付費(fèi)In-App Purc

2013-09-09 14:26:25

iOS應(yīng)用內(nèi)置付費(fèi)In-App Purc

2009-02-12 10:12:00

NAT配置

2009-02-10 09:47:00

應(yīng)用程序訪問(wèn)權(quán)限

2014-12-19 12:57:57

APP推廣運(yùn)營(yíng)

2013-05-22 10:00:30

iOSWeb Appicon

2013-09-09 16:11:16

iOS應(yīng)用內(nèi)置付費(fèi)IAP總結(jié)

2023-10-13 19:42:00

2011-03-28 10:12:44

FreeBSDnagios

2010-07-12 09:42:06

FreeBSD 7.0nagios安裝

2010-11-18 23:24:42

云遷移

2010-04-23 14:04:23

Oracle日期操作

2024-05-07 09:01:21

Queue 模塊Python線程安全隊(duì)列

2013-04-15 10:48:16

Xcode ARC詳解iOS ARC使用

2013-06-08 11:13:00

Android開(kāi)發(fā)XML解析

2013-09-09 15:49:44

iOS應(yīng)用內(nèi)置付費(fèi)IAP設(shè)置總結(jié)

2023-11-06 08:14:51

Go語(yǔ)言Context

2011-05-17 10:19:40

EMC Celerra

2009-02-20 11:43:22

UNIXfish全攻略
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

毛片在线网站| 国产在线一区二区三区| 狼狼综合久久久久综合网| 美国一级黄色录像| 日本人妻丰满熟妇久久久久久| 日韩在线综合| 欧美性猛交xxxx久久久| 风间由美一区二区三区| 久久久久人妻一区精品色| 国偷自产一区二区免费视频| 不卡视频免费播放| 不卡在线观看av| 日韩精品――中文字幕| 国产尤物av一区二区三区| 人与嘼交av免费| av资源网在线播放| 久久国产精品亚洲人一区二区三区| 欧美另类变人与禽xxxxx| 欧洲精品久久| 青青草视频在线观看免费| 欧美黑人做爰爽爽爽| 亚洲自拍另类综合| 成人羞羞视频免费| 欧美高清69hd| 欧美精品色图| 欧美日韩视频第一区| 日韩欧美第二区在线观看| 欧美亚洲另类小说| 成人亚洲一区二区| 欧美日韩精品三区| 综合久久国产| 国产日韩欧美视频在线观看| 亚洲情侣在线| 精品久久国产老人久久综合| av在线观看地址| 婷婷综合激情网| 久久www成人_看片免费不卡| 国产一区二区三区免费视频| 日本中文字幕高清| 午夜伦理在线| 国产精品一区专区| 97视频在线观看成人| 中文字幕一区二区人妻在线不卡| 亚洲成人va| 亚洲日本丝袜连裤袜办公室| 69174成人网| 日本三级视频在线| 国产一区亚洲| 亚洲情综合五月天| 手机av在线免费| 污网站在线免费看| 久久日韩粉嫩一区二区三区| 国产精品一区二区三区久久久| 波多野结衣久久久久| 97超碰成人| 日韩欧美国产成人| 人妻久久久一区二区三区| 狠狠v欧美ⅴ日韩v亚洲v大胸| 久久99热狠狠色一区二区| 久久999免费视频| 青青草成人免费视频| 久久精品黄色| 午夜a成v人精品| 亚洲午夜精品一区二区三区| 亚洲乱色熟女一区二区三区| 午夜精品影院| 国产亚洲精品久久久久动| 最近中文字幕在线mv视频在线| 中文字幕综合| 欧美天堂在线观看| 国产l精品国产亚洲区久久| 久操视频在线观看| 久久网这里都是精品| 欧美精品一区二区三区在线四季 | 一区二区国产视频| 大胆欧美熟妇xx| 蜜桃视频在线免费| 国产精品99久久久| 国产精品美女999| 亚洲精品国产精品乱码| 中文字幕一区二区三区在线视频| 久久av资源网站| 精品人妻一区二区三区蜜桃视频 | 日韩视频精品| 免费av网站在线观看| 成人av片在线观看| 精品日韩美女| 国产视频一二三四区| 国产精品一区二区视频| 国模精品娜娜一二三区| 国产精品久久久久久久成人午夜| 亚洲综合日本| 欧美精品www| 亚洲二区在线播放| 大色综合视频网站在线播放| 久久精品视频在线观看| 亚洲精品国产一区黑色丝袜| 欧美日韩一区二区三区视频播放| 理论片在线不卡免费观看| 一级免费在线观看| 免费高清在线视频一区·| 全球成人中文在线| 日韩手机在线观看| 日本女优在线视频一区二区| 欧美孕妇毛茸茸xxxx| 一区二区三区免费高清视频| 真实国产乱子伦精品一区二区三区| 欧美高清videos高潮hd| 黄色一级片中国| 天天做天天爱综合| 久久精品视频导航| 九九热在线免费观看| 一本久道综合久久精品| 97国产精品免费视频| 中文永久免费观看| 蜜臀va亚洲va欧美va天堂 | 91片黄在线观看喷潮| 日韩电影在线一区二区三区| 欧美在线性爱视频 | 国产suv一区二区三区| 亚洲免费影视| 国产精品18毛片一区二区| 中文字幕在线观看日本| 亚洲国产精品v| 偷拍视频一区二区| 粉嫩一区二区三区国产精品| 中文字幕欧美日韩一区| 青青青青草视频| 天堂√中文最新版在线| 色综合久久综合中文综合网| 欧美黄色免费影院| 素人啪啪色综合| 日韩av中文字幕在线| 国产吞精囗交久久久| 欧美日韩三级电影在线| 88xx成人精品| 亚洲色成人www永久网站| 成人综合婷婷国产精品久久| 国产精品一区二区三区免费观看| 午夜在线视频观看| 亚洲精品国产一区二区精华液| 欧美日韩视频免费| 久久精品九色| 日韩国产在线看| 久久国产精品波多野结衣| 国产亚洲成人一区| 国产免费一区二区三区香蕉精| 欧美理论在线观看| 狠狠色狠色综合曰曰| 波多野结衣xxxx| 91成人在线精品视频| 亚洲欧美第一页| 朝桐光av在线| 国产呦精品一区二区三区网站| 国产一区免费| 91桃色在线| 精品国产乱子伦一区| 91狠狠综合久久久久久| 日本午夜一本久久久综合| 日韩av在线电影观看| 免费成人动漫| 一本色道久久88综合日韩精品| 男人的天堂久久久| 国产成人精品一区二 | 国产欧美午夜| 久久久久se| 九色porny丨首页在线| 欧美日韩成人在线| 色在线观看视频| 爽好多水快深点欧美视频| ts人妖另类在线| 春暖花开成人亚洲区| 亚洲国产视频网站| 欧美日韩精品区别| 亚洲精品蜜桃乱晃| 久久6免费高清热精品| 高清国产mv在线观看| 欧美性xxxxxxxxx| 影音先锋男人在线| 国产精品资源在线看| 日本a视频在线观看| 欧美人与牛zoz0性行为| 97精品国产97久久久久久春色| 天天干天天草天天射| 亚洲欧美视频在线观看视频| 欧美日韩一区二区区别是什么 | 国产真实精品久久二三区| 一本色道久久88亚洲精品综合| 久久久成人av毛片免费观看| 久久精品电影网站| 国模私拍视频在线| 欧美午夜免费电影| 美女脱光内衣内裤| 日韩午夜黄色| 亚洲免费不卡| 电影在线观看一区二区| 欧美猛交ⅹxxx乱大交视频| 天堂在线视频网站| 欧美丰满美乳xxx高潮www| 国产精品不卡av| 成人午夜碰碰视频| 少妇激情一区二区三区| 午夜精品av| 午夜午夜精品一区二区三区文| 欧美在线在线| 久热精品在线视频| 日韩美女一级视频| 午夜国产精品一区| 少妇高潮在线观看| 91偷拍与自偷拍精品| 97国产精东麻豆人妻电影| 99视频精品全部免费在线视频| 国产a一区二区| 日本久久二区| 久久国产精品久久久久久| 国产绿帽一区二区三区| 欧美性20hd另类| 日韩欧美中文字幕视频| 国产午夜精品理论片a级大结局| 日本三级免费观看| 欧美亚韩一区| 亚洲国产精品影视| 亚洲天堂中文字幕在线观看| 国产精品欧美一区二区| 一本大道色婷婷在线| 九色91av视频| 成人日韩欧美| 精品国产一区二区亚洲人成毛片| 中文字幕+乱码+中文乱码www| 精品久久久久久久久国产字幕| 好吊日免费视频| 福利一区在线观看| 黑人糟蹋人妻hd中文字幕| 国内精品福利| 日本中文字幕一级片| 久久精品欧美一区| 国产精品免费一区二区三区在线观看| 欧美影视资讯| 国产精品成人免费电影| 毛片免费不卡| 色多多国产成人永久免费网站| 国产婷婷在线视频| 精品视频1区2区| 日本三级一区二区三区| 91国偷自产一区二区三区观看| 黄色一级片一级片| 国产欧美日韩综合| 免费欧美一级片| 国产精品五区| 尤物av无码色av无码| 禁断一区二区三区在线| 91青青草免费观看| 经典三级久久| 99久热re在线精品996热视频| 电影一区二区三区久久免费观看| 久久理论片午夜琪琪电影网| 男人的天堂av高清在线| 日韩高清免费观看| 深夜福利在线看| 欧美精品在线观看一区二区| 一级二级三级视频| 亚洲成人你懂的| 亚洲另类欧美日韩| 色婷婷亚洲精品| 中文字幕欧美人妻精品| 欧美乱妇23p| 亚洲黄色小说网址| 日韩av最新在线| 国产美女视频一区二区三区 | 在线观看区一区二| 欧美三级免费看| 亚洲无人区一区| 羞羞在线观看视频| 亚洲伦理在线精品| 美国美女黄色片| 最近日韩中文字幕| 欧美黄色一级生活片| 中文字幕中文在线不卡住| 黄色正能量网站| 中文子幕无线码一区tr | 精品福利在线观看| 国产精品久久久久久久久久精爆| 亚洲尤物在线视频观看| 日韩av大片在线观看| 欧洲精品中文字幕| www久久久com| 7799精品视频| 中文字幕在线观看第二页| 5月丁香婷婷综合| 无码国产精品96久久久久| 在线播放精品一区二区三区| av观看在线| 久久综合久久美利坚合众国| 国产乱码在线| 欧美国产精品va在线观看| 手机av在线| 成人h猎奇视频网站| www.久久.com| 国产精品一区在线播放| 欧美综合视频| 丁香色欲久久久久久综合网| 日韩精品亚洲专区| 中文字幕一二三区| 日本一区二区三区国色天香| 久久久久久福利| 91传媒视频在线播放| 成人av一区二区三区在线观看| 亚洲欧洲一区二区三区久久| 香蕉久久aⅴ一区二区三区| 日本久久精品视频| 欧美中文字幕精在线不卡| 日本欧美中文字幕| 亚洲大奶少妇| 亚洲精品视频一二三| 国产农村妇女精品一二区| 天天操夜夜操很很操| 国产精品亚洲第一区在线暖暖韩国 | 午夜精品一区二区在线观看| 99在线精品视频在线观看| 日本黄色www| 中文字幕制服丝袜成人av | 欧美风情第一页| 一本在线高清不卡dvd| 蜜桃av噜噜一区二区三区麻豆| 久久久国产精品x99av| 影音成人av| 日本不卡一二三区| 亚洲欧美日韩一区在线观看| 女性生殖扒开酷刑vk| 91在线一区二区| 粉嫩精品久久99综合一区| 精品免费在线视频| 国产 日韩 欧美 精品| 欧美人在线视频| 久久一级大片| 中文字幕中文字幕一区三区| 日本不卡免费在线视频| 亚洲自拍偷拍一区二区| 欧美日韩国产丝袜另类| 色窝窝无码一区二区三区成人网站 | 国产精品扒开腿做爽爽| 欧美日韩国产影院| 四虎精品成人影院观看地址| 97久久精品国产| 久久a爱视频| 日韩欧美精品一区二区| 久久资源在线| 久久久久久久久久久久| 一本久久a久久精品亚洲| 青春草在线观看| 国产成人一区三区| 日本一区精品视频| 糖心vlog在线免费观看| 亚洲专区在线| 日韩av在线看免费观看| 色一情一伦一子一伦一区| 青青草免费在线| 国产精品xxxxx| 日韩毛片视频| 加勒比av中文字幕| 亚洲免费三区一区二区| 黄色www视频| 庆余年2免费日韩剧观看大牛| 国产一区二区三区网| www.com操| 一区二区三区资源| 无码精品一区二区三区在线| 青青青国产精品一区二区| 日韩av自拍| 在线观看免费看片| 欧美日韩另类在线| av中文天堂在线| 91免费高清视频| 国产调教一区二区三区| 鲁一鲁一鲁一鲁一av| 亚洲蜜臀av乱码久久精品| 全国男人的天堂网| 国产成人亚洲综合| 91精品国产视频| 中文成人无字幕乱码精品区| 一区二区三区在线看| 天天综合天天综合| 国产美女精彩久久| 亚洲激情一区| 国产午夜在线一区二区三区| 自拍视频在线观看一区二区| 亚洲av综合色区无码一区爱av | 国产又爽又黄ai换脸| 成人在线综合网站| 波多野结衣绝顶大高潮| 久久成人一区二区| 日韩三级av| 免费毛片网站在线观看| 亚洲国产精品成人综合色在线婷婷 | 日韩一卡二卡三卡| 亚洲成a人v欧美综合天堂麻豆| 91久久国产综合久久蜜月精品 | 免费看污污网站| 久久久国产综合精品女国产盗摄| 国产亚洲精品久久久久久打不开|