内购流程

内购完整详细的流程,网站如下:

http://blog.sina.com.cn/s/blog_6f5fd9ba0100ug9n.html

具体内容

第一印象覺得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,按如下步驟創建一個:

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

(2)填寫下列信息:

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

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

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

(3)按 “Save”

(4)按 App ID旁的“Configure” 鏈接

(5)選取 “Enable In App Purchase”選擇框

(6)按“Done”

2. 創建一個新的Provisioning Profile文件

在創建了新的App ID后,你需要生成一個指向這個App ID的新provisioning profile。

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

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

2確保你處於Development 標籤下, 按下右上角的 “New Profile”

3填入所需信息並指向你剛創建的唯一的App ID

4如果你在Actions條目下看到 “Pending”,那麼請按下“Development”標籤標題進行刷新

5點擊 “Download” 下載新的profile文件

6將profile文件拖入到Dock中Xcode圖標上進行安裝

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

1)在Xcode中, 選擇 Window > Organizer

2)選擇左邊 “Provisioning Profiles” 分類

3)Ctrl-按下profile > Reveal in Finder

4)將新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 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”

7. 編寫代碼

下面我們開始編寫代碼對剛加入到iTunes Connect中的產品信息進行提取。我訪問產品數據,我們需要使用 StoreKit framework。

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

1.添加 StoreKit framework 到你的項目中。

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



上面代碼有幾點需要注意:指定產品id時,你必須使用完整產品id。例如,上例中使用 “com.runmonster.runmonsterfree.upgradetopro”。僅使用 “upgradetopro” 將不會正常工作。如果在productsRequest:didReceiveResponse:中response.products 為 nil,而你的產品id出現於 response.invalidProductIdentifers 數組中時,那麼請做好心理準備開始一場徒勞的搜索戰吧。 StoreKit API沒有提供任何幫助,也沒有任何指示關於為什麼你的id是無效的。很可愛,不是嗎?SKProduct類提供了有關程序標題和描述的本地化版本,但是價格則沒有本地化版本。下面是針對此疏忽提供的代碼:12345678910// SKProduct+LocalizedPrice.h#import#import@interface SKProduct (LocalizedPrice)

@property (nonatomic, readonly) NSString *localizedPrice;

@end

// SKProduct+LocalizedPrice.m

#import "SKProduct+LocalizedPrice.h"

@implementation SKProduct (LocalizedPrice)

- (NSString *)localizedPrice

{

NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];

[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];

[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

[numberFormatter setLocale:self.priceLocale];

NSString *formattedString = [numberFormatter stringFromNumber:self.price];

[numberFormatter release];

return formattedString;

}

@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 協議:12345678910111213141516171819// InAppPurchaseManager.h// add a couple notifications sent out when the transaction completes#define kInAppPurchaseManagerTransactionFailedNotification @"kInAppPurchaseManagerTransactionFailedNotification"#define kInAppPurchaseManagerTransactionSucceededNotification @"kInAppPurchaseManagerTransactionSucceededNotification"…@interface InAppPurchaseManager : NSObject{

}

// public methods

- (void)loadStore;

- (BOOL)canMakePurchases;

- (void)purchaseProUpgrade;

@end

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

// InAppPurchaseManager.m

#define kInAppPurchaseProUpgradeProductId @"com.runmonster.runmonsterfree.upgradetopro"

#pragma -

#pragma Public methods

//

// call this method once on startup

//

- (void)loadStore

{

// restarts any purchases if they were interrupted last time the app was open

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

// get the product description (defined in early sections)

[self requestProUpgradeProductData];

}

//

// call this before making a purchase

//

- (BOOL)canMakePurchases

{

return [SKPaymentQueue canMakePayments];

}

//

// kick off the upgrade transaction

//

- (void)purchaseProUpgrade

{

SKPayment *payment = [SKPayment paymentWithProductIdentifier:kInAppPurchaseProUpgradeProductId];

[[SKPaymentQueue defaultQueue] addPayment:payment];

}

#pragma -

#pragma Purchase helpers

//

// saves a record of the transaction by storing the receipt to disk

//

- (void)recordTransaction:(SKPaymentTransaction *)transaction

{

if ([transaction.payment.productIdentifier isEqualToString:kInAppPurchaseProUpgradeProductId])

{

// save the transaction receipt to disk

[[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"proUpgradeTransactionReceipt" ];

[[NSUserDefaults standardUserDefaults] synchronize];

}

}

//

// enable pro features

//

- (void)provideContent:(NSString *)productId

{

if ([productId isEqualToString:kInAppPurchaseProUpgradeProductId])

{

// enable the pro features

[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isProUpgradePurchased" ];

[[NSUserDefaults standardUserDefaults] synchronize];

}

}

//

// removes the transaction from the queue and posts a notification with the transaction result

//

- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful

{

// remove the transaction from the payment queue.

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil];

if (wasSuccessful)

{

// send out a notification that we’ve finished the transaction

[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionSucceededNotification object:self userInfo:userInfo];

}

else

{

// send out a notification for the failed transaction

[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];

}

}

//

// called when the transaction was successful

//

- (void)completeTransaction:(SKPaymentTransaction *)transaction

{

[self recordTransaction:transaction];

[self provideContent:transaction.payment.productIdentifier];

[self finishTransaction:transaction wasSuccessful:YES];

}

//

// called when a transaction has been restored and and successfully completed

//

- (void)restoreTransaction:(SKPaymentTransaction *)transaction

{

[self recordTransaction:transaction.originalTransaction];

[self provideContent:transaction.originalTransaction.payment.productIdentifier];

[self finishTransaction:transaction wasSuccessful:YES];

}

//

// called when a transaction has failed

//

- (void)failedTransaction:(SKPaymentTransaction *)transaction

{

if (transaction.error.code != SKErrorPaymentCancelled)

{

// error!

[self finishTransaction:transaction wasSuccessful:NO];

}

else

{

// this is fine, the user just cancelled, so don’t notify

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

}

#pragma mark -

#pragma mark SKPaymentTransactionObserver methods

//

// called when the transaction status is updated

//

- (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];

break;

default:

break;

}

}

}

要測試上面的新代碼,你還需要編寫調用 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”就可以再次下載此產品。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容