參考鏈接
iOS開發(fā)之內(nèi)購-AppStore
iOS App提交指南(二)-協(xié)議、稅務(wù)和銀行業(yè)務(wù)
iOS應(yīng)用內(nèi)付費(fèi)(IAP)開發(fā)步驟列表
一、創(chuàng)建App
首先你需要登錄 App的ItunesConnection,你會(huì)看到如下界面
簡單的介紹一下這幾個(gè)選項(xiàng)
- 我的App主要用于管理自己的App應(yīng)用,例如編輯資料,上架,下架等。
- 銷售和趨勢主要是來查看App在各個(gè)平臺(tái)的下載量,收入等方面數(shù)據(jù),里面有曲線圖等圖文結(jié)合的方式給我們參考。
- 付款和財(cái)務(wù)報(bào)告顯示的是你的收入以及付款等相關(guān)信息。
- iAd主要是跟廣告有關(guān),開發(fā)者可以登錄到Workbench,通過iAd對應(yīng)用的廣告進(jìn)行控制。
- 用戶和職能用于生成相應(yīng)賬號(hào),例如蘋果沙河測試賬號(hào)。
- 協(xié)議,稅務(wù)和銀行業(yè)務(wù)則是你銀行相關(guān)賬戶的信息設(shè)置。
在這里我們選擇第一個(gè)選項(xiàng),我的App,然后點(diǎn)擊左上角的加號(hào),新建一個(gè)用來測試用的App。
點(diǎn)新建 App,會(huì)出現(xiàn)新建窗口;
在這里有幾個(gè)需要填寫的地方,名稱自己取,平臺(tái)IOS,語言選擇了簡體中文,套裝ID也就是你的Bundle Identifier,需要你在Certificates頁面 申請BundleID,SKU可以理解為用戶看一看到的唯一標(biāo)示,會(huì)體現(xiàn)在你的app的App Store的鏈接中。
申請BundleID
打開Certificates頁面,在左側(cè)選擇Identifiers,并點(diǎn)擊加號(hào),申請一個(gè)新的Identifiers。

在這里Name可以隨意填寫,我填寫的是TestAppStroeTestDemo,而用來使用的BundleID,我們在這里必須選擇第一個(gè)選項(xiàng)唯一的,不用選擇通配。在下面的選項(xiàng)中, 我們只需要勾選一個(gè) Apple Pay即可,其他選項(xiàng)看自己需求,我在這里只選擇了它。

之后我們回到創(chuàng)建App,選擇好自己剛創(chuàng)建的 BundleID ,填寫SKU, SKU是你App的專用ID,我在這里隨意填寫,直接復(fù)制了App名。點(diǎn)擊創(chuàng)建,我們的測試App則創(chuàng)建成功。
二、協(xié)議、稅務(wù)和銀行業(yè)務(wù)
進(jìn)入?yún)f(xié)議、稅務(wù)和銀行業(yè)務(wù)頁面

進(jìn)入?yún)f(xié)議、稅務(wù)和銀行業(yè)務(wù)頁面后,會(huì)有3種合同類型,如果你之前沒有主動(dòng)申請過去合同,那么一般你現(xiàn)在激活的合同只有iOS Free Application一種。
頁面內(nèi)容分為兩塊:
- Request Contracts(申請合同)
- Contracts In Effect(已生效合同)。
合同類型分為3種:
- iOS Free Application(免費(fèi)應(yīng)用合同)
- iOS Paid Application(付費(fèi)應(yīng)用合同)
- iAd App NetNetwork(廣告合同)
筆者暫時(shí)只申請過付費(fèi)應(yīng)用合同,所以下面主要講一下付費(fèi)應(yīng)用合同的申請流程。

當(dāng)我們點(diǎn)擊申請iOS Paid Application合同后,該合同的狀態(tài)會(huì)變成如下的樣子,我們可以看到其中Status為Pending Tax, Bank, Contact。意思是聯(lián)系方式、銀行和稅務(wù)信息沒有填寫。

1、填寫聯(lián)系方式
我們點(diǎn)擊Contact Info下方的Set Up按鈕可以進(jìn)入聯(lián)系方式填寫頁面,如下圖:

如果你沒有添加過聯(lián)系人,你需要通過Add New Contact按鈕來添加一個(gè)新的聯(lián)系人。然后指定聯(lián)系人的職務(wù),職務(wù)如下:
- Senior Management:高管
- Financial:財(cái)務(wù)
- Technical:技術(shù)支持
- Legal:法務(wù)
- Marketing:市場推廣
如果你是獨(dú)立開發(fā)者,可以全部填你自己一個(gè)人。
2、填寫銀行卡信息
我們點(diǎn)擊Bank Info下方的Set Up按鈕可以進(jìn)入聯(lián)系方式填寫頁面,如下圖:

選擇你的銀行賬戶,如果你沒有,點(diǎn)擊旁邊的Add Bank Account添加一個(gè)賬戶。
下面是添加一個(gè)賬戶的流程。
2-1、選擇銀行所在的國家

2-2、填寫銀行CNAPS Code
如果你不知道CNAPS Code是多少,可以點(diǎn)擊Look up Transit Number來查詢,查詢時(shí)會(huì)根據(jù)3個(gè)關(guān)鍵信息來查詢,如下:
- Bank Name:銀行的英文名稱(不能是拼音)
- City:銀行所在的城市英文名稱(中國的城市用拼音)
- Postal Code:郵編
-
然后在下面就會(huì)出來備選的銀行,選擇正確的銀行后,點(diǎn)擊next,進(jìn)入下一步。
填寫銀行CNAPS Code
銀行信息
2-3、確認(rèn)銀行信息

2-4、填寫銀行賬號(hào)信息
- Bank Account Number:銀行賬號(hào)
- Confirm Bank Account Number:再次輸入銀行賬號(hào)
- Account Holder Name:持卡人姓名,中文名用拼寫,名在前,姓在后
-
Bank Account Currency:貨幣類型,一般國內(nèi)的開發(fā)者選擇CNY
填寫銀行賬號(hào)信息
2-5、確認(rèn)所有信息

3、填寫稅務(wù)信息
稅務(wù)信息這一塊了解不是很多,不過因?yàn)槭菄鴥?nèi)開發(fā)者,可以不用太費(fèi)心,稅務(wù)信息分3種:
- U.S Tax Forms: 美國稅務(wù)
- Australia Tax Forms:澳大利亞稅務(wù)
-
Canada Tax Forms: 加拿大稅務(wù)
填寫稅務(wù)信息
筆者選擇的是U.S Tax Forms,選擇后會(huì)問你兩個(gè)問題,第一個(gè)問題如下:詢問你是否是美國居民,有沒有美國伙伴關(guān)系或者美國公司,如果沒有直接選擇No。
是否美國居民
接下來第二個(gè)問題如下:詢問你有沒有在美國的商業(yè)性活動(dòng),沒有也直接選No。
是否在美國的商業(yè)性活動(dòng)
然后填寫你的稅務(wù)信息,包括以下幾點(diǎn):
- Individual or Organization Name:個(gè)人或者組織名稱
- Country of incorporation: 所在國家
- Type of Beneficial Owner:受益方式,獨(dú)立開發(fā)者選個(gè)人
- Permanent Residence:居住地址
- Mailing address:郵寄地址
- Name of Person Making this Declaration:聲明人
- Title:頭銜
填寫完這些信息后就可以提交了

4、等待審核
當(dāng)你填寫完所有資料后,合同狀態(tài)就會(huì)變成Processing,筆者凌晨1點(diǎn)左右提交,下午就通過了。

三、添加內(nèi)購買項(xiàng)目
App創(chuàng)建好之后,我們打開創(chuàng)建的App,在左上角選擇功能,會(huì)看到左側(cè)的App 內(nèi)購買項(xiàng)目。我們點(diǎn)擊右下角的加號(hào),為App添加內(nèi)購項(xiàng)目。
虛擬物品添加分為如下幾種:
- 消耗品(Consumable products):比如游戲內(nèi)金幣等。
- 不可消耗品(Non-consumable products):簡單來說就是一次購買,終身可用(用戶可隨時(shí)從App Store restore)。
- 自動(dòng)更新訂閱品(Auto-renewablesubscriptions):和不可消耗品的不同點(diǎn)是有失效時(shí)間。比如一整年的付費(fèi)周刊。在這種模式下,開發(fā)者定期投遞內(nèi)容,用戶在訂閱期內(nèi)隨時(shí)可以訪問這些內(nèi)容。訂閱快要過期時(shí),系統(tǒng)將自動(dòng)更新訂閱(如果用戶同意)。
- 非自動(dòng)更新訂閱品(Non-renewablesubscriptions):一般使用場景是從用戶從IAP購買后,購買信息存放在自己的開發(fā)者服務(wù)器上。失效日期/可用是由開發(fā)者服務(wù)器自行控制的,而非由AppStore控制,這一點(diǎn)與自動(dòng)更新訂閱品有差異。
- 免費(fèi)訂閱品(Free subscriptions):在Newsstand中放置免費(fèi)訂閱的一種方式。免費(fèi)訂閱永不過期。只能用于Newsstand-enabled apps。
類型2、3、5都是以Apple ID為粒度的。比如小張有三個(gè)iPad,有一個(gè)Apple ID購買了不可消耗品,則三個(gè)iPad上都可以使用。
類型1、4一般來說則是現(xiàn)買現(xiàn)用。如果開發(fā)者自己想做更多控制,一般選4
之后我們會(huì)看到類型的選項(xiàng),如下圖
官方的注釋寫的很清楚了,只在這里簡單的說下前兩種:
- 消耗型項(xiàng)目 就像你玩游戲需要買金幣,買鉆石等,只要花錢就可以無限次的購買
-
非消耗型項(xiàng)目 就像你在App Store購買App,買了一次之后就不用再買第二次,你擁有永久使用權(quán)。
在我們的app中,是充值會(huì)員,所以選擇的是第一種,可以無限次購買。
填寫信息
這里有幾個(gè)選項(xiàng),需要填寫商品名稱,產(chǎn)品ID以及價(jià)格等級(jí),簡單說明一下
- 商品名稱根據(jù)你的消費(fèi)道具的實(shí)際意義來說明,比如“100顆寶石”,“100金幣”等。
- 產(chǎn)品ID是比較重要的,由項(xiàng)目自定義,只要唯一即可,因?yàn)闇y試,我在這里隨便填寫的123,在實(shí)際應(yīng)用中,一定要認(rèn)真填寫。
-
價(jià)格等級(jí)的話“查看價(jià)格表”中有對應(yīng)的說明,可以對照著表中每個(gè)國家的貨幣價(jià)格與等級(jí)來選擇
接下來是語言選擇,和上傳快照如下圖
內(nèi)置購買詳細(xì)信息
點(diǎn)擊添加語言,填寫名稱和描述,這里我們依然選擇簡體中文,如下
添加語言
審核備注,根據(jù)實(shí)際情況填寫,可以不填。而下面的屏幕快照,則是商品圖片,以像素為單位,最低尺寸為321,390,尺寸需求如下圖,上傳即可。
審核備注
到這里為止, 我們的內(nèi)購項(xiàng)目則添加完成。接下來則是測試階段了。
四、申請沙盒測試賬號(hào)(用來測試購買項(xiàng)目)
這個(gè)賬號(hào),是利用蘋果的沙盒測試環(huán)境來模擬AppStore的購買流程,你肯定不會(huì)想要用真實(shí)RMB去購買測試吧?
首先我們回到iTunes Connect中,在這里我們選擇用戶和職能。
然后在上面的第三個(gè)選項(xiàng)沙箱技術(shù)測試員中點(diǎn)擊加號(hào),添加測試員。
在信息填寫頁面只簡單說兩句。
所有信息都可以隨意填寫,不用管是否真實(shí)。
App Store地區(qū)選擇,一定要選對,它對應(yīng)的是你創(chuàng)建的App的地區(qū), 你App是中國的話, 在這里我們依然選擇中國。
此賬號(hào)只能用來測試,不要在正式的appstore上使用
填寫完畢,點(diǎn)擊保存后,我們則生成一個(gè)測試賬號(hào),當(dāng)然這個(gè)賬號(hào)是可以隨時(shí)刪除和添加的。
五、大致流程
IAP流程分為兩種,一種是直接使用Apple的服務(wù)器進(jìn)行購買和驗(yàn)證,另一種就是自己假設(shè)服務(wù)器進(jìn)行驗(yàn)證。由于國內(nèi)網(wǎng)絡(luò)連接Apple服務(wù)器驗(yàn)證非常慢,而且也為了防止黑客偽造購買憑證,通用做法是自己架設(shè)服務(wù)器進(jìn)行驗(yàn)證。
下面我們通過圖來看看兩種方式的差別:
5.1、使用Apple服務(wù)器

5.2、自己架設(shè)服務(wù)器

簡單說下第二中情況的流程:
- 用戶進(jìn)入購買虛擬物品頁面,App從后臺(tái)服務(wù)器獲取產(chǎn)品列表然后顯示給用戶
- 用戶點(diǎn)擊購買購買某一個(gè)虛擬物品,APP就發(fā)送該虛擬物品的productionIdentifier到Apple服務(wù)器
- Apple服務(wù)器根據(jù)APP發(fā)送過來的productionIdentifier返回相應(yīng)的物品的信息(描述,價(jià)格等)
- 用戶點(diǎn)擊確認(rèn)鍵購買該物品,購買請求發(fā)送到Apple服務(wù)器
- Apple服務(wù)器完成購買后,返回用戶一個(gè)完成購買的憑證
- APP發(fā)送這個(gè)憑證到后臺(tái)服務(wù)器驗(yàn)證
- 后臺(tái)服務(wù)器把這個(gè)憑證發(fā)送到Apple驗(yàn)證,Apple返回一個(gè)字段給后臺(tái)服務(wù)器表明該憑證是否有效
- 后臺(tái)服務(wù)器把驗(yàn)證結(jié)果在發(fā)送到APP,APP根據(jù)驗(yàn)證結(jié)果做相應(yīng)的處理
六、大致代碼
#import "ViewController.h"
#import <StoreKit/StoreKit.h>
@interface ViewController () <SKPaymentTransactionObserver, SKProductsRequestDelegate>
@property (nonatomic, strong) NSString * receipt;
@end
@implementation ViewController
/**
* 開發(fā)流程:
* 1、引入頭文件 #import <StoreKit/StoreKit.h>
* 2、檢查用戶是否允許使用 內(nèi)置購買 [SKPaymentQueue canMakePayments]
* 3、如果允許:獲取所有付費(fèi)Product ID(productionIdentifier)列表??梢杂贸A勘4嬖诒镜?,也可以自己服務(wù)器返回(原因:連接蘋果服務(wù)器比較慢)
* 4、先查詢是否有該productionIdentifier的商品信息,獲取SKPayment實(shí)例,然后通過SKPaymentQueue的 addPayment方法發(fā)起一個(gè)購買的操作。
* 5、監(jiān)聽購買結(jié)果 [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
* 6、購買完成回調(diào)- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
* 7、服務(wù)器驗(yàn)證憑證(Optional)。如果購買成功,我們需要將憑證發(fā)送到服務(wù)器上進(jìn)行驗(yàn)證。
* 服務(wù)器工作:
* 7.1 接收ios端發(fā)過來的購買憑證。
* 7.2 判斷憑證是否已經(jīng)存在或驗(yàn)證過,然后存儲(chǔ)該憑證。
* 7.3 將該憑證發(fā)送到蘋果的服務(wù)器驗(yàn)證,并將驗(yàn)證結(jié)果返回給客戶端。
* 7.4 如果需要,修改用戶相應(yīng)的會(huì)員權(quán)限。
* 8、網(wǎng)絡(luò)異常、崩潰等導(dǎo)致無法驗(yàn)證,將購買憑證持久化。用戶下次啟動(dòng)的時(shí)候,再發(fā)一次驗(yàn)證
* 8.1 保存數(shù)據(jù)(日期、用戶、憑證receipt)
* 8.2 重新啟動(dòng),讀取數(shù)據(jù),發(fā)送網(wǎng)絡(luò)請求
* 8.3 如果成功,刪除文件
*/
- (void)viewDidLoad {
[super viewDidLoad];
// 監(jiān)聽購買結(jié)果
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
- (void)buyProdutin:(UIButton *)sender
{
// 確認(rèn)用戶是否允許使用 內(nèi)置購買
if([SKPaymentQueue canMakePayments]){
// 獲取商品的productionIdentifier
NSString * productIdentifier = @""; //用戶選擇
[self getProductInfo:productIdentifier];
}else{
}
}
#pragma mark - 查詢productIdentifier 的商品信息
- (void)getProductInfo:(NSString *)productIdentifier
{
NSArray * product = [[NSArray alloc] initWithObjects:productIdentifier, nil];
NSSet * set = [NSSet setWithArray:product];
// 請求蘋果服務(wù)器,是否有該商品
SKProductsRequest * request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
request.delegate = self;
[request start];
// 這里可彈出提示信息 : 正在購買,請稍后
}
// 查詢該產(chǎn)品信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSArray * myProduct = response.products;
if(myProduct.count == 0){
// 說明沒有該商品,或查詢失敗
return;
}
// 如果有,發(fā)起購買操作
SKPayment * payment = [SKPayment paymentWithProduct:myProduct[0]];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
// 查詢失敗
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
// 提示信息
}
#pragma mark - 購買回調(diào)
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
{
for(SKPaymentTransaction * transaction in transactions){
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
// 交易成功
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
// 交易失敗
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
// 已經(jīng)購買過該商品
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing:
// 商品添加進(jìn)列表
break;
default:
break;
}
}
}
//沙盒測試環(huán)境驗(yàn)證
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
//正式環(huán)境驗(yàn)證
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
/**
* 驗(yàn)證購買,避免越獄軟件模擬蘋果請求達(dá)到非法購買問題
// 交易結(jié)束后,驗(yàn)證票據(jù)信息是否正確,之后才可以給用戶商品
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
// 測試環(huán)境
self.receipt = [[NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]] base64EncodedStringWithOptions:0];
NSError *error;
NSDictionary *requestContents = @{
@"receipt-data": self.receipt
};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0
error:&error];
// 設(shè)置URL
NSURL *storeURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:requestData];
// 網(wǎng)絡(luò)請求,驗(yàn)證
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
// 交易失敗后,回調(diào)
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
if(transaction.error.code != SKErrorPaymentCancelled) {
// 購買失敗
} else {
// 用戶取消交易
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
// 已購買過商品回調(diào)
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
#pragma mark - 發(fā)送憑證失敗的處理
/**
* 1 保存數(shù)據(jù)(日期、用戶、憑證receipt)
* 2 重新啟動(dòng),讀取數(shù)據(jù),發(fā)送網(wǎng)絡(luò)請求
* 3 如果成功,刪除文件
*/
- (void)dealloc
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
@end
需要注意以下幾點(diǎn):
- 代碼中的self.profuctIdArr所填寫的是你的購買項(xiàng)目的的ID,我這里是當(dāng)時(shí)填寫的ID 123。
- 在監(jiān)聽購買結(jié)果后,一定要調(diào)用[[SKPaymentQueue defaultQueue] finishTransaction:tran];來允許你從支付隊(duì)列中移除交易。
- 沙盒環(huán)境測試appStore內(nèi)購流程的時(shí)候,請使用沒越獄的設(shè)備。
- 請務(wù)必使用真機(jī)來測試,一切以真機(jī)為準(zhǔn)。
- 項(xiàng)目的Bundle identifier需要與您申請AppID時(shí)填寫的bundleID一致,不然會(huì)無法請求到商品信息。
- 真機(jī)測試的時(shí)候,一定要退出原來的賬號(hào),才能用沙盒測試賬號(hào)
- 二次驗(yàn)證,請注意區(qū)分宏, 測試用沙盒驗(yàn)證





