内购

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.内购流程

内购_第1张图片
屏幕快照 2017-06-23 下午8.52.39.png
内购_第2张图片
屏幕快照 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];

提示:

  1. 实例化请求时,必须指定有效的identifiers集合,之所以如此处理,主要是为了确保提交的内购商品真的通过了苹果的审批,处于可用状态!
  2. 要想获取到准确的可用产品集合,需要通过代理方法实现
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response

3 . 越狱用户无法测试内购,但是可以购买

(2)购买指定产品

  1. 内购的交易过程是通过SKPaymentTransactionObserver监控的,因此需要为IAPHelper添加交易观察者:
// 添加交易观察者对象
[[SKPaymentQueue defaultQueue]addTransactionObserver:sharedInstance];
  1. 由于发起交易需要使用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 

@interface ViewController () 

/** 所有的商品的数组 */
@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

你可能感兴趣的:(内购)