前言
本文會給大家詳細介紹iOS內購,雖然之前網上也有內購的教程,但是還不夠詳細,我重新整理出一份教程,希望對大家有所幫助。
基於Xcode7.1.1版本,模擬器iphone6,9.1系統。
部分地方直接摘自網路,省時省心省力。
多圖預警!!!
轉載請註明出處@yimouleng
一. 建立測試App
建立App-1
首先你需要登入 App的ItunesConnection,你會看到如下介面
簡單的介紹一下這幾個選項
- 1.我的App主要用於管理自己的App應用,例如編輯資料,上架,下架等。
- 2.銷售和趨勢主要是來檢視App在各個平臺的下載量,收入等方面資料,裡面有曲線圖等圖文結合的方式給我們參考。
- 3.付款和財務報告顯示的是你的收入以及付款等相關資訊。
- 4.iAd主要是跟廣告有關,開發者可以登入到Workbench,通過iAd對應用的廣告進行控制。
- 5.使用者和職能用於生成相應賬號,例如蘋果沙河測試賬號。
- 6.協議,稅務和銀行業務則是你銀行相關賬戶的資訊設定。
在這裡我們選擇第一個選項,我的App, 然後點選左上角的加號,新建一個用來測試用的App。
我們會看到彈出的視窗
在這裡有幾個需要填寫的地方,名稱自己取,平臺IOS,語言選擇了簡體中文,套裝ID也就是你的Bundle Identifier
,需要你在Certificates頁面 申請BundleID,在這裡簡單的給大家介紹一下。
申請BundleID
開啟Certificates頁面 ,在左側選擇 Identifiers,並點選加號,申請一個新的Identifiers。
在這裡Name可以隨意填寫,我填寫的是TestAppStroeTestDemo,而用來使用的BundleID,我們在這裡必須選擇第一個選項唯一的,不用選擇通配。在下面的選項中, 我們只需要勾選一個 Apple Pay
即可,其他選項看自己需求,我在這裡只選擇了它。
之後一路Done即可。
建立App-2
之後我們回到建立App,選擇好自己剛建立的 BundleID ,填寫SKU, SKU是你App的專用ID,我在這裡隨意填寫,直接複製了App名。點選建立,我們的測試App則建立成功。
二.新增內購
App建立好之後,我們開啟建立的App,在左上角選擇功能,會看到左側的App 內購買專案。我們點選右下角的加號,為App新增內購專案。
之後我們會看到型別的選項,如下圖
官方的註釋寫的很清楚了,只在這裡簡單的說下前兩種
消耗型專案 就像你玩遊戲需要買金幣,買鑽石等,只要花錢就可以無限次的購買
非消耗型專案 就像你在App Store購買App,買了一次之後就不用再買第二次,你擁有永久使用權。
在這裡為了方便測試,我們選擇第一種 消耗型專案
。來到內購專案填寫頁面,如下圖。
這裡有幾個選項,需要填寫商品名稱,產品ID以及價格等級,簡單說明一下
1.商品名稱根據你的消費道具的實際意義來說明,比如“100顆寶石”,“100金幣”等。
2.產品ID是比較重要的,由專案自定義,只要唯一即可,因為測試,我在這裡隨便填寫的123,在實際應用中,一定要認真填寫。
3.價格等級的話“檢視價格表”中有對應的說明,可以對照著表中每個國家的貨幣價格與等級來選擇
接下來是語言選擇,和上傳快照如下圖
點選新增語言,填寫名稱和描述,這裡我們依然選擇簡體中文,如下
稽核備註,根據實際情況填寫,可以不填。而下面的螢幕快照,則是商品圖片,以畫素為單位,最低尺寸為321,390,尺寸需求如下圖,上傳即可。
到這裡為止, 我們的內購專案則新增完成。接下來則是測試階段了。
三.申請沙盒測試賬號(用來測試購買專案)
這個賬號,是利用蘋果的沙盒測試環境來模擬AppStore的購買流程,你肯定不會想要用真實RMB去購買測試吧?
首先我們回到iTunes Connect中,在這裡我們選擇使用者和職能
。
然後在上面的第三個選項沙箱技術測試員中點選加號,新增測試員。
在資訊填寫頁面只簡單說兩句。
所有資訊都可以隨意填寫,不用管是否真實。
App Store地區選擇,一定要選對,它對應的是你建立的App的地區, 你App是中國的話, 在這裡我們依然選擇中國。
此賬號只能用來測試,不要在正式的appstore上使用
填寫完畢,點選儲存後,我們則生成一個測試賬號,當然這個賬號是可以隨時刪除和新增的。
四.核心程式碼
之後終於到了我們擼程式碼的時候了,點開你的Xcode建立你的專案!
首先我們需要在專案工程中加入“storekit.framework”,加入標頭檔案#import
在.h檔案中加入“SKPaymentTransactionObserver,SKProductsRequestDelegate”監聽機制
程式碼很簡單,直接在.m檔案在中填寫,新增了二次驗證,防止越獄手機等內購。如下,
.m檔案
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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
// // ViewController.m // 內購 // // Created by Ely on 15/12/15. // Copyright © 2015年 Ely. All rights reserved. // #import "ViewController.h" #import #import "SVProgressHUD.h" @interface ViewController ()SKPaymentTransactionObserver,SKProductsRequestDelegate> @property (nonatomic,strong) NSArray *profuctIdArr; @property (nonatomic,copy) NSString *currentProId; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self createPay]; } - (void)createPay { [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; self.profuctIdArr = @[@"123"]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(100, 100, 100, 100); button.backgroundColor = [UIColor greenColor]; [button setTitle:@"6元" forState:UIControlStateNormal]; [button addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchDown]; button.tag = 100; [self.view addSubview:button]; } - (void)btnClick:(UIButton *)button { NSString *product = self.profuctIdArr[button.tag-100]; _currentProId = product; if([SKPaymentQueue canMakePayments]){ [self requestProductData:product]; }else{ NSLog(@"不允許程式內付費"); } } //請求商品 - (void)requestProductData:(NSString *)type{ NSLog(@"-------------請求對應的產品資訊----------------"); [SVProgressHUD showWithStatus:nil maskType:SVProgressHUDMaskTypeBlack]; NSArray *product = [[NSArray alloc] initWithObjects:type,nil]; NSSet *nsset = [NSSet setWithArray:product]; SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset]; request.delegate = self; [request start]; } //收到產品返回資訊 - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{ NSLog(@"--------------收到產品反饋訊息---------------------"); NSArray *product = response.products; if([product count] == 0){ [SVProgressHUD dismiss]; NSLog(@"--------------沒有商品------------------"); return; } NSLog(@"productID:%@", response.invalidProductIdentifiers); NSLog(@"產品付費數量:%lu",(unsigned long)[product count]); SKProduct *p = nil; for (SKProduct *pro in product) { NSLog(@"%@", [pro description]); NSLog(@"%@", [pro localizedTitle]); NSLog(@"%@", [pro localizedDescription]); NSLog(@"%@", [pro price]); NSLog(@"%@", [pro productIdentifier]); if([pro.productIdentifier isEqualToString:_currentProId]){ p = pro; } } SKPayment *payment = [SKPayment paymentWithProduct:p]; NSLog(@"傳送購買請求"); [[SKPaymentQueue defaultQueue] addPayment:payment]; } //請求失敗 - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{ [SVProgressHUD showErrorWithStatus:@"支付失敗"]; NSLog(@"------------------錯誤-----------------:%@", error); } - (void)requestDidFinish:(SKRequest *)request{ [SVProgressHUD dismiss]; NSLog(@"------------反饋資訊結束-----------------"); } //沙盒測試環境驗證 #define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt" //正式環境驗證 #define AppStore @"https://buy.itunes.apple.com/verifyReceipt" /** * 驗證購買,避免越獄軟體模擬蘋果請求達到非法購買問題 * */ -(void)verifyPurchaseWithPaymentTransaction{ //從沙盒中獲取交易憑證並且拼接成請求體資料 NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL]; NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl]; NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//轉化為base64字串 NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接請求資料 NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; //建立請求到蘋果官方進行購買驗證 NSURL *url=[NSURL URLWithString:SANDBOX]; NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url]; requestM.HTTPBody=bodyData; requestM.HTTPMethod=@"POST"; //建立連線併傳送同步請求 NSError *error=nil; NSData *responseData=[NSURLConnection sendSynchronousRequest:requestM returningResponse:nil error:&error]; if (error) { NSLog(@"驗證購買過程中發生錯誤,錯誤資訊:%@",error.localizedDescription); return; } NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil]; NSLog(@"%@",dic); if([dic[@"status"] intValue]==0){ NSLog(@"購買成功!"); NSDictionary *dicReceipt= dic[@"receipt"]; NSDictionary *dicInApp=[dicReceipt[@"in_app"] firstObject]; NSString *productIdentifier= dicInApp[@"product_id"];//讀取產品標識 //如果是消耗品則記錄購買數量,非消耗品則記錄是否購買過 NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults]; if ([productIdentifier isEqualToString:@"123"]) { int purchasedCount=[defaults integerForKey:productIdentifier];//已購買數量 [[NSUserDefaults standardUserDefaults] setInteger:(purchasedCount+1) forKey:productIdentifier]; }else{ [defaults setBool:YES forKey:productIdentifier]; } //在此處對購買記錄進行儲存,可以儲存到開發商的伺服器端 }else{ NSLog(@"購買失敗,未通過驗證!"); } } //監聽購買結果 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{ for(SKPaymentTransaction *tran in transaction){ switch (tran.transactionState) { case SKPaymentTransactionStatePurchased:{ NSLog(@"交易完成"); [self verifyPurchaseWithPaymentTransaction]; [[SKPaymentQueue defaultQueue] finishTransaction:tran]; } break; case SKPaymentTransactionStatePurchasing: NSLog(@"商品新增進列表"); break; case SKPaymentTransactionStateRestored:{ NSLog(@"已經購買過商品"); [[SKPaymentQueue defaultQueue] finishTransaction:tran]; } break; case SKPaymentTransactionStateFailed:{ NSLog(@"交易失敗"); [[SKPaymentQueue defaultQueue] finishTransaction:tran]; [SVProgressHUD showErrorWithStatus:@"購買失敗"]; } break; default: break; } } } //交易結束 - (void)completeTransaction:(SKPaymentTransaction *)transaction{ NSLog(@"交易結束"); [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; } - (void)dealloc{ [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end |
在這裡需要注意幾點,
- 程式碼中的
self.profuctIdArr
所填寫的是你的購買專案的的ID,我這裡是當時填寫的ID 123。- 在監聽購買結果後,一定要呼叫
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
來允許你從支付佇列中移除交易。- 沙盒環境測試appStore內購流程的時候,請使用沒越獄的裝置。
- 請務必使用真機來測試,一切以真機為準。
- 專案的Bundle identifier需要與您申請AppID時填寫的bundleID一致,不然會無法請求到商品資訊。
- 真機測試的時候,一定要退出原來的賬號,才能用沙盒測試賬號
- 二次驗證,請注意區分巨集, 測試用沙盒驗證
在這裡附上截圖:
點選購買按鈕
選擇使用現有Apple ID,填寫測試賬號
確認是否購買
購買成功
最後師列印輸出日誌
到這裡,我們的內購則全部完成了。
如還有不懂得請留言,或者 加群67784110聯絡我。
本文所寫的Demo可在我的GITHUB下載,點此連結。
內購時遇到的問題和解決辦法,我放在下一篇文章中,點此內購時遇到的問題和解決辦法。