首先我們知道什么是內(nèi)購?
- 內(nèi)購就是在我們的App中能夠購買東西
- 當(dāng)然購買東西包括手機(jī),毛絨玩具等日常用品,也包括購買虛擬的例如雙倍經(jīng)驗卡,大血瓶等.
- 那么什么時候使用內(nèi)購呢?
我們還需要知道蘋果公司的盈利模式:
通過蘋果應(yīng)用程序商店有三種主要賺錢的方式:
1. 直接收費(與國內(nèi)大部分用戶 的消費習(xí)慣相悖)
1.1 廣告
1.2 O2O -> Online推廣 & Offline交易,閉環(huán)
2. 內(nèi)購:應(yīng)用程序本身的增值產(chǎn)品,游戲裝備,應(yīng)用程序中增值功能同樣可以內(nèi)購
內(nèi)購:三(蘋果)七(開發(fā)商)開
3.第三方支付:跟應(yīng)用程序無關(guān)的
蘋果不能從中獲利
所以.當(dāng)我們在應(yīng)用中有銷售行為的話,能不走內(nèi)購就不走內(nèi)購,但是增值業(yè)務(wù)的話,必須是走內(nèi)購流程,否則在上架App Store的時候是會被拒絕的.
但是,我們?nèi)绻亲鲭娚填怉pp,那么久不要走內(nèi)購了,因為你的產(chǎn)品銷量越大,你就虧的越多,因為App開發(fā)商還要給蘋果30%的分紅,哦?不,是蘋果先拿到錢,然后再給你70%的分紅.
so,內(nèi)購主要是針對APP內(nèi)置的增值服務(wù)的,就是虛擬商品,一把屠龍寶刀,不就是一張圖片嗎?所以蘋果要分紅.那么App做內(nèi)購的步驟有哪些呢?
1.首先你要有一個開發(fā)者賬號 需要99$.
2.你要有一部 iOS 真機(jī),未越獄版本,越獄版不能測試,只能購買
3.你需要在 蘋果開發(fā)者網(wǎng)站 配置相關(guān)證書 .cer 和 .mobileprovision證書 配置App相關(guān)內(nèi)購信息
3.1 -- 配置App(必須要有一些消耗品或者非消耗品), AppID 不能使用統(tǒng)配符. (越獄手機(jī)不能測試內(nèi)購,但是能購買內(nèi)購商品).
3.1.1 --設(shè)置方式: 在 iTunes Connect 網(wǎng)站里, ->"App Store" 添加內(nèi)購APP, 然后再進(jìn)入”功能"(設(shè)置 內(nèi)購產(chǎn)品,:非消耗型項目, 一次性消費型項目)
3.2 -- 測試賬號: 不用真的花錢.
3.2.1 -- 設(shè)置方式: “功能”—>” “在用戶和職能”—> “沙箱測試員” —>添加測試賬號" .這個郵箱瞎寫,但是密碼要記住
3.3 -- 配置賬戶信息 借記卡/信用卡都行
3.3.1--設(shè)置方式: “功能”—>”協(xié)議\稅務(wù)和銀行業(yè)務(wù)” (都是老板的信息,錢由蘋果公司打給老板)
3.4 -- 在回到 App Store 里將剛剛那些 設(shè)置的Appde內(nèi)購項目添加到 你的App里
很重要卻很容易忽視的細(xì)節(jié)
>>> 在使用未越獄的真機(jī)測試內(nèi)購的時候,因為使用的是測試賬號,是真機(jī).
>>>所以需要在真機(jī)的 “設(shè)置”—> “iTunes Store 和 App Store” —>注銷真實的賬號(否則就真扣錢了) —>換成 剛剛在develop網(wǎng)站里填寫的 內(nèi)購測試賬號
>代碼是敲不完的,我們學(xué)的是思路.
>代碼源于生活,又高于生活.
那么就讓我們結(jié)合實際商場購物來理一下我們寫代碼思路:
1> App 想蘋果服務(wù)器請求可銷售商品
2> 代理方法獲得可銷售商品
3> 展示商品(tableView等)
4>用戶選擇商品
5> 根據(jù)用戶選擇的商品,給用戶小票(商品轉(zhuǎn)payment類型),那小票去排隊
6> 監(jiān)聽 交易隊列變化
7> 用戶去交錢,我們監(jiān)聽用戶付款狀態(tài)
8> 付款成功, 我們給用戶相應(yīng)的增值服務(wù)
9> 結(jié)束交易 (否則用戶下一次進(jìn)來還是在交易)

App內(nèi)購圖示

官方內(nèi)購配圖
下面我們來上代碼:
//內(nèi)購需要導(dǎo)入框架
#import <StoreKit/StoreKit.h>
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//需要在 APP中 設(shè)置 bundel ID 和 在 網(wǎng)站注冊時候一樣.
// 有內(nèi)購需求的App 需要 安裝在App里按鈕 蘋果develop 網(wǎng)站里面配置好 ios_development.cer 和 xxx.mobileprovision(配置文件),只要雙擊一下,一閃就算安裝好了
}
0>首先:我們需要讀取JSON文件
//0 需要獲得可銷售商品(就是我們的APP內(nèi)購商品的 productsID)
NSString * productPath = [[NSBundle mainBundle] pathForResource:@"products.json" ofType:nil];
//把JSON 轉(zhuǎn)為 data
NSData *jsonData = [NSData dataWithContentsOfFile:productPath];
//反序列化
NSArray *productArr = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
NSLog(@"%@",productArr);
//我們需要取出 [{productId:"xxxx"}] 數(shù)組里的字典里面的 key 對應(yīng)的Value值
//KVC 取值
NSArray *tempArr2 = [productArr valueForKey:@"productId"];
NSLog(@"%@",tempArr2);
1>我們想蘋果發(fā)送銷售App內(nèi)購商品的請求
//1>App向蘋果請求可銷售商品
SKProductsRequest * proRequest = [[SKProductsRequest alloc]initWithProductIdentifiers:[NSSet setWithArray:tempArr2]];
2>通過代理獲得 蘋果返回的課銷售商品
//2 >獲取可銷售的 商品 (通過代理)
//2.1
proRequest.delegate = self;
//2.2 需要開始請求
[proRequest start];
/** 2.3
* 當(dāng)獲取到蘋果允許銷售的商品 時候調(diào)用
*
* @param request 銷售內(nèi)購商品的請求
* @param response 蘋果對我的請求的返回的響應(yīng) (里面有產(chǎn)品數(shù)組,以及不允許銷售商品的 ID)
*/
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
//遍歷,獲得每一個可銷售商品的信息
for (SKProduct *product in response.products) {
NSLog(@"產(chǎn)品價格%@---產(chǎn)品ID %@---產(chǎn)品標(biāo)題 %@----產(chǎn)品描述 %@",product.price,product.productIdentifier,product.localizedTitle,product.localizedDescription);
}
//給全局?jǐn)?shù)組賦值,里面裝可銷售 商品
self.productsArray = response.products;
//賦值后,需要刷新數(shù)據(jù)源
[self.tableView reloadData];
}
//2.4 還要在上面遵守代理
@interface ViewController ()<SKProductsRequestDelegate>
//2.5 并且需要賦值一個數(shù)組,所以我們上面定義一個數(shù)組
/**
* 裝所有 可銷售內(nèi)購商品的數(shù)組
*/
@property (nonatomic, strong) NSArray * productsArray;
3>展示數(shù)據(jù)(可銷售的內(nèi)購商品)
//3 通過tableview展示數(shù)據(jù) 可銷售商品的數(shù)據(jù)
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.productsArray.count;
}
//3.1
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *ID = @"storeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
SKProduct *product = self.productsArray[indexPath.row];
cell.textLabel.text = product.localizedTitle;
// cell.detailTextLabel.text = product.price.stringValue;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@",[product.price description]];
return cell;
}
3 補(bǔ)充 :上面給cell賦值時候,不注意引起Crash.分享如下:
/*引起B(yǎng)UG源代碼:
cell.detailTextLabel.text = product.price;--->引起Crash.報錯如下 是因為price類型是 NSDecimalNumber.
報錯如下:
reason: '-[NSDecimalNumber isEqualToString:]: unrecognized selector sent to instance 0x7fa11ad28f10'
更改方式1: cell.detailTextLabel.text = product.price.stringValue;
更改方式2: cell.detailTextLabel.text = [NSString stringWithFormat:@"%@",[product.price description]];
(更改方式1/2 留下一個就行.)
*/
```
> 4> 用戶選擇購買那些增值服務(wù)
//4 用戶選擇商品(屠龍刀 ,大藥瓶等), 代理方法
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// 4.1 取出用戶選擇的產(chǎn)品
SKProduct *product = self.productsArray[indexPath.row];
}
> 5> 用戶拿小票排隊等待付款
````
//5.1 拿商品轉(zhuǎn)換類型 (根據(jù)商品是什么樣的,商家給用戶小票,讓用戶拿著小票去排隊付款)
SKPayment * payment = [SKPayment paymentWithProduct:product];
//5 . 排隊,等付款
[[SKPaymentQueue defaultQueue] addPayment:payment];
````
> 6> 監(jiān)聽付款隊列的變化
````
//6 監(jiān)聽 付款隊列的變化,增加一個監(jiān)聽者,遵守SKPaymentTransactionObserver 協(xié)議就行
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
//6.1在上面遵守協(xié)議
@interface ViewController ()<SKProductsRequestDelegate,SKPaymentTransactionObserver>
````
>7 監(jiān)聽付款隊列的變化 輪到自己付款.
````
/**
* 7. 監(jiān)聽付款隊列發(fā)生了變化時候調(diào)用 直白:更新付款隊列的情報
*
* @param queue 付款隊列 交易隊列
* @param transactions 所有的交易(別人也在交易,存在許多交易在隊列里,放進(jìn)一個數(shù)組里)
*/
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{}
````
>8 > 根據(jù)付款的狀態(tài),提供對應(yīng)的增值服務(wù)
>9 > 如果交易結(jié)束,關(guān)閉交易
````
/*
SKPaymentTransactionStatePurchasing, // 交易正在被加入隊列
SKPaymentTransactionStatePurchased, // 交易在隊列中, 用戶已經(jīng)付款.客戶端需要完成交易
SKPaymentTransactionStateFailed, // 交易失敗
SKPaymentTransactionStateRestored, // 交易從交易歷史中被恢復(fù). 客戶端需要完成交易.
SKPaymentTransactionStateDeferred // 交易暫時不確定. 加入交易隊列了,在猶豫要不要付款. iOS8新增
*/
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
//遍歷所有交易,得出沒有交易的狀態(tài)
for (SKPaymentTransaction * payTran in transactions) {
if(payTran.transactionState == SKPaymentTransactionStatePurchased){
//8. 用戶付款成功,我們提供相應(yīng)增值服務(wù).
NSLog(@"用戶已經(jīng)付款,我方App給他提供增值服務(wù)");
//9 結(jié)束交易. 操作隊列結(jié)束本次 交易.
[[SKPaymentQueue defaultQueue] finishTransaction:payTran];
}
if(payTran.transactionState == SKPaymentTransactionStateRestored){
//8. 用戶付款成功,我們提供相應(yīng)增值服務(wù).
NSLog(@"用戶已經(jīng)付款,我方App給他提供增值服務(wù)");
//9 結(jié)束交易. 操作隊列結(jié)束本次 交易.
[[SKPaymentQueue defaultQueue] finishTransaction:payTran];
}
//增加一個判斷.如果失敗,失敗的原因是什么(不是用戶主動取消的情況)
if (payTran.transactionState == SKPaymentTransactionStateFailed) {
if (payTran.error.code != SKErrorPaymentCancelled) {
NSLog(@"交易失?。?%@", payTran.error.localizedDescription);
}
}
}
}
````
> 10 用戶如果換手機(jī)了,怎么辦?之前購買過的可以設(shè)置一鍵恢復(fù)
````
// 10 :一鍵 恢復(fù)購買裝備 (例如換手機(jī)了)
//在viewdidLoad里增加一個復(fù)位按鈕
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"測試";
UIBarButtonItem *restoreButton = [[UIBarButtonItem alloc]initWithTitle:@"恢復(fù)購買" style:UIBarButtonItemStylePlain target:self action:@selector(restoreButtonClick:)];
self.navigationItem.leftBarButtonItem = restoreButton;
}
-(void)restoreButtonClick:(UIButton *)sender{
// 付款隊列 恢復(fù) 已經(jīng)完成的 所有交易
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
// 付款隊列 恢復(fù) 已經(jīng)完成的 所有交易 需要應(yīng)用程序的 用戶名. (用戶可能有3個號)(用戶填寫用戶名去后臺驗證密碼)
// [[SKPaymentQueue defaultQueue] restoreCompletedTransactionsWithApplicationUsername:<#(nullable NSString *)#>];
}
````
###由于時間倉促,以及個人能力有限,不足之處.或者哪里有不同意見.好的想法還希望不吝告知.共同進(jìn)步.碼字不容易啊!
##最后:源碼在[我的iOS in_App Purchases(內(nèi)購)](https://github.com/HHQBOOK/in_App_Purchases)