最近應用審覈被拒絕了,緣由是由於使用了第三方支付,蘋果說須要使用到應用內購買。可是查了下相關資料,太雜且不詳細,好吧,因此如今本身來寫博客咯,把我所知道的一一列出來,可能內容有點亂,你們就將就着些吧html
首先進入蘋果的ItunesConnection(https://itunesconnect.apple.com)點擊左上角的加號新建一個App應用,點擊後該網站會彈出一個信息編輯框,你們只要將上面的信息填充完畢點擊save便可在蘋果的app平臺上擁有一個屬於本身的App。ios
在套裝ID的上,須要提早爲該App申請一個AppID以及BundleID,只要是申請成功了就會在選擇列表中顯示出來。若是有人有疑問如何申請,請看我以前那一篇推送的博客,裏面有詳細的步驟。附上連接點擊打開連接。服務器
這裏順便多說一句這個ItunesConnect是用來幹嗎的,它是蘋果公司給我的或企業提供管理本身App的一個平臺。在這個平臺上開發者能夠新建,刪除和管理本身的App應用,開發者能夠根據需求對App應用進行上架與下架,編輯App信息,生成測試app所需的信息。具體操做我就不細說了。網絡
咱們打開ItunesConnect,進入協議、稅務和銀行業務,配置相關信息。數據結構
填寫相關信息,由於我是已經申請成功了,因此看到了就是下圖app
進入協議、稅務和銀行業務頁面後,會有3種合同類型,若是你以前沒有主動申請過去合同,那麼通常你如今激活的合同只有iOS Free Application一種。ide
頁面內容分爲兩塊:測試
合同類型分爲3種:網站
若是你沒有添加過聯繫人,你須要經過Add New Contact按鈕來添加一個新的聯繫人。而後指定聯繫人的職務,職務以下:ui
若是你是獨立開發者,能夠所有填你本身一我的。
咱們點擊Bank Info下方的Set Up按鈕能夠進入聯繫方式填寫頁面,以下圖:
選擇你的銀行帳戶,若是你沒有,點擊旁邊的Add Bank Account添加一個帳戶。下面是添加一個帳戶的流程。
2-二、填寫銀行CNAPS Code
若是你不知道CNAPS Code是多少,能夠點擊Look up Transit Number來查詢,查詢時會根據3個關鍵信息來查詢,以下:
2-三、確認銀行信息
2-四、填寫銀行帳號信息
2-五、確認全部信息
三、填寫稅務信息
稅務信息這一塊瞭解不是不少,不過由於是國內開發者,能夠不用太費心,稅務信息分3種:
我選擇的是U.S Tax Forms,選擇後會問你兩個問題,第一個問題以下:詢問你是不是美國居民,有沒有美國夥伴關係或者美國公司,若是沒有直接選擇No。
接下來第二個問題以下:詢問你有沒有在美國的商業性活動,沒有也直接選No。
而後填寫你的稅務信息,包括如下幾點:
填寫完這些信息後就能夠提交了
四、等待審覈
當你填寫完全部資料後,合同狀態就會變成Processing, 大概24小時內就會有結果。
進入ItunesConnect,點擊你的App,選擇上面「功能」中的"App內購買項目",就能夠看到右邊有一個+號,以下圖(最近由於被IPV6的問題給拒絕了)
單擊+號,選擇你須要建立的購買類型
在上圖所示的編輯框中輸入,商品名稱,產品ID以及價格等級,在這邊說明一下:
1.商品名稱根據你的消費道具的實際意義來講明,好比「100顆寶石」,「100金幣」等。
2.產品ID是比較重要的,由項目自定義,只要惟一便可,像我通常都是用App的bundleID加一個後綴來表示,這樣既跟項目關聯又具備惟一性。
3.價格等級的話「查看價格表」中有對應的說明,能夠對照着表中每一個國家的貨幣價格與等級來選擇。
建立購買項目成功後,回到App內購買項目,就能夠看到咱們剛剛建立的購買項目了。
咱們打開ItunesConnect,選擇「用戶和職能」選項, 咱們能夠看到有一個「沙箱技術測試員」,咱們單擊「+」號,添加咱們的測試賬號,以下圖:
而後咱們的相關信息,我就不一一列舉了,以下圖:
單擊「存儲」,咱們的測試賬號就建立成功了。下面開始擼代碼了
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 上有對返回的狀態碼的詳細說明。