作者:iHTCboy
前言
WWDC21 是历年来 In App Purchase(IAP,内购内购买)最大的变化,分别推出了 StoreKit 2、App Store Server API、App Store Server Notifications V2 三大特性,去年我们也编写了 《苹果iOS内购三步曲:App内退款、历史订单查询、绑定用户防掉单!— WWDC21》 文章,所以我们本文不会再深入提及去年的更新,大家如果不太熟悉,可以先温习一下。本文将对今年 WWDC22 带来的变化,从整体的视角一起回顾。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c7fWy8Qe-1657516283945)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cd35fcd8bccc4fbb95b66c57febc9d65~tplv-k3u1fbpfcp-watermark.image?)]
以下是编者对 In App Purchase 这几年重要的更新或调整的梳理:
时间 | 事件 | 变化 | 来源 |
---|---|---|---|
2020 年 11 月 18 日 | App Store 小型企业计划 | 日历年收入在 100 万美元以下的小型和独立开发者将可以享受 15% 的佣金费率,仅为 App Store 标准佣金费率 30% 的一半,付费 app 和 App 内购买项目的收益抽成将降低 15%。 | 1、2 |
2020 年 11 月 23 日 | 针对在线多人活动的 app 内购买项目规定 | 3.1.3(d) 一对一服务:如果您的 App 允许购买两个人之间的一对一实时服务 (例如,学生辅导、医疗咨询、看房服务或健身训练),您可以使用 App 内购买项目以外的其他购买方式来收取相应款项。一对几和一对多的实时服务则必须使用 App 内购买项目。 | 1、2 |
2021 年 8 月 26 日 | Apple 与美国开发者就 App Store 达成和解 | 美国开发者提起的 App Store 集体诉讼与苹果和解,Apple 设立一亿美元的基金来帮助美国的小型业务开发者,符合条件的开发者获得 250 美元至 3 万美元的现金)。 | 1、2 |
2021 年 9 月 1 日 | 日本公平贸易委员会结束对 App Store 的调查 | 3.1.3(a) “阅读器”类型的 App:此类 App 可以允许用户访问先前购买的内容或内容订阅 (具体包括:杂志、报纸、图书、音频、音乐和视频)。各种阅读器 App 可以为使用免费版本的用户提供帐户创建功能,并为现有用户提供帐户管理功能。阅读器 App 开发者可以申请 External Link Account 授权,以在其 App 中提供一个指向其拥有或负责维护的网站的信息链接,以便用户创建或管理帐户。了解有关 External Link Account 授权的更多信息。 | 1、2 |
2022 年 1 月 14 日 | 针对在荷兰 App Store 上分发的约会 App 的更新 | 荷兰消费者和市场管理局(ACM)允许荷兰 App Store 上的约会 App 开发人员与用户共享额外的付款处理选项。允许仅在荷兰 App Store 中分发的约会 App 在 App 内提供其他支付处理选项。开发者可以使用 StoreKit 外部购买授权,苹果降低 3% 的佣金,可与小型企业计划或自动续期订阅的 15 %佣金叠加,最低抽成 12 %。 | 1、2 |
2022 年 5 月 16 日 | 自动续期订阅提价更新 | 目前,当自动续期订阅提价时,订阅者必须在 App 提价之前选择接受。新调整:符合某些特定条件并在提前通知用户的情况下,开发者在为自动续订订阅提价时,无需用户额外采取行动,亦不会中断服务。(前提条件:每年提价不超过一次,同时订阅价格上调不超过 5 美元和 50%,或者年度订阅价格上调不超过 50 美元和 50%,并且是在法律允许的范围内。) | 1、2 |
2022 年 6 月 30 日 | 针对在韩国分发 App 的更新 | 允许仅在韩国 App Store 中分发的 App 在 App 内提供其他支付处理选项。开发者可以使用 StoreKit 外部购买授权,但苹果收益抽成 26%。 | 1、2 |
说到内购,环绕着的新闻,总起到一些波澜,从 2021 年苹果推出 App Store 小型企业计划,降低 15% 的佣金,大家的讨论一直源源不断,对于小型企业和开发者,确实是明显感受到 15% 带来的回报!本文不去讨论合理性,App Store 从 2008 年推出就是一个创举,它改变了世界对 App 的认识。我们本文更多的是讨论如果利用这些变化,为用户提供更好的服务或体验!
本文主要从四方面进行探讨:
- StoreKit 2
- App Store Server API
- App Store Server Notifications V2
- App Store Connect
StoreKit 2
StoreKit 2 和 Original StoreKit,应该怎么选择?苹果在选择文档在给出了答案:
- StoreKit 2: 一个基于 Swift 的 API,以 JSON Web Signature (JWS) 格式提供 Apple 签名交易验证,从 iOS 15、macOS 12、tvOS 15 和 watchOS 8 开始提供。
- Original API for In-App Purchase: 一个使用 App Store 收据提供交易信息的API,从 iOS 3、macOS 10.7、tvOS 9 和 watchOS 6.2 开始提供。
去年的文章,我们提到以下功能必须依赖 Original StoreKit API:
- 为批量购买计划(VPP,Volume Purchase Program)提供支持。有关更多信息,请参阅 设备管理。
- 提供应用预订(app pre-orders)。有关更多信息,请参阅 应用预订。
- 您的 App 从收费更改为免费 App,反之亦然。
- 推广应用内购买。有关更多信息,请参阅 推广应用程序内购买。
- 对现有和历史遗留的旧 App 使用 v1 API。
因此,今年的 StoreKit 2,苹果提供新的字段 preorderDate 和 originalPurchaseDate 来获取 App 预订时间和购买时间,但是只支持 iOS 16+。
所以,目前 iOS 16 和 StoreKit 2 不能解决的问题:
- 为批量购买计划(VPP,Volume Purchase Program)提供支持。有关更多信息,请参阅 设备管理。
- 推广应用内购买。有关更多信息,请参阅 推广应用程序内购买。
- 对现有和历史遗留的旧 App 使用 Original StoreKit API。
2022年,如何选择 Original StoreKit 还是 StoreKit 2
对于支持低于 iOS 15 以下 app 依然需要使用 Original StoreKit,直到只支持 iOS 15+,并且支持迁移到 StoreKit 2。对于目前开发者来说,使用 StoreKit 2 的成本主要是兼容的系统版本,还有一方面是服务端的兼容,最后是 app 如果有 IAP 服务,那一定是核心业务,不容许一点点的错误!这导致了大多数 app 还处于围观 StoreKit 2 的状态。对于只支持 iOS 15+ 或者独立开发者,建议可以尝试使用 StoreKit 2,如果有异常时,降级到 Original StoreKit 就可以。总之,最后等时间给我们答案吧。
App Transaction(App 交易)
StoreKit 2 增加了 App Transaction 结构体,用于代替 Original StoreKit 的 receipt 内容,具体直接查看接口文档:
/// Represents signed transaction information for an app purchase.
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
public struct AppTransaction : Sendable {
/// The JSON representation of the transaction.
public var jsonRepresentation: Data {
get }
/// A number the App Store uses to uniquely identify the application.
public let appID: UInt64?
/// The application version the transaction is for.
public let appVersion: String
/// A number the App Store uses to uniquely identify the version of the application.
public let appVersionID: UInt64?
/// Identifies the application the transaction is for.
public let bundleID: String
/// The server environment this transaction was created in.
public let environment: AppStore.Environment
/// The version of the app originally purchased.
public let originalAppVersion: String
/// The date this original app purchase occurred on.
public let originalPurchaseDate: Date
/// The date this app was preordered.
public let preorderDate: Date?
/// A SHA-384 hash of `AppStore.deviceVerificationID` appended after
/// `deviceVerificationNonce` (both lowercased UUID strings).
public let deviceVerification: Data
/// The nonce used when computing `deviceVerification`.
/// - SeeAlso: `AppStore.deviceVerificationID`
public let deviceVerificationNonce: UUID
/// The date this transaction was generated and signed.
public let signedDate: Date
/// Get the cached `AppTransaction` for this version of the app or make
/// a request to get one from the App Store server if one has not been cached yet.
public static var shared: VerificationResult<AppTransaction> {
get async throws }
/// Refreshes the shared `AppTransaction` from the App Store server.
/// Calling this function will force an authentication dialog to display to the user.
public static func refresh() async throws -> VerificationResult<AppTransaction>
}
App Transaction
从以上接口可以获取 App 预订时间 preorderDate 和购买时间 originalPurchaseDate 等。另外,验证用户当前使用的 app 是否正品购买以防止欺诈的作用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f0GlZYcw-1657516283946)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7238c8194e124ca7b76202546135881f~tplv-k3u1fbpfcp-watermark.image?)]
- 购买您的 app 的签名信息
- 使用 JWS 签名
- 替换 Original StoreKit 的 receipt(票据)
- StoreKit 提供验证方法
- 开发者可以执行自己的验证(或处理)
验证 App Transaction 的方法:
@available(iOS 16.0, *)
func verificationAppTransaction() {
Task {
do {
let verificationResult = try await StoreKit.AppTransaction.shared
switch verificationResult {
case .verified(let appTransaction):
// StoreKit verified that the user purchased this app and
// the properties in the AppTransaction instance.
// Add your code here.
case .unverified(let appTransaction, let verificationError):
// The app transaction didn't pass StoreKit's verification.
// Handle unverified app transaction information according
// to your business model.
// Add your code he