iOS开发之 - 内购

作者: Q以梦为马 | 来源:发表于2016-10-24 19:24 被阅读954次

电商之类的 app 大多用的都是第三方支付(支付宝微信等支付),但是在某种特殊情况之下,我们却不得不使用内购。比如商品是在本 app 中使用和消耗的(游戏币游戏道具等),就一定要用内购,苹果强制的,否则会被拒绝上线。因此作为 iOS 开发者,不光要了解第三方支付,对内购也要有一定的认识!

一、什么是内购?

内购是苹果推出的一种支付方式。说白了内购就是苹果获取利润的方式之一。如果我们使用第三方支付,只会支付少量的💰,但使用内购却要支付很多💰💰💰💰💰💰💰💰,要和苹果三七分帐(以前是四六分😢)。

二、内购产品的类别

官方的注释写的很清楚了,内购有五种产品类别,简介如下:

  • 非消耗品(Nonconsumable)
    指的是在游戏中一次性购买并拥有永久访问权的物品或服务。非消耗品物品可以被用户再次下载,并且能够在用户的所有设备上使用。
  • 消耗品(Consumable)
    消耗品购买不可被再次下载,根据其特点,消耗品不能在用户的设备之间跨设备使用,除非自定义服务在用户的账号之间共享这些信息。
    以下三种类别在iBooks中使用,目前iBooks不支持大陆市场
  • 免费订阅(Free subscriptions)
  • 自动续费订阅(Auto-renewing subscriptions)
  • 非自动续费订阅(Nonrenewing subscriptions)

三、苹果官方的内购流程

内购流程
  • 白话文如下⬇️
  1. 程序向服务器发送请求,获得一份产品列表。
  2. 服务器返回包含产品标识符的列表。
  3. 程序向App Store发送请求,得到产品的信息。
  4. App Store返回产品信息。
  5. 程序把返回的产品信息显示给用户(App的store界面)
  6. 用户选择某个产品
  7. 程序向App Store发送支付请求
  8. App Store处理支付请求并返回交易完成信息。
  9. 程序从信息中获得数据,并发送至服务器。
  10. 服务器纪录数据,并进行审(我们的)查。
  11. 服务器将数据发给App Store来验证该交易的有效性。
  12. App Store对收到的数据进行解析,返回该数据和说明其是否有效的标识。
  13. 服务器读取返回的数据,确定用户购买的内容。
  14. 服务器将购买的内容传递给程序。

四、代码实现

4.1 项目的Bundle identifier需要与您申请AppID时填写的bundleID一致,不然会无法请求到商品信息。

Bundle identifier

4.2要使用内购,需要导入 StoreKit 依赖库


入StoreKit

4.3代码部分

#import "UITableController.h"
#import <StoreKit/StoreKit.h>

@interface UITableController () <SKProductsRequestDelegate, UITableViewDelegate, UITableViewDataSource, SKPaymentTransactionObserver>

/** 所有商品 */
@property (nonatomic, strong) NSArray *products;
@end

@implementation UITableController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self requestProducts];

}

// 请求可卖商品
- (void)requestProducts {
    
    // 1.从服务器请求所有商品的ProductIds
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"iapdemo.plist" ofType:nil];
    NSArray *productArray = [NSArray arrayWithContentsOfFile:filePath];
    
    // 2.获取productId
    NSArray *productIdArray = [productArray valueForKeyPath:@"productId"];
    
    // 3.请求可卖的商品
    NSSet *productIdSet = [NSSet setWithArray:productIdArray];
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdSet];
    request.delegate = self;
    [request start];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    // 添加观察者
    [[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
{
    // 1.展示商品
    self.products = [response.products sortedArrayWithOptions:NSSortConcurrent usingComparator:^NSComparisonResult(SKProduct *obj1, SKProduct *obj2) {
        return [obj1.price compare:obj2.price];
    }];
    
    // 2.刷新表格
    [self.tableView reloadData];
}

// 请求失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {

    NSLog(@"%@", [error localizedDescription]);
}

// 请求结束
- (void)requestDidFinish:(SKRequest *)request {

    NSLog(@"请求结束");
}


#pragma mark - 实现tableView的数据源和代理方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.products.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"productCellId";
    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
{
    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(@"购买过该商品");
                [queue finishTransaction:transation];
                break;
                
            case SKPaymentTransactionStateDeferred:
                NSLog(@"未决定");
                break;
            default:
                break;
        }
    }
}

- (void)dealloc {

    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

另外使用这个方法即可恢复购买

[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

** <end>**


相关文章

  • iOS 苹果内购流程

    本文参考: iOS开发之内购完全笔记 iOS开发内购全套图文教程 iOS应用程序内购/内付费(一) 代码...

  • iOS开发之 - 内购

    电商之类的 app 大多用的都是第三方支付(支付宝微信等支付),但是在某种特殊情况之下,我们却不得不使用内购。比如...

  • iOS应用程序内购(IAP)

    参考:iOS开发内购全套图文教程

  • applePay

    # iOS应用内支付(内购)的个人开发过程及坑!

  • ios 内购开发

    pragma mark ===================== 内购支付的 /*stringType=2购买...

  • iOS开发内购

    http://www.jianshu.com/p/86ac7d3b593a http://www.jianshu....

  • iOS 内购开发

    一.设置协议 1.打开App Store Connect,选择 协议,税务和银行业务 2.因为我已经添加过信息了,...

  • iOS 开发 - 内购

    前言 关于 iOS 内购的介绍这里就不多讲了,有兴趣的同学可以去看苹果的官方介绍。官方的教程已经非常详细了,按照官...

  • iOS支付

    支付宝支付 支付宝支付支付宝补充 微信支付 微信支付 内购 iOS开发 内购流程

  • iOS开发系列--通讯录、蓝牙、内购、GameCenter、iC

    iOS开发系列--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开发汇总http...

网友评论

  • 搁浅的晴天:问一下,已经批准的内购可以修改吗
  • 0x00chen:楼主在吗,我遇到一个巨难解决的问题,再添加沙箱技术测试员的时候,总是添加不上,一种错误是“java.lang.NullPointerException”,还有一种错误是"此电子邮件地址已与现有 Apple ID 关联。"这该怎么解决啊:sob:
    两好三坏:电子邮件随便写一个,不要与现有 AppleId 有关联;
  • Dismon:请问,你有没有遇到这种情况,测试内购的时候,总是成功一次,失败一次,然后成功一次,失败一次

    第一次能购买成功,然后第二次购买能够弹出确认框,点击购买返回 SKErrorDomain Code=0 无法连接 itunes 的错误,然后再次购买,又能成功
    爱自由鹏:@Dismon 请问解决了吗,我这也是一次成功 一次失败
  • ibiaoma:简书里的打赏功能是内购吗?
    ibiaoma:@iOS_以梦为马 可是苹果就判定我的是,还要找他们理论
    Q以梦为马: @ibiaoma 简书里的打赏和微信QQ红包一样应该都不是,欢乐斗地主里的欢乐豆是的😄

本文标题:iOS开发之 - 内购

本文链接:https://www.haomeiwen.com/subject/jhuluttx.html