zhun#1.通过苹果应用程序商店有三种主要赚钱的方式:
(1)直接收费(与国内大部分用户的消费习惯相悖)
(2)广告
O2O -> Online推广 & Offline交易,闭环
不要砍功能,增加内容,而不是增加功能
(3)内购:应用程序本身的增值产品,游戏装备,应用程序中增值功能同样可以内购
第三方支付:跟应用程序无关的
内购:三(苹果)七(开发商)开
2.内购的五种产品类别
(1)非消耗品(Nonconsumable)一旦购买,终身拥有
指的是在游戏中一次性购买并拥有永久访问权的物品或服务。非消耗品物品可以被用户再次下载,并且能够在用户的所有设备上共享
(2)消耗品(Consumable),买了就用,用了就没
消耗品购买不可被再次下载,根据其特点,消耗品不能在用户的设备之间跨设备使用,除非自定义服务在用户的账号之间共享这些信息
以下三种类别在iBooks中使用,目前iBooks不支持大陆市场
ISBN:每本书的一个ID
(3)免费订阅(Free subscriptions)
(4)自动续费订阅(Auto-renewing subscriptions)
(5)非自动续费订阅(Nonrenewing subscriptions)
3.内购流程
屏幕快照 2017-06-23 下午8.52.39.png
屏幕快照 2017-06-23 下午8.53.58.png
4.要使用内购,需要导入StoreKit框架
5.内购的常用方法
(1)请求有效的产品代号集合
// 1) 实例化产品请求
SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:identifiers];
// 2) 设置代理
[request setDelegate:self];
// 3) 启动请求
[request start];
提示:
- 实例化请求时,必须指定有效的identifiers集合,之所以如此处理,主要是为了确保提交的内购商品真的通过了苹果的审批,处于可用状态!
- 要想获取到准确的可用产品集合,需要通过代理方法实现
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
3 . 越狱用户无法测试内购,但是可以购买
(2)购买指定产品
- 内购的交易过程是通过SKPaymentTransactionObserver监控的,因此需要为IAPHelper添加交易观察者:
// 添加交易观察者对象
[[SKPaymentQueue defaultQueue]addTransactionObserver:sharedInstance];
- 由于发起交易需要使用SKProduct对象,因此需要使用字典记录所有可用的商品
NSMutableDictionary *_productsDict;
(3)验证购买(在购买完成之后,验证)
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
// 购买完成
if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
NSLog(@"购买完成 %@", transaction.payment.productIdentifier);
[queue finishTransaction:transaction];
} else if (transaction.transactionState == SKPaymentTransactionStateFailed) {
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(@"交易失败: %@", transaction.error.localizedDescription);
}
}
}
}
(4)恢复购买(针对非消耗品)
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
购买数据记录问题——系统偏好
[[NSUserDefaults standardUserDefaults]setBool:isPurchased forKey:productId];
[[NSUserDefaults standardUserDefaults]synchronize];
案例
#import "ViewController.h"
#import <StoreKit/StoreKit.h>
@interface ViewController () <SKProductsRequestDelegate, UITableViewDataSource, UITableViewDelegate, SKPaymentTransactionObserver>
/** 所有的商品的数组 */
@property (nonatomic, strong) NSArray *products;
- (IBAction)restore:(id)sender;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 去自己的服务器请求所有想卖商品的ProductIds
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"iapdemo.plist" ofType:nil];
NSArray *productArray = [NSArray arrayWithContentsOfFile:filePath];
NSArray *productIdArray = [productArray valueForKeyPath:@"productId"];
// 去苹果服务器请求可卖的商品
NSSet *productIdSet = [NSSet setWithArray:productIdArray];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdSet];
request.delegate = self;
[request start];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// 3.添加观察者(代理是一对一的关系/观察者一对多)
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// 移除观察者
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
#pragma mark - 实现SKProductsRequest的代理方法
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
// 展示商品
self.products = [response.products sortedArrayWithOptions:NSSortConcurrent usingComparator:^NSComparisonResult(SKProduct *obj1, SKProduct *obj2) {
return [obj1.price compare:obj2.price];
}];
// 2.刷新表格
[self.tableView reloadData];
}
#pragma mark - 实现tableView的数据源和代理方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.products.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"ProductCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
// 1.取出模型
SKProduct *product = self.products[indexPath.row];
// 2.给cell设置数据
cell.textLabel.text = product.localizedTitle;
cell.detailTextLabel.text = [NSString stringWithFormat:@"价格:%@", product.price];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.取出模型
SKProduct *product = self.products[indexPath.row];
// 2.购买商品
[self buyProduct:product];
}
#pragma mark - 购买商品
- (void)buyProduct:(SKProduct *)product
{
// 1.创建票据
SKPayment *payment = [SKPayment paymentWithProduct:product];
// 2.将票据加入到交易队列中
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
#pragma mark - 实现SKPaymentQueue的回调方法
/*
队列中的交易发生改变时,就会调用该方法
*/
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
/*
SKPaymentTransactionStatePurchasing, 正在购买
SKPaymentTransactionStatePurchased, 已经购买(购买成功)
SKPaymentTransactionStateFailed, 购买失败
SKPaymentTransactionStateRestored, 恢复购买
SKPaymentTransactionStateDeferred 未决定
*/
for (SKPaymentTransaction *transation in transactions) {
switch (transation.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(@"用户正在购买");
break;
case SKPaymentTransactionStatePurchased:
NSLog(@"购买成功,将对应的商品给用户");
// 将交易从交易队列中移除
[queue finishTransaction:transation];
break;
case SKPaymentTransactionStateFailed:
NSLog(@"购买失败,告诉用户没有付钱成功");
// 将交易从交易队列中移除
[queue finishTransaction:transation];
break;
case SKPaymentTransactionStateRestored:
NSLog(@"恢复商品,将对应的商品给用户");
// transation.payment.productIdentifier
// 将交易从交易队列中移除
[queue finishTransaction:transation];
break;
case SKPaymentTransactionStateDeferred:
NSLog(@"未决定");
break;
default:
break;
}
}
}
#pragma mark - 恢复购买
- (IBAction)restore:(id)sender {
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
@end