iOS 內購最新講解

一.總說內購的內容

協議、稅務和銀行業務 信息填寫

內購商品的添加

添加沙盒測試賬號

內購代碼的具體實現

內購的注意事項

二.協議、稅務和銀行業務 信息填寫

2.1、協議、稅務和銀行業務 信息填寫 的入口

協議、稅務和銀行業務 信息填寫 的入口

2.2、選擇申請合同類型

進入協議、稅務和銀行業務頁面后,會有3種合同類型,如果你之前沒有主動申請過去合同,那么一般你現在激活的合同只有iOS Free Application一種。

頁面內容分為兩塊:

Request Contracts(申請合同)

Contracts In Effect(已生效合同)。

合同類型分為3種:

iOS Free Application(免費應用合同)

iOS Paid Application(付費應用合同)

iAd App NetNetwork(廣告合同)

這里我們主要主要講一下付費應用合同的申請流程。

付費應用合同的申請流程

2.3、申請iOS Paid Application合同(協議、稅務和銀行業務3個都要填寫)

協議、稅務和銀行業務

2.4、Contact Info(填寫聯系方式)

填寫聯系方式

如果你沒有添加過聯系人,你需要通過Add New Contact按鈕來添加一個新的聯系人。然后指定聯系人的職務,

職務如下:

Senior Management:高管

Financial:財務

Technical:技術支持

Legal:法務

Marketing:市場推廣

如果你是獨立開發者,可以全部填你自己一個人。

2.5、填寫銀行信息

填寫銀行信息

選擇你的銀行賬戶,如果你沒有,點擊旁邊的Add Bank Account添加一個賬戶。下面是添加一個賬戶的流程。

2.5.1、選擇銀行所在的國家

選擇銀行所在的國家

2.5.2、填寫銀行標識CNAPS Code

如果你不知道CNAPS Code是多少,可以百度搜CNAPS Code來查詢,查詢時會根據3個關鍵信息來查詢,如下:

Bank Name:銀行的英文名稱(不能是拼音)

City:銀行所在的城市英文名稱(中國的城市用拼音)

Postal Code:郵編

然后在下面就會出來備選的銀行,選擇正確的銀行后,點擊next,進入下一步。

百度搜CNAPS Code來查詢

銀行信息的填寫

2.5.3、確認銀行信息

確認銀行信息

2.5.4、填寫銀行賬號信息

Bank Account Number:銀行賬號

Confirm Bank Account Number:再次輸入銀行賬號

Account Holder Name:持卡人姓名,中文名用拼寫,名在前,姓在后

Bank Account Currency:貨幣類型,一般國內的開發者選擇CNY

填寫銀行賬號信息

2.5.5、確認所有信息

確認所有信息

2.6.填寫稅務信息(這個內容比較多)

2.6.1.稅務信息這一塊了解不是很多,不過因為是國內開發者,可以不用太費心,稅務信息分3種:

U.S Tax Forms: 美國稅務

Australia Tax Forms:澳大利亞稅務

Canada Tax Forms: 加拿大稅務

稅務信息

2.6.2.一堆條約

我選擇的是U.S Tax Forms,選擇后會問你兩個問題:

第1個問題如下:詢問你是否是美國居民,有沒有美國伙伴關系或者美國公司,如果沒有直接選擇No。

詢問你是否是美國居民,有沒有美國伙伴關系或者美國公司,如果沒有直接選擇No

接下來第二個問題如下:詢問你有沒有在美國的商業性活動,沒有也直接選No

接下來第二個問題如下:詢問你有沒有在美國的商業性活動,沒有也直接選No

2.6.3.然后填寫你的稅務信息,包括以下幾點:

Individual or Organization Name:個人或者組織名稱

Country of incorporation: 所在國家

Type of Beneficial Owner:受益方式,獨立開發者選個人

Permanent Residence:居住地址

Mailing address:郵寄地址

Name of Person Making this Declaration:聲明人

Title:頭銜

填寫你的稅務信息

2.6.4.打鉤

打鉤

2.6.5.澳大利亞的不要管了

澳大利亞的不要管了

2.6.6.加拿大的也不用管了

加拿大的也不用管了

2.7.填寫完成

填寫完成

2.8.待審核

你填寫完所有資料后,合同狀態就會變成Processing, 大概24小時內就會有結果。

三.內購商品的添加

3.1.創建內購商品

創建內購商品

3.2.選擇內購類型

3.2.1.消耗型商品:類似游戲中的鉆石,還有現在某些APP中的貨幣,比如斗魚里的魚丸、映客里的映票。會被消耗的,要選擇消耗型商品

注意:大多數的消耗型商品都是需要登錄的,因為需要在數據庫存余額。

需要注意的是:在登錄之前,你最好不要讓用戶看到商品,有可能會因為這個原因被拒(大家都說看運氣)

3.2.2.非消耗型商品:無法被消耗的商品,比如上文提到的視頻課程,一次購買,就應該永久可以觀看

注意:當你使用非消耗型商品時,你需要添加一個恢復購買的按鈕

這個常見于各種游戲中,其實知道這個規定以后還是挺好理解的,非消耗型商品是不可被消耗的,一次購買終身使用的,非消耗型的商品是跟appleId綁定的,就是你平時下載APP讓你輸入賬號密碼的內個。

你需要一個恢復購買的按鈕,來讓用戶恢復他購買的內容

3.2.3.訂閱類型商品:如果你的公司是外包公司,有訂閱類型商品的APP一定要用客戶的賬號提交審核,因為當APP中有過訂閱類型商品,注意是有過,創建過再刪除也算,這個APP無法被轉移賬號

注意:使用或曾經使用過訂閱型商品的APP無法轉移

選擇內購類型

具體內購類型

選擇語言

FA40E42F-400E-4A85-949A-ED90C9B6B475.png

3.3.創建好的產品

創建好的產品

3.4.在上線的時候記得添加內購的商品

添加內購商品

選擇內購產品之后的狀態

四.添加沙盒測試賬號

4.1.添加沙盒測試的入口

添加沙盒測試的入口

4.2.添加沙盒測試賬號

添加沙盒測試賬號

4.3.具體的測試賬號信息填寫

具體的測試賬號信息填寫

五.內購代碼的具體實現(這才是大家所期望看到的)

5.1.我創建了一個購買金幣的內購控制器ApplePayCIOViewController

在此,我僅僅向大家貼出.m的詳細代碼

5.2.內購的流程詳細講解

5.2.1. 用戶先拿到購買產品的單子,

5.2.2.拿著單子去蘋果那里交錢,交完錢讓蘋果在單子上蓋個章

5.2.3.拿著蓋了章的單子傳給自己的服務器來驗證是否真的支付成功

5.2.4.根據服務器返回的信息做具體的處理

內購的流程詳細講解

5.3.上代碼

5.3.1.先導入StoreKit.framework庫;

5.3.2.創建ApplePayCIOViewController,遵守協議

5.3.3.ApplePayCIOViewController.m代碼

#import"ApplePayCIOViewController.h"

#import//?產品的ID

#define?ProductID1?@"CIOCourses1"

@interfaceApplePayCIOViewController?(){

NSString?*selectProductID;

}

@end

@implementation?ApplePayCIOViewController

-(void)viewWillAppear:(BOOL)animated{

[superviewWillAppear:animated];

//?添加觀察者

[[SKPaymentQueue?defaultQueue]?addTransactionObserver:self];

}

-(void)viewWillDisappear:(BOOL)animated{

[superviewWillDisappear:animated];

//?移除觀察者

[[SKPaymentQueue?defaultQueue]?removeTransactionObserver:self];

}

-?(void)viewDidLoad?{

[superviewDidLoad];

self.title?=?@"內購";

self.navigationItem.rightBarButtonItem?=?[[UIBarButtonItem?alloc]initWithTitle:@"測試"style:UIBarButtonItemStylePlain?target:self?action:@selector(test)];

//?恢復購買的按鈕

UIButton?*?revert?=?[[UIButton?alloc]initWithFrame:CGRectMake(20,100,100,80)];

[revert?setBackgroundColor:JKRandomColor];

[revert?addTarget:self?action:@selector(replyToBuy)?forControlEvents:UIControlEventTouchUpInside];

[self.view?addSubview:?revert];

self.view.backgroundColor?=[UIColor?redColor];

}

#pragma?mark?恢復購買(主要是針對非消耗產品)

-(void)replyToBuy{

[[SKPaymentQueue?defaultQueue]?restoreCompletedTransactions];

}

#pragma?mark?測試內購

-(void)test{

if([SKPaymentQueue?canMakePayments]){

//?productID就是你在創建購買項目時所填寫的產品ID

selectProductID?=?[NSString?stringWithFormat:@"%@",ProductID1];

[self?requestProductID:selectProductID];

}else{

6

//?NSLog(@"不允許程序內付費");

UIAlertView?*alertError?=?[[UIAlertView?alloc]?initWithTitle:@"溫馨提示"

message:@"請先開啟應用內付費購買功能。"

delegate:nil

cancelButtonTitle:@"確定"

otherButtonTitles:?nil];

[alertError?show];

}

}

#pragma?mark1.請求所有的商品ID

-(void)requestProductID:(NSString?*)productID{

//?1.拿到所有可賣商品的ID數組

NSArray?*productIDArray?=?[[NSArray?alloc]initWithObjects:productID,?nil];

NSSet?*sets?=?[[NSSet?alloc]initWithArray:productIDArray];

//?2.向蘋果發送請求,請求所有可買的商品

//?2.1.創建請求對象

SKProductsRequest?*sKProductsRequest?=?[[SKProductsRequest?alloc]initWithProductIdentifiers:sets];

//?2.2.設置代理(在代理方法里面獲取所有的可賣的商品)

sKProductsRequest.delegate?=?self;

//?2.3.開始請求

[sKProductsRequest?start];

}

#pragma?mark2.蘋果那邊的內購監聽

-(void)productsRequest:(SKProductsRequest?*)request?didReceiveResponse:(SKProductsResponse?*)response{

NSLog(@"可賣商品的數量=%ld",response.products.count);

NSArray?*product?=?response.products;

if([product?count]?==0){

NSLog(@"沒有商品");

return;

}

for(SKProduct?*sKProductinproduct)?{

NSLog(@"pro?info");

NSLog(@"SKProduct?描述信息:%@",?sKProduct.description);

NSLog(@"localizedTitle?產品標題:%@",?sKProduct.localizedTitle);

NSLog(@"localizedDescription?產品描述信息:%@",sKProduct.localizedDescription);

NSLog(@"price?價格:%@",sKProduct.price);

NSLog(@"productIdentifier?Product?id:%@",sKProduct.productIdentifier);

if([sKProduct.productIdentifier?isEqualToString:?selectProductID]){

[self?buyProduct:sKProduct];

break;

}else{

//NSLog(@"不不不相同");

}

}

}

#pragma?mark?內購的代碼調用

-(void)buyProduct:(SKProduct?*)product{

//?1.創建票據

SKPayment?*skpayment?=?[SKPayment?paymentWithProduct:product];

//?2.將票據加入到交易隊列

[[SKPaymentQueue?defaultQueue]?addPayment:skpayment];

//?3.添加觀察者,監聽用戶是否付錢成功(不在此處添加觀察者)

//[[SKPaymentQueue?defaultQueue]?addTransactionObserver:self];

}

#pragma?mark4.實現觀察者監聽付錢的代理方法,只要交易發生變化就會走下面的方法

-(void)paymentQueue:(SKPaymentQueue?*)queue?updatedTransactions:(NSArray?*)transactions{

/*

SKPaymentTransactionStatePurchasing,????正在購買

SKPaymentTransactionStatePurchased,?????已經購買

SKPaymentTransactionStateFailed,????????購買失敗

SKPaymentTransactionStateRestored,??????回復購買中

SKPaymentTransactionStateDeferred???????交易還在隊列里面,但最終狀態還沒有決定

*/

for(SKPaymentTransaction?*transactionintransactions)?{

switch(transaction.transactionState)?{

caseSKPaymentTransactionStatePurchasing:{

NSLog(@"正在購買");

}break;

caseSKPaymentTransactionStatePurchased:{

NSLog(@"購買成功");

//?購買后告訴交易隊列,把這個成功的交易移除掉

[queue?finishTransaction:transaction];

[self?buyAppleStoreProductSucceedWithPaymentTransactionp:transaction];

}break;

caseSKPaymentTransactionStateFailed:{

NSLog(@"購買失敗");

//?購買失敗也要把這個交易移除掉

[queue?finishTransaction:transaction];

}break;

caseSKPaymentTransactionStateRestored:{

NSLog(@"回復購買中,也叫做已經購買");

//?回復購買中也要把這個交易移除掉

[queue?finishTransaction:transaction];

}break;

caseSKPaymentTransactionStateDeferred:{

NSLog(@"交易還在隊列里面,但最終狀態還沒有決定");

}break;

default:

break;

}

}

}

//?蘋果內購支付成功

-?(void)buyAppleStoreProductSucceedWithPaymentTransactionp:(SKPaymentTransaction?*)paymentTransactionp?{

NSString?*?productIdentifier?=?paymentTransactionp.payment.productIdentifier;

//?NSLog(@"productIdentifier?Product?id:%@",?productIdentifier);

NSString?*transactionReceiptString=?nil;

//系統IOS7.0以上獲取支付驗證憑證的方式應該改變,切驗證返回的數據結構也不一樣了。

NSString?*version?=?[UIDevice?currentDevice].systemVersion;

if([version?intValue]?>=7.0){

//?驗證憑據,獲取到蘋果返回的交易憑據

//?appStoreReceiptURL?iOS7.0增加的,購買交易完成后,會將憑據存放在該地址

NSURLRequest?*?appstoreRequest?=?[NSURLRequest?requestWithURL:[[NSBundle?mainBundle]appStoreReceiptURL]];

NSError?*error?=?nil;

NSData?*?receiptData?=?[NSURLConnection?sendSynchronousRequest:appstoreRequest?returningResponse:nil?error:&error];

transactionReceiptString?=?[receiptData?base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

}else{

NSData?*?receiptData?=?paymentTransactionp.transactionReceipt;

//??transactionReceiptString?=?[receiptData?base64EncodedString];

transactionReceiptString?=?[receiptData?base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

}

//?去驗證是否真正的支付成功了

[self?checkAppStorePayResultWithBase64String:transactionReceiptString];

}

-?(void)checkAppStorePayResultWithBase64String:(NSString?*)base64String?{

/*?生成訂單參數,注意沙盒測試賬號與線上正式蘋果賬號的驗證途徑不一樣,要給后臺標明?*/

/*

注意:

自己測試的時候使用的是沙盒購買(測試環境)

App?Store審核的時候也使用的是沙盒購買(測試環境)

上線以后就不是用的沙盒購買了(正式環境)

所以此時應該先驗證正式環境,在驗證測試環境

正式環境驗證成功,說明是線上用戶在使用

正式環境驗證不成功返回21007,說明是自己測試或者審核人員在測試

*/

/*

蘋果AppStore線上的購買憑證地址是:https://buy.itunes.apple.com/verifyReceipt

測試地址是:https://sandbox.itunes.apple.com/verifyReceipt

*/

//????NSNumber?*sandbox;

NSString?*sandbox;

#if(defined(APPSTORE_ASK_TO_BUY_IN_SANDBOX)?&&?defined(DEBUG))

//sandbox?=?@(0);

sandbox?=?@"0";

#else

//sandbox?=?@(1);

sandbox?=?@"1";

#endif

NSMutableDictionary?*prgam?=?[[NSMutableDictionary?alloc]?init];;

[prgam?setValue:sandbox?forKey:@"sandbox"];

[prgam?setValue:base64String?forKey:@"reciept"];

/*

請求后臺接口,服務器處驗證是否支付成功,依據返回結果做相應邏輯處理

0?代表沙盒??1代表?正式的內購

最后最驗證后的

*/

/*

內購驗證憑據返回結果狀態碼說明

21000?App?Store無法讀取你提供的JSON數據

21002?收據數據不符合格式

21003?收據無法被驗證

21004?你提供的共享密鑰和賬戶的共享密鑰不一致

21005?收據服務器當前不可用

21006?收據是有效的,但訂閱服務已經過期。當收到這個信息時,解碼后的收據信息也包含在返回內容中

21007?收據信息是測試用(sandbox),但卻被發送到產品環境中驗證

21008?收據信息是產品環境中使用,但卻被發送到測試環境中驗證

*/

NSLog(@"字典==%@",prgam);

}

#pragma?mark?客戶端驗證購買憑據

-?(void)verifyTransactionResult

{

//?驗證憑據,獲取到蘋果返回的交易憑據

//?appStoreReceiptURL?iOS7.0增加的,購買交易完成后,會將憑據存放在該地址

NSURL?*receiptURL?=?[[NSBundle?mainBundle]?appStoreReceiptURL];

//?從沙盒中獲取到購買憑據

NSData?*receipt?=?[NSData?dataWithContentsOfURL:receiptURL];

//?傳輸的是BASE64編碼的字符串

/**

BASE64?常用的編碼方案,通常用于數據傳輸,以及加密算法的基礎算法,傳輸過程中能夠保證數據傳輸的穩定性

BASE64是可以編碼和解碼的

*/

NSDictionary?*requestContents?=?@{

@"receipt-data":?[receipt?base64EncodedStringWithOptions:0]

};

NSError?*error;

//?轉換為?JSON?格式

NSData?*requestData?=?[NSJSONSerialization?dataWithJSONObject:requestContents

options:0

error:&error];

//?不存在

if(!requestData)?{/*?...?Handle?error?...?*/}

//?發送網絡POST請求,對購買憑據進行驗證

NSString?*verifyUrlString;

#if(defined(APPSTORE_ASK_TO_BUY_IN_SANDBOX)?&&?defined(DEBUG))

verifyUrlString?=?@"https://sandbox.itunes.apple.com/verifyReceipt";

#else

verifyUrlString?=?@"https://buy.itunes.apple.com/verifyReceipt";

#endif

//?國內訪問蘋果服務器比較慢,timeoutInterval?需要長一點

NSMutableURLRequest?*storeRequest?=?[NSMutableURLRequest?requestWithURL:[[NSURL?alloc]?initWithString:verifyUrlString]?cachePolicy:NSURLRequestUseProtocolCachePolicy?timeoutInterval:10.0f];

[storeRequest?setHTTPMethod:@"POST"];

[storeRequest?setHTTPBody:requestData];

//?在后臺對列中提交驗證請求,并獲得官方的驗證JSON結果

NSOperationQueue?*queue?=?[[NSOperationQueue?alloc]?init];

[NSURLConnection?sendAsynchronousRequest:storeRequest?queue:queue

completionHandler:^(NSURLResponse?*response,?NSData?*data,?NSError?*connectionError)?{

if(connectionError)?{

NSLog(@"鏈接失敗");

}else{

NSError?*error;

NSDictionary?*jsonResponse?=?[NSJSONSerialization?JSONObjectWithData:data?options:0error:&error];

if(!jsonResponse)?{

NSLog(@"驗證失敗");

}

//?比對?jsonResponse?中以下信息基本上可以保證數據安全

/*

bundle_id

application_version

product_id

transaction_id

*/

NSLog(@"驗證成功");

}

}];

}

@end

六.內購的注意事項

6.1.一般發生于首次提交app或添加新商品,當你的app通過審核以后,你發現在生產環境下獲取不到商品,這是因為app雖然過審核了,但是內購商品還沒有正式添加到蘋果的服務器里,耐心等待一段時間就可以啦~

6.2. 代碼中的_currentProId所填寫的是你的購買項目的的ID,這個和第二步創建的內購的productID要一致;本例中是 123。

6.3. 在監聽購買結果后,一定要調用[[SKPaymentQueue defaultQueue] finishTransaction:tran];來允許你從支付隊列中移除交易。

6.4. 沙盒環境測試appStore內購流程的時候,請使用沒越獄的設備。

6.5. 請務必使用真機來測試,一切以真機為準。

6.6. 項目Bundle identifier需要與您申請AppID時填寫的bundleID一致,不然會無法請求到商品信息。

6.7. 真機測試的時候,一定要退出原來的賬號,才能用沙盒測試賬號

6.8. 二次驗證,請注意區分宏, 測試用沙盒驗證,App Store審核的時候也使用的是沙盒購買,所以驗證購買憑證的時候需要判斷返回Status Code決定是否去沙盒進行二次驗證,為了線上用戶的使用,驗證的順序肯定是先驗證正式環境,此時若返回值為21007,就需要去沙盒二次驗證,因為此購買的是在沙盒進行的。

6.9.您的應用是否處于等待開發者發布(Pending Developer Release)狀態?等待發布狀態的IAP是無法測試的。

6.10.您的內購項目是否是最近才新建的,或者進行了更改?內購項目需要一段時間才能反應到所有服務器上,這個過程一般是一兩小時,也可能再長一些達到若干小時。

6.11.您在iTC中Contracts, Tax, and Banking Information項目中是否有還沒有設置或者過期了的項目?不完整的財務信息無法進行內購測試。

6.12.您是在越獄設備上進行內購測試么?越獄設備不能用于正常內購,您需要重裝或者尋找一臺沒有越獄的設備。

6.13.您的應用是否是被拒狀態(Rejected)或自己拒絕(Developer Rejected)了?被拒絕狀態的應用的話對應還未通過的內購項目也會一起被拒,因此您需要重新將IAP項目設為Cleared for Sale。

6.14.您使用的測試賬號是否是美國區賬號?雖然不是一定需要,但是鑒于其他地區的測試賬號經常抽風,加上美國區賬號一直很穩定,因此強烈建議使用美國區賬號。正常情況下IAP不需要進行信用卡綁定和其他信息填寫,如果你遇到了這種情況,可以試試刪除這個測試賬號再新建一個其他地區的。

6.15.您是否將設備上原來的app刪除了,并重新進行了安裝?記得在安裝前做一下Clean和Clean Build Folder。

6.16.您的plist中的Bundle identifier的內容是否和您的AppID一致?

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 公司項目中有虛擬產品,所以要使用蘋果內購.自此記錄一下蘋果內購的流程.前提是已有開發者賬號 協議,稅務和銀行業務 ...
    better棟閱讀 2,044評論 0 7
  • 自己開發的視頻直播項目,牽涉到充值金幣,用到了蘋果公司的內購,趴坑了兩天,這里總結下實現蘋果內購。 一. 創建測試...
    Leo丶Dicaprio閱讀 3,445評論 8 7
  • iOS應用如果涉及到支付功能,分為兩類:第三方支付和蘋果內購。那么什么情況下選擇使用第三方支付,又在什么情況下選擇...
    ZfRee閱讀 39,012評論 36 66
  • 剛剛看完<心理追兇>,還沒有緩過來,新浪微博上就有江歌劉鑫事件,覺得世界上真有這么自私的人,還不要臉,交朋友真...
    銘嵐閱讀 330評論 0 0
  • 我的夢想是成為一棵樹。我的人生,便要是從一粒種子到一根樹苗,到一棵小樹,再到一棵大樹的過程。 「樹」,是關于我如何...
    心智學徒H閱讀 1,576評論 2 7