IAP

iOS IAP

iOS In-app Purchase

Posted by MAYBESHEWILL on March 10, 2019

前言

最近有朋友问内购相关的东西,当然这是一个已经存在很久的技术点,自己也学习了一下,趁着还有点热度,所以记录一下这个学习过程。当然既复杂也简单,其实官方文档已经给出了非常权威的说明,这也就是为什么极力推荐官方文档必须看一看的原因,是什么就是什么,说得跟清楚。当然也有一些不接地气的地方,需要自己再实践一下。

In-App Purchase

In-App Purchase Programming Guide

Receipt Validation Programming Guide

Best Practices and What’s New with In-App Purchases

Subscriptions

上边的官方文档其实都应该认真看一看。

概念

IAP 到底是啥玩意?In-App Purchase 即应用内购买,可以理解为Apple 开发的一套非常成熟的B2C 的消费模式,并且整个购买过程都发生在宿主App 内。这里也可以引申出Apple 对于内购是有提成的,毕竟,开发这一套东西可不是简单的,这可不是我说的,这是Apple 自己说的 😂我个人认为App Store 之所以能这么强大,并且盈利很萌,IAP 这套系统,有着决定性的作用。

  • 对用户免费的 App,Apple 不会收取费用;
  • 专门通过广告赚钱的 App,如用户喜欢的免费游戏等,Apple 不会收取费用;
  • 用户在 app 之外注册或购买数字商品的 App 业务交易,Apple 不会收取费用;
  • 销售实体商品的 App (包括叫车和送餐服务),Apple 不会收取费用。

只有使用我们安全的 app 内购买系统,在 app 内购买数字商品和服务,Apple 才会要求收取费用。也就是常说的提成。

接下来试着理解一下上边提到的商品,主要分为以下几种:

  • 消耗型。可以购买多次。即用即买
  • 非消耗型。只能购买一次,也只需要购买一次。比如游戏中的某个人物,某个需要付费解锁的赛道。
  • 自动续期订阅。典型的是连续包月的会员。
  • 非续期订阅。典型的某某视频是一个月会员,这里注意区别一下,他的特点是只能使用一个月,到期即结束
类型 消耗型 非消耗型 自动续期订阅 非续期订阅
购买次数 多次 一次 多次 多次
收据出现次数 一次 一直存在 一直存在 一直存在
设备同步 不会同步 系统同步 系统同步 App自己处理
恢复 不会恢复 系统恢复 系统恢复 App自己处理

其中,订阅。在我的印象中好像最近两年才逐渐流行起来,也是Apple 主推的一种模式。普通的内购商品手续费是30%,而订阅超过一年的用户,手续费则降低到15%。并还可以进行优惠促销活动。

Introductory Offers

自动续期订阅 - App Store - Apple Developer 其中免费试用是大部分App 在使用的一种方法,免费试用时间结束后就需要进行订阅了。这个是否正在享受优惠也可以在内购凭证中验证。下边两个Key 的值,当有一个为YES,那么就说明当前用户正在享受优惠

  • is_in_intro_offer_period 是否在享受折扣价
  • is_trial_period 是否是免费试用

其中App Store推广 也被越来越多的应用,即在App Store 搜索结果中出现相关促销,用户可以直接点击并调起App 进行付费,相当方便。这里需要实现相关代理方法。可以下图,这个可以是订阅也可以是App 内购买项目。 IMG_6483.jpg

代码怎么写

具体路程不再赘述,也有大量的Sample Code 可以直接拿过来用,总结一下大概是以下几个步骤。 StoreKit 提供了核心API SKPaymentQueue,我们的操作都围绕这个东西,然后关注代理方法就可以了。

  • App通过SKProductRequest来请求商品
  • 通过SKProductsRequestDelegate中的代理方法,获得SKProduct
  • 用SKProduct生成SKMutablePayment,添加到SKPaymentQueue里
  • 通过SKPaymentTransactionObserver中的代理方法,获得正在购买的回调
  • 通过SKPaymentTransactionObserver中的代理方法,获得正在购买成功的回调
  • App用本地的收据和用户ID 等信息,通知服务端IAP 购买成功
  • 服务端发送收据到App Store,验证收据
  • App Store 返回验证收据的结果
  • 服务端为用户发放商品
  • 服务单通知客户端结果
  • 客户端完成SKPaymentTransaction

其中服务端并不是必须的。Apple 本身已经提供了收据验证,包括本地验证和App Store 验证,当然严格意义上是需要有后端作校验的,可以使购买过程更加严谨。其中获取收据之后是会存储SanBox 路径的 获取:

NSBundle *mainBundle = [NSBundle mainBundle]; NSURL *receiptURL = [mainBundle appStoreReceiptURL];

一个收据解剖一下的样子可以看下图

验证收据的过程大概可以分为:

  • 找到收据。 如果未找到收据,则验证失败。
  • 验证收据的真实性和完整性。 收据必须由Apple正确签名,不得被篡改。
  • 解析收据以提取包标识符,包版本等属性。
  • 验证在收据中找到的包标识符是否与应用程序的包标识符匹配。 对捆绑版本执行相同操作。
  • 计算设备GUID的哈希值。 计算的散列基于特定于设备的信息。
  • 如果使用批量购买计划,请检查收据的到期日期。

由于本地去解密一个收据验证的过程比较复杂,所以建议直接用App Store 验证收据。可能很多人不知道,收据这个东西不光是部署了In-app Purchase 才会有,普通的下载安装一个免费的app 也是有收据的。

由于未上线的App 统一使用SandBox 环境进行,所以当处于审核期间的App 在进行Receipt 验证的时候需要看status code 是否为 21007,是则需要在SandBox 环境中验证,否则是一定会被拒的。因为两个环境的URL 是不一样。

还有一点需要注意的是,如果是订阅制的App,需要加上下边两个点,否则也一定会被拒。

  • App Store的描述信息里加上《自动续费服务说明》
  • App内的充值界面提供两个链接:会员服务协议,自动续费服务规则。

先整理到这里,想到什么再补充。

Receipt Validation · objc.io

官方文档 Validating Receipts With the App Store

补充: 行业新闻

因未使用苹果专门付费渠道,丁香医生App无法更新

𝑰 𝒍𝒐𝒗𝒆 𝑨𝒑𝒑𝒍𝒆 . 𝑷𝒆𝒂𝒄𝒆!

文章使用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议