iOS开发IAP (In-App purchase)

释放双眼,带上耳机,听听看~!

哪些可以作为IAP商品

  1. 虚拟物品
  2. App某些功能
  3. 服务

IAP产品种类

  1. Non-consumable products
    • 同一个AppleID 只能购买一次,再次购买会提示”已购买”;比如某个关卡,或者杂志
  2. consumable products
    • 同一个AppleID 可以购买多次,比如游戏中的金币
  3. Auto-renewable subscriptions
    • 同一Apple ID 在购买时会检查是否购买过,如果购买过并且还在续期权限中,系统会提示已购买而无法再购买;如果购买过之后取消过,则可以再次购买(自动续费购买 实际意义上表示签订协议,之后取消操作类似于关闭;关闭之后可以选择打开,如果你是在续期期限间关闭再打开,是不会重复扣费;如果超出期限再打开,会进行扣费)
  4. Non-renewable subscriptions
    • 同一Apple ID 可以购买多次,如果购买过并且权限未过期,系统会提示续期,可以再次购买。 
      productType.png

IAP购买流程

  1. 基本流程 
    iapProcess.png
  • 每个IAP产品,都有唯一的ProductId与之对应(可以在itc后台配置,比较坑的是,创建之后无法物理删除,即使在itc后台删除掉产品,用相同的ProductId会提示已被占用)
  • 通过ProductId可以发送请求获取具体的产品信息(描述、价格、时限等)
    //send request
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:productID]];
    request.delegate = self;
    ....
    [request start];
    
      //SKRequestDelegate callback
    - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{....}
    - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{....}
    
  • 系统会弹窗,展示IAP产品信息 
    IMG_5314.PNG
  • 用户确认后,发起支付请求
  SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
payment.applicationUsername = applicationUsername; //可以唯一标识用户账号即可,是用于apple检测非法活动
[[SKPaymentQueue defaultQueue] addPayment:payment];
  • 用户支付后,系统处理支付请求,返回此次transaction信息
//需要监听Payment Queue,建议是在didFinishLaunchingWithOptions:时就增加监听
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
//处理回调事件
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
//购买完成...
break;
case SKPaymentTransactionStateFailed:
//交易失败...
break;
case SKPaymentTransactionStateRestored:
//恢复交易...
break;
case SKPaymentTransactionStatePurchasing:
//交易正在进行..
break;
default:
break;
}
}
}

交易信息可能会重复或者伪造;需要进行小票验证,分为两种:本地验证和服务端验证(以下内容会详细介绍)

  • 解锁相关内容,需要关闭此次交易,否则系统会一直返回此次交易
//如果涉及到下载的内容,需要等下载内容完成后关闭交易
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

如何测试

  1. 测试环境的自动订阅周期和线上是不同的,具体参见链接
    testSubscription.png

小票验证

本地验证

本人没有尝试过本地验证小票的方式,简单看了下官方文档的介绍,以下是摘自官网的步骤

image.png

服务端验证

主要是将App获取到的小票凭证发送给自己服务器,通过自己服务器和AppStore服务器连接,并发送小票凭证,根据获取之后的响应数据进行判断。

  1. 小票格式
    • iOS6格式: 交易支付结果返回的transactiontransaction.transactionReceipt
    • iOS7格式: 本地获取 [[NSBundle mainBundle] appStoreReceiptURL]
  2. 服务端向AppStore发送数据
    {
    "receipt-data":"", //小票凭证进行base64编码后的数据
    "password":"",  //小票凭证中含有自动续费的内容时,必须有该参数(需要在itc后台生成)
    "exclude-old-transactions":false //仅和 iOS7样式的订阅类小票相关。 如果为 true,结果只包括所有订阅的最新续期交易
    }
    
  3. 响应数据
    • iOS6格式小票凭证验证结果 
      iOS6_receiptResult.png
    • iOS7格式小票凭证验证结果 
      iOS7_receiptResult..png

不仅小票格式不同,结果会不一致;根据IAP产品种类的不同,返回结果的字段也会有所差异,比如说pending_renewal_info只有iOS7的小票且包含自动续费内容才会返回,里面字段的内容也是和自动续费相关;如果想知道字段各个含义可以移步
Validating Receipts With the App Store
小票具体字段含义

关于自动订阅

  1. 自动订阅可以提供给用户一段试用期限,试用时长可以自定义(试用之前不会进行扣费)
  2. 订阅可以分组和服务分级
    • 同一个订阅组中订阅时互斥的;用户只能一次订阅一个群组中的一个选项
    • 同一订阅群组中的每个IAP产品都分配到一个订阅等级;订阅可以进行升级、降级、跨级
      • 升级。当顾客从较低等级的订阅切换到更高等级的订阅时。顾客先前的 App 内购买项目金额将会按比例退还到原始的付款方式。新的 App 内购买项目将收取完整价格并立即生效,这会将顾客的续期日期更改为升级日期。
      • 降级。当顾客从较高等级的订阅切换到较低等级的订阅时。在下一个续期日期,会以新费率向顾客收费。
      • 跨级。当顾客在同一等级的订阅间进行切换时。如果 App 内购买项目的时限相同,那么顾客先前的 App 内购买项目金额将会按比例退还到原始的付款方式。新的 App 内购买项目将收取完整价格并立即生效,这会将顾客的续期日期更改为升级日期。如果 App 内购买项目的时限不同,那么跨级将会在顾客的下一个续期日期生效。
        如下图itc管理后台,配置有三个等级,每个等级有两项内容

        subscriptionGroup.png
  3. 以自然月进行扣费;Apple 会在过期时间前24h进行尝试自动订阅
  4. 查看自己购买过的自动订阅内容
    • 可以进行取消;但即使取消订阅,订阅项一直会展示,随时可以再重新订阅,如果此次点击购买时间在你上次订阅周期且不在上面升降级条件中,不会进行扣费,等到下个周期才会扣费
    • 设置 – [iTunes Store与App Store] – 点击[Apple ID]- 选择[查看Apple ID] – 点击[帐户设置]-点击[订阅]
    • 另一种方式跳转到管理订阅:https://buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/manageSubscriptions
  5. 想要了解自动续费配置流程可以移步创建自动续期订阅
  6. 自动续费整体流程 
    autoRenew.png
statusUpdateNotification

上面介绍的自动续费验证流程依靠客户端App的开启,Apple为自动续费提供了一种server-to-server的通知

  • 需要在itunes connect后台中填入处理notification的url(ATS;具体操作步骤见启用针对自动续期订阅的服务器通知
  • 针对自动订阅通知类型:
    • INITIAL_BUY
    • CANCEL
    • RENEWAL
    • INTERACTIVE_RENEWAL (取消后又重新订阅)
    • DID_CHANGE_RENEWAL_PREFERENCE(修改自动订阅,升降级)
  • 但是我们在测试环境测试时,发现并不是每次都能收到通知,具体什么原因还不是清楚
    最近看到论坛上statusUpdateNotification not getting renewal notification type,感觉有点坑,这些通知类型,不是字面上理解的意思

    If you read the description of the RENEWAL event, you will note - "Automatic renewal was successful for an expired subscription. Check Subscription Expiration Date to determine the next renewal date and time." In general, iTunes will attempt to charge the user account a day before an auto-renewing subscription is scheduled to expire. If the renewal is successful, there is no server-to server notification because the auto-renewing subscription did not enter into an expired state. However, in the few cases that iTunes is unable to renew the subscription (generally there was a connection problem with the credit card server) and the auto-renewing subscription is not renewed before the expiration_date passes, the auto-renewing subscription is technically considered “expired”. However, iTunes will still continue to attempt to renew the subscription. It iTunes is successful, then the “RENEWAL” event is sent. for this reason, the advice is presented - “Check Subscription Expiration Date to determine the next renewal date and time.”
    
SKReceiptRefreshRequest
  1. 可以刷新本地的小票数据,获取到最新的小票数据
  2. 可以看下它和RestoreCompletedTransactions区别

参考资料

  1. App 内购买项目配置流程
  2. About Receipt Validation
  3. In-App Purchase Programming Guide
  4. wwdc2017 中303和305 关于storekit内容
    5.IAP slider

人已赞赏
iOS文章

iOS开发内购最新版(埋坑)

2020-2-3 12:32:58

iOS文章

iOS开发应用内支付自动续费 连续包月 审核注意问题

2020-2-3 20:35:36

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
有新消息 消息中心
搜索