iOS應用內購/內付費

最近應用審覈被拒絕了,緣由是由於使用了第三方支付,蘋果說須要使用到應用內購買。可是查了下相關資料,太雜且不詳細,好吧,因此如今本身來寫博客咯,把我所知道的一一列出來,可能內容有點亂,你們就將就着些吧html

1、建立應用

首先進入蘋果的ItunesConnection(https://itunesconnect.apple.com)點擊左上角的加號新建一個App應用,點擊後該網站會彈出一個信息編輯框,你們只要將上面的信息填充完畢點擊save便可在蘋果的app平臺上擁有一個屬於本身的App。ios

在套裝ID的上,須要提早爲該App申請一個AppID以及BundleID,只要是申請成功了就會在選擇列表中顯示出來。若是有人有疑問如何申請,請看我以前那一篇推送的博客,裏面有詳細的步驟。附上連接點擊打開連接服務器

這裏順便多說一句這個ItunesConnect是用來幹嗎的,它是蘋果公司給我的或企業提供管理本身App的一個平臺。在這個平臺上開發者能夠新建,刪除和管理本身的App應用,開發者能夠根據需求對App應用進行上架與下架,編輯App信息,生成測試app所需的信息。具體操做我就不細說了。網絡

2、填寫協議、稅務和銀行業務

咱們打開ItunesConnect,進入協議、稅務和銀行業務,配置相關信息。數據結構

填寫相關信息,由於我是已經申請成功了,因此看到了就是下圖app

進入協議、稅務和銀行業務頁面後,會有3種合同類型,若是你以前沒有主動申請過去合同,那麼通常你如今激活的合同只有iOS Free Application一種。ide

頁面內容分爲兩塊測試

  • Request Contracts(申請合同)
  • Contracts In Effect(已生效合同)。

合同類型分爲3種網站

  • iOS Free Application(免費應用合同)
  • iOS Paid Application(付費應用合同)
  • iAd App筆者暫時只申請過付費應用合同,因此下面主要講一下付費應用合同的申請流程。


一、填寫聯繫方式

 

    • 咱們點擊Contact Info下方的Set Up按鈕能夠進入聯繫方式填寫頁面,以下圖:

若是你沒有添加過聯繫人,你須要經過Add New Contact按鈕來添加一個新的聯繫人。而後指定聯繫人的職務,職務以下:ui

      • Senior Management:高管
      • Financial:財務
      • Technical:技術支持
      • Legal:法務
      • Marketing:市場推廣

若是你是獨立開發者,能夠所有填你本身一我的。

二、填寫銀行信息

  咱們點擊Bank Info下方的Set Up按鈕能夠進入聯繫方式填寫頁面,以下圖:  

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

  2-一、選擇銀行所在的國家

  

 

  

  2-二、填寫銀行CNAPS Code
    若是你不知道CNAPS Code是多少,能夠點擊Look up Transit Number來查詢,查詢時會根據3個關鍵信息來查詢,以下:

    • Bank Name:銀行的英文名稱(不能是拼音)
    • City:銀行所在的城市英文名稱(中國的城市用拼音)
    • Postal Code:郵編
      而後在下面就會出來備選的銀行,選擇正確的銀行後,點擊next,進入下一步。

    
    

  2-三、確認銀行信息

    
  2-四、填寫銀行帳號信息

    • Bank Account Number:銀行帳號
    • Confirm Bank Account Number:再次輸入銀行帳號
    • Account Holder Name:持卡人姓名,中文名用拼寫,名在前,姓在後
    • Bank Account Currency:貨幣類型,通常國內的開發者選擇CNY

    
  2-五、確認全部信息
    
 三、填寫稅務信息 

  稅務信息這一塊瞭解不是不少,不過由於是國內開發者,能夠不用太費心,稅務信息分3種:

  • U.S Tax Forms: 美國稅務
  • Australia Tax Forms:澳大利亞稅務
  • Canada Tax Forms: 加拿大稅務

  

  我選擇的是U.S Tax Forms,選擇後會問你兩個問題,第一個問題以下:詢問你是不是美國居民,有沒有美國夥伴關係或者美國公司,若是沒有直接選擇No。

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

  

  而後填寫你的稅務信息,包括如下幾點:

  • Individual or Organization Name:我的或者組織名稱
  • Country of incorporation: 所在國家
  • Type of Beneficial Owner:受益方式,獨立開發者選我的
  • Permanent Residence:居住地址
  • Mailing address:郵寄地址
  • Name of Person Making this Declaration:聲明人
  • Title:頭銜

  填寫完這些信息後就能夠提交了

  
  
 四、等待審覈

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

3、建立購買項目

 進入ItunesConnect,點擊你的App,選擇上面「功能」中的"App內購買項目",就能夠看到右邊有一個+號,以下圖(最近由於被IPV6的問題給拒絕了)

  
單擊+號,選擇你須要建立的購買類型

  • 一、消耗型項目
  • 二、非消耗型項目
  • 三、自動續訂型項目
  • 四、免費訂閱
  • 五、非續訂訂閱
      選擇你須要建立的購買項目類型後,輸入產品的參考名稱、產品的ID,選擇產品售價等級,而後單擊添加語言輸入你的產品相關信息,再上傳屏幕預覽,單擊保存即建立購買項目成功。以下圖:   

  在上圖所示的編輯框中輸入,商品名稱,產品ID以及價格等級,在這邊說明一下:

  1.商品名稱根據你的消費道具的實際意義來講明,好比「100顆寶石」,「100金幣」等。

  2.產品ID是比較重要的,由項目自定義,只要惟一便可,像我通常都是用App的bundleID加一個後綴來表示,這樣既跟項目關聯又具備惟一性。

  3.價格等級的話「查看價格表」中有對應的說明,能夠對照着表中每一個國家的貨幣價格與等級來選擇。

  建立購買項目成功後,回到App內購買項目,就能夠看到咱們剛剛建立的購買項目了。

4、添加應用購買測試賬號

  咱們打開ItunesConnect,選擇「用戶和職能」選項, 咱們能夠看到有一個「沙箱技術測試員」,咱們單擊「+」號,添加咱們的測試賬號,以下圖:

  
  而後咱們的相關信息,我就不一一列舉了,以下圖:

  
單擊「存儲」,咱們的測試賬號就建立成功了。下面開始擼代碼了

5、擼代碼咯

  1.首先在項目工程中加入「storekit.framework」,加入頭文件#import <StoreKit/StoreKit.h>

  2.在進行使用App內購買頁面.h文件中加入「SKPaymentTransactionObserver,SKProductsRequestDelegate」監聽機制  

  我就開始貼代碼吧

  1 - (void)viewDidLoad {
  2     
  3     [super viewDidLoad];
  4    
  5     // 設置購買隊列的監聽器
  6     [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
  7     
  8     if([SKPaymentQueue canMakePayments]){
  9                     //productID就是你在建立購買項目時所填寫的產品ID
 10                     [self requestProductData: productID];
 11                 }else{
 12                     self.ringIndicator.hidden = YES;
 13                     //                    NSLog(@"不容許程序內付費");
 14                     UIAlertView *alertError = [[UIAlertView alloc] initWithTitle:@"舒適提示"
 15                                                                          message:@"請先開啓應用內付費購買功能。"
 16                                                                         delegate:nil
 17                                                                cancelButtonTitle:@"肯定"
 18                                                                otherButtonTitles: nil];
 19                     [alertError show];
 20                 }
 21 
 22 }
 23 #pragma mark - 請求商品
 24 //請求商品
 25 - (void)requestProductData:(NSString *)type{
 26     NSLog(@"-------------請求對應的產品信息----------------");
 27     NSArray *product = [[NSArray alloc] initWithObjects:type, nil];
 28     
 29     NSSet *nsset = [NSSet setWithArray:product];
 30     SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
 31     request.delegate = self;
 32     [request start];
 33     //    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
 34 }
 35 
 36 #pragma mark 收到產品返回信息
 37 - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
 38     self.ringIndicator.hidden = YES;
 39     NSLog(@"--------------收到產品反饋消息---------------------");
 40     NSArray *product = response.products;
 41     if([product count] == 0){
 42         [self showHUDTipWithTitle:@"沒有該商品"];
 43         NSLog(@"--------------沒有商品------------------");
 44         return;
 45     }
 46     
 47     SKProduct *p = nil;
 48     for (SKProduct *pro in product) {
 49         NSLog(@"pro info");
 50         NSLog(@"SKProduct 描述信息:%@", [pro description]);
 51         NSLog(@"localizedTitle 產品標題:%@", [pro localizedTitle]);
 52         NSLog(@"localizedDescription 產品描述信息:%@", [pro localizedDescription]);
 53         NSLog(@"price 價格:%@", [pro price]);
 54         NSLog(@"productIdentifier Product id:%@", [pro productIdentifier]);
 55         
 56         if([pro.productIdentifier isEqualToString: productID]){
 57             p = pro;
 58             money = [NSString stringWithFormat:@"%@",[pro price]];
 59         }else{
 60             NSLog(@"不不不相同");
 61         }
 62     }
 63     SKPayment *payment = [SKPayment paymentWithProduct:p];
 64     //    SKPayment *payment = [SKPayment paymentWithProductIdentifier:PayKey];
 65     NSLog(@"發送購買請求");
 66     [[SKPaymentQueue defaultQueue] addPayment:payment];
 67 }
 68 
 69 //請求失敗
 70 - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
 71     //     [self showHUDTipWithTitle:@"請求失敗,錯誤"];
 72     self.ringIndicator.hidden = YES;
 73     NSLog(@"------------------錯誤-----------------:%@", error);
 74     UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription]
 75                                                        delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil];
 76     [alerView show];
 77 }
 78 
 79 - (void)requestDidFinish:(SKRequest *)request{
 80     //    [self showHUDTipWithTitle:@"反饋信息結束"];
 81     NSLog(@"------------反饋信息結束-----------------");
 82 }
 83 
 84 #pragma mark 監聽購買結果
 85 //監聽購買結果
 86 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
 87     self.ringIndicator.hidden = YES;
 88     NSLog(@" 監聽購買結果 -----paymentQueue--------");
 89     for (SKPaymentTransaction *transaction in transactions)
 90     {
 91         switch (transaction.transactionState)
 92         {
 93             case SKPaymentTransactionStatePurchased:{
 94                 NSLog(@"-----交易完成 --------");
 95                 //交易完成
 96                 [self commitSeversSucceeWithTransaction:transaction];
 97                 
 98                 
 99             }
100                 break;
101             case SKPaymentTransactionStateFailed:{
102                 NSLog(@"-----交易失敗 --------");
103                 //交易失敗
104                 [self failedTransaction:transaction];
105                 
106             }
107                 break;
108             case SKPaymentTransactionStateRestored:{
109                 NSLog(@"-----已經購買過該商品(重複支付) --------");
110                 //已經購買過該商品
111                 [self restoreTransaction:transaction];
112                 //                 [self commitSeversSucceeWithTransaction:transaction];
113                 
114                 
115             }
116             case SKPaymentTransactionStatePurchasing:  {
117                 //商品添加進列表
118                 NSLog(@"-----商品添加進列表 --------");
119             }
120                 break;
121             default:
122                 break;
123         }
124     }
125 }
126 
127 //交易結束
128 - (void)completeTransaction: (SKPaymentTransaction *)transaction
129 {
130     NSLog(@" 交易結束 -----completeTransaction--------");
131     
132     // Remove the transaction from the payment queue.
133     [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
134     
135 }
136 
137 - (void)commitSeversSucceeWithTransaction:(SKPaymentTransaction *)transaction
138 {
139     
140     NSString * productIdentifier = transaction.payment.productIdentifier;
141     NSLog(@"productIdentifier Product id:%@", productIdentifier);
142     NSString *transactionReceiptString= nil;
143     
144     //系統IOS7.0以上獲取支付驗證憑證的方式應該改變,切驗證返回的數據結構也不同了。
145     
146     if(SYSTEMVERSION >= 7.0){
147         // 驗證憑據,獲取到蘋果返回的交易憑據
148         // appStoreReceiptURL iOS7.0增長的,購買交易完成後,會將憑據存放在該地址
149         NSURLRequest * appstoreRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle]appStoreReceiptURL]];
150         NSError *error = nil;
151         NSData * receiptData = [NSURLConnection sendSynchronousRequest:appstoreRequest returningResponse:nil error:&error];
152         
153         transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
154     }else{
155         
156         NSData * receiptData = transaction.transactionReceipt;
157         //        transactionReceiptString = [receiptData base64EncodedString];
158         transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
159     }
160     //    NSLog(@"transactionReceiptString == %@",transactionReceiptString);
161     [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
162     // 向本身的服務器驗證購買憑證
163    // [self SendRequestWithtransactionReceiptString:transactionReceiptString Transaction:transaction];
164     
165     
166 }
167 //記錄交易
168 -(void)recordTransaction:(NSString *)product{
169     NSLog(@"-----記錄交易--------");
170 }
171 
172 //處理下載內容
173 -(void)provideContent:(NSString *)product{
174     NSLog(@"-----下載--------");
175 }
176 
177 - (void)failedTransaction:(SKPaymentTransaction *)transaction {
178     if(transaction.error.code != SKErrorPaymentCancelled) {
179         NSLog(@"購買失敗");
180         UIAlertView *alerView2 =  [[UIAlertView alloc] initWithTitle:@"舒適提示"
181                                                              message:@"購買該套餐失敗,請從新嘗試購買"
182                                                             delegate:nil cancelButtonTitle:NSLocalizedString(@"關閉",nil) otherButtonTitles:nil];
183         
184         [alerView2 show];
185     } else {
186         NSLog(@"用戶取消交易");
187         
188         UIAlertView *alerView2 =  [[UIAlertView alloc] initWithTitle:@"舒適提示"
189                                                              message:@"您已取消該購買"
190                                                             delegate:nil cancelButtonTitle:NSLocalizedString(@"關閉",nil) otherButtonTitles:nil];
191         
192         [alerView2 show];
193     }
194     [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
195 }
196 
197 
198 -(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction{
199     
200 }
201 
202 
203 - (void) restoreTransaction: (SKPaymentTransaction *)transaction
204 {
205     NSLog(@" 交易恢復處理");
206     [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
207     
208 }
209 
210 -(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{
211     NSLog(@"-------paymentQueue----");
212 }
213 
214 #pragma mark connection delegate
215 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
216 {
217     NSLog(@"connection==%@",  [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
218 }

-(void)dealloc

{

    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//解除監聽

 }

代碼我就不一一解釋了。接下來我就給你們看運行後的結果。

 


  




 

最後給你們補充點東西,在與服務器作較驗的時候,考慮到網絡異常狀況,服務器的驗證應該是一個可恢復的隊列,若是失敗了,應該進行重試。

與蘋果的驗證接口文檔在https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingStoreReceipts.html#//apple_ref/doc/uid/TP4008267-CH104-SW3 。簡單來講就是將購買憑證用Base64編碼,而後Post給蘋果的驗證服務器,蘋果將驗證結果以JSON形式返回。

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

注意事項:

蘋果在審覈應用時,只會在沙盒(sandbox)環境購買,其產生的購買憑證,也只能鏈接蘋果的測試驗證服務器。可是審覈的應用又是鏈接的線上服務器,那應該判斷蘋果正式驗證服務器的返回狀態碼,若是 是21007,則再一次鏈接測試服務器進行驗證便可。https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Introduction.html  上有對返回的狀態碼的詳細說明。

相關文章
相關標籤/搜索