前言
最近有朋友问内购相关的东西,当然这是一个已经存在很久的技术点,自己也学习了一下,趁着还有点热度,所以记录一下这个学习过程。当然既复杂也简单,其实官方文档已经给出了非常权威的说明,这也就是为什么极力推荐官方文档必须看一看的原因,是什么就是什么,说得跟清楚。当然也有一些不接地气的地方,需要自己再实践一下。
In-App Purchase Programming Guide
Receipt Validation Programming Guide
上边的官方文档其实都应该认真看一看。
概念
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 内购买项目。
代码怎么写
具体路程不再赘述,也有大量的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内的充值界面提供两个链接:会员服务协议,自动续费服务规则。
先整理到这里,想到什么再补充。
补充: 行业新闻
𝑰 𝒍𝒐𝒗𝒆 𝑨𝒑𝒑𝒍𝒆 . 𝑷𝒆𝒂𝒄𝒆!
文章使用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议