作者:iHTCboy

前语

WWDC21 是历年来 In App Purchase(IAP,内购内购买)最大的改动,别离推出了 StoreKit 2、App Store Server API、App Store Server Notifications V2 三大特性,上一年我们也编写了 《苹果iOS内购三步曲:App内退款、前史订单查询、绑定用户防掉单!— WWDC21》 文章,所以我们本文不会再深化提及上一年的更新,我们假设不太熟悉,可以先温习一下。本文将对本年 WWDC22 带来的改动,从全体的视角一起回忆。

WWDC22 - In App Purchase 更新总结

以下是编者对 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) 1对1服务:假设您的 App 容许购买两个人之间的1对1实时服务 (例如,学生教导、医疗咨询、看房服务或健身操练),您可以运用 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 的认识。我们本文更多的是议论假设运用这些改动,为用户供应更好的服务或体会!

本文主要从四方面进行评论:

  1. StoreKit 2
  2. App Store Server API
  3. App Store Server Notifications V2
  4. 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:

  1. 为批量购买计划(VPP,Volume Purchase Program)供应支撑。有关更多信息,请参看 设备处理。
  2. 供应运用预订(app pre-orders)。有关更多信息,请参看 运用预订。
  3. 您的 App 从收费更改为免费 App,反之亦然。
  4. 推行运用内购买。有关更多信息,请参看 推行运用程序内购买。
  5. 对现有和前史留传的旧 App 运用 v1 API。

因此,本年的 StoreKit 2,苹果供应新的字段 preorderDate 和 originalPurchaseDate 来获取 App 预订时间和购买时间,但是只支撑 iOS 16+。

所以,现在 iOS 16 和 StoreKit 2 不能处理的问题:

  1. 为批量购买计划(VPP,Volume Purchase Program)供应支撑。有关更多信息,请参看 设备处理。
  2. 推行运用内购买。有关更多信息,请参看 推行运用程序内购买。
  3. 对现有和前史留传的旧 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 是否正品购买以防止欺诈的作用。

WWDC22 - In App Purchase 更新总结

  • 购买您的 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 here.
                }
            } catch {
                // Handle errors.
            }
        }
    }

终究说明一下,App Transaction 的内容,初度启动时,StoreKit 会自动获取更新并坚持最新情况。当您的 app 无法通过 shared 特色获得 App Transaction 时(包含回来 Verification.unverified(::) 或抛出反常过错),可以运用 refresh() 改写 App 生意内容,但是改写时,系统会弹窗提示用户或许需求从头授权认证 Apple ID 账号,所以建议是供应用户操作的按钮,由用户自动建议调用。

New properties(新特性)

StoreKit 2 带来了新的四个字段:

WWDC22 - In App Purchase 更新总结

  • 价格区域
  • 生意的服务器环境
  • 最近的订阅初步日期
  • 岗兵值(占位符值)

Price locale

extension Product {
    @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
    public var priceFormatStyle: Decimal.FormatStyle.Currency { get }
    @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
    public var subscriptionPeriodFormatStyle: Date.ComponentsFormatStyle { get }
}

新增 priceFormatStyle 和 subscriptionPeriodFormatStyle 字段。一般情况下,苹果建议尽或许运用 displayPrice 字段标明格式。例如从 price 特色获取两个品项的价格,例如 2 products for $(price * 2)

Server environment

public struct Transaction : Identifiable {
    @available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
    public let environment: AppStore.Environment
    @available(iOS, introduced: 15.0, deprecated: 16.0, message: "Use the environment property instead")
    @available(macOS, introduced: 12.0, deprecated: 13.0, message: "Use the environment property instead")
    @available(tvOS, introduced: 15.0, deprecated: 16.0, message: "Use the environment property instead")
    @available(watchOS, introduced: 8.0, deprecated: 9.0, message: "Use the environment property instead")
    @available(macCatalyst, introduced: 15.0, deprecated: 16.0, message: "Use the environment property instead")
    public var environmentStringRepresentation: String { get }
}

在 iOS 16+ 运用 environment 结构体,在 iOS 15 运用 environmentStringRepresentation 字段。

获取到的字段值:

环境 说明
App Store Production App Store 商铺包环境的生意
App Store Sandbox 或 TestFlight Sandbox Develop 或 TestFlight 环境的生意
Xcode StoreKit Testing Xcode 运用 Xcode 进行 StoreKit 检验的生意

Recent subscription start date

extension Product.SubscriptionInfo {
    public struct RenewalInfo {
        @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
        public var recentSubscriptionStartDate: Date { get }
    }
}

recentSubscriptionStartDate 标明自动续期订阅购买中订阅的最早初步日期,忽略了超越 60 天的全部续费失利的订阅。

需求留心的是,不要运用 recentSubscriptionStart 字段日期来核算付费服务天数,从前,自动续期订阅的净收入结构和 App Store 上的其他商业模式不同,用户订阅累积满一年后,开发者的 收入将增加到订阅价格的 85%。所以,开发者不能根据这个字段来判别用户订阅是否满一年。其他,假设开发者其时注册了 App Store Small Business Program,符合条件的情况下,不管订阅是否已累积满一年,其实在每个结算周期收到订阅价格的 85%。

Sentinel values

WWDC22 - In App Purchase 更新总结

其他,在不支撑的系统和环境中,就会运用 Sentinel values 岗兵值(占位符值),例如 Price local 下运用 Locale(identifier: "xx\_XX"),而 Recent subscription start date 运用 Date.distantPast 等。这是为什么呢?

由于以上的字段,其它在 Xcode13 和 iOS 15 是不存在的!苹果运用 Xcode 14 供应了对 iOS 15, iPadOS 15, macOS 12, Mac Catalyst 15, watchOS 9, tvOS 15 等的支撑。原理是通过 Xcode 14 编译 app 时,会带上这些字段在 app 包体中,低系统的用户更新包含这些字段的版别时,就能运用。(详细是怎样编译和结束,有懂的朋友欢迎留言交流,小编暂时还没有找到相关文档。)

其他,JWS Transaction 的 Payload 内也新增 environment、recentSubscriptionStartDate 相关字段,下文会说到。

WWDC22 - In App Purchase 更新总结

SwiftUI API

针对 SwiftUI 增加了优惠代码兑换接口和运用内评分接口。

WWDC22 - In App Purchase 更新总结

WWDC22 - In App Purchase 更新总结

StoreKit messages

StoreKit Message API 只支撑 iOS 16+,用于开发者在 app 中接收和闪现 App Store 消息处理。举例来说,自动续期订阅的费用涨价时,假设需求用户供认附和涨价,就需求弹窗给用于供认:

WWDC22 - In App Purchase 更新总结

详细的 StoreKit messages 交互流程图:

WWDC22 - In App Purchase 更新总结

获取 App Store messages 消息,运用 SwiftUI 结束的代码示例:

WWDC22 - In App Purchase 更新总结

然后闪现 App Store messages 消息,需求通过 SwiftUI 环境变量 displayStoreKitMessage 来解析和闪现,运用 SwiftUI 结束的代码示例:

WWDC22 - In App Purchase 更新总结

applicationUsername 和 appAccountToken

let payment = SKMutablePayment(product: product)
payment.applicationUsername = uuidString
SKPaymentQueue.default().add(payment)

applicationUsername 是 Original StoreKit 创建苹果订单时,由开发者赋值的一个字段,原本这个字段是传入用户 UID 的 Hash 值,作用是给苹果验证运用购买以防止欺诈,比方代充和黑产恶意充值等。

而 appAccountToken 是上一年 WWDC21 推出 StoreKit 2 的一个字段,用于开发者将苹果生意与自己服务上的用户相关的 UUID 格式的字段。

WWDC22 - In App Purchase 更新总结

而现在,苹果打通了 applicationUsername 和 appAccountToken,当用 Original StoreKit 创建订单时,applicationUsername 字段赋值运用 UUID 格式内容时,则可以在服务端告知或许解析 receipt 收据时,可以获取这个 UUID 值,也就是订单可以相关供认。

我们回忆一下,我们为什么需求运用 applicationUsername?我们是希望每个生意 transaction 可以相关用户订单号,关于订阅类型和非消耗类型品项,相关用户 UID 就能满意需求,但是关于非消耗型品项,其实,需求相关用户 UID 还有订单号 OrderID,由于非消耗型品项可以重复购买并且没有 UID 的强相关。举例来说,游戏里的用户账号或许不止一个,或许一个账号下的游戏人物,通常不止有一个人物,所以购买非消耗型品项时,开发者希望相关的是其时用户 UID 和此人物 RoleID 生成的开发者订单号 OrderID,但此刻,UUID 格式并不能满意开发者自定义的需求!

所以,applicationUsername 和 appAccountToken 的透传值,对开发者有必定的相关作用,但其实还不完美。

External Purchase(外部购买,第三方支付)

符合条件的 app 可以包含一个链接,引导运用该 app 的用户访问网站进行外部购买。要包含该链接,请结束此授权的央求。有关符合条件的 app 和央求此授权的更多信息,请参看:

  • 在荷兰分发约会 App
  • 在韩国运用第三方支付供应商分发 App

详细的细节这儿不说,就重点说说代码。首要,需求更新 app 的 Info.plist 文件,增加权限:

  • com.apple.developer.storekit.external-purchase :标明您的 app 是否可以供应外部购买。
  • com.apple.developer.storekit.external-purchase-link :标明您的 app 是否可以包含一个链接,引导用户访问网站进行外部购买。
  • SKExternalPurchase :标明您的 app 可以供应外部购买的国家或区域。
  • SKExternalPurchaseLink :标明您的 app 可以供应外部购买的国家或区域和对应的用户访问网站进行外部购买的链接。

配置示例:

    <key>com.apple.developer.storekit.external-purchase</key>
    <true/>
    <key>com.apple.developer.storekit.external-purchase-link</key>
    <true/>
	 <key>SKExternalPurchase</key>
    <array>
        <string>nl</string>
    </array>
    <key>SKExternalPurchaseLink</key>
    <dict>
        <key>nl</key>
        <string>https://www.iHTCboy.com</string>
    </dict>

然后就是接口调用,在 iOS 或 iPadOS 15.4 或更高版别,运用 StoreKit External Purchase API:

@available(iOS 15.4, *)
@available(macOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
public enum ExternalPurchase {
    /// The result of presenting the external purchase notice sheet.
    public enum NoticeResult : Sendable {
        /// The user chose to continue to view external purchases.
        case continued
        /// The user chose to cancel and **not** view external purchases.
        case cancelled
        public static func == (a: ExternalPurchase.NoticeResult, b: ExternalPurchase.NoticeResult) -> Bool
        public func hash(into hasher: inout Hasher)
        public var hashValue: Int { get }
    }
    /// Present a notice sheet to users before showing external purchases.
    ///
    /// Only call this method as a result of deliberate user interaction, such as tapping a button.
    /// - Returns: Whether the user chose to continue to view the external purchases. Only show
    ///            external purchases if the result is `NoticeResult.continued`.
    /// - Throws: A `StoreKitError`
    public static func presentNoticeSheet() async throws -> ExternalPurchase.NoticeResult
}

WWDC22 - In App Purchase 更新总结

如图所示,按照苹果的标准,运用外部购买有必要要的进程:

  1. 查看其时设备容许付款
  2. 关于工作 iOS 和 iPadOS 15.4 或更高版其他设备,运用 StoreKit ExternalPurchase API
  3. 关于低于 iOS 和 iPadOS 15.4 系统,运用上图的 UI 规划和文本内容提示用户

在 iOS 和 iPadOS 15.4 工作的代码示例:

// 其时设备不能支付,则不能进行购买~
guard AppStore.canMakePayments else {
    return
}
do {
    // 翻开外部购买流程
    let res = try await ExternalPurchase.presentNoticeSheet()
    // 翻开效果
    switch res {
    case .continued:
        print("用户选择继续查看外部购买")
    case .cancelled:
        print("用户选择吊销,不查看外部购买")
    @unknown default:
        fatalError()
    }
} catch {
    // 反常流程
    print(error.localizedDescription)
}

留心事项:

  • 获取苹果容许权限后,您才可以在 app 中包含第三方支付系统
  • 只需用户点击 I Understand(我了解)后,才能跳转到第三方支付系统
  • 不包含任何躲藏、休眠或苹果未容许的支付功用或行为
  • 只能在苹果容许的国家或区域的 App Store 商铺运用第三方支付系统

External Link Account(访问外部网站的链接)

阅览器 App 是指将供应以下一种或多种数字内容类型作为其主要功用的 App:杂志、报纸、图书、音频、音乐或视频。

通过阅览器 App,用户可以登录他们在 App 之外创建的帐户,然后可以在用户的 Apple 设备上阅览和畅读先前购买的媒体内容或内容订阅。开发者可以供应指向 app 网站的链接,以便用户在 app 网站上创建和处理帐户。有关符合条件的 app 和央求此授权的更多信息,请参看:

  • 分发包含指向您网站的链接的“阅览器” App

同理,首要,需求更新 app 的 Info.plist 文件,增加权限:

  • com.apple.developer.storekit.external-link.account :标明您的 app 是否可以链接到外部网站进行帐户创建或处理。
  • SKExternalLinkAccount :标明您的 app 可以供应外部创建或处理帐户的国家或区域,和对应的用户访问创建或处理帐户网站的链接。
	<key>com.apple.developer.storekit.external-link.account</key>
	<true/>
	<key>SKExternalLinkAccount</key>
	<dict>
		<key>*</key>
		<string>https://www.iHTCboy.com</string>
		<key>jp</key>
		<string>https://www.iHTCboy.com/jp</string>
	</dict>

然后就是接口调用,在 iOS 或 iPadOS 16 或更高版别,运用 StoreKit External Link Account API:

@available(iOS 16.0, *)
@available(macOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
public enum ExternalLinkAccount : Sendable {
    /// Whether the app can open the external link account.
    ///
    /// Check this property before showing any UI controls that the user can use to open the external link
    /// account.
    /// You may want to check the value of this property again when the App Store storefront changes.
    /// - Important: If this property is `false`, do not show UI controls that call `open()` as the
    ///              method will always fail.
    public static var canOpen: Bool { get async }
    /// Opens the external link account in the user's default browser.
    ///
    /// Only call this method as a result of deliberate user interaction, such as tapping a button. If
    /// `canOpen` is `false`, this method will always throw an error. Returning without throwing an error
    /// does not guarantee the user was redirected to the external link account.
    /// - Throws: A `StoreKitError`
    public static func open() async throws
}

WWDC22 - In App Purchase 更新总结

如图所示,按照苹果的标准,运用外部购买有必要要的进程:

  1. 查看其时设备容许付款
  2. 关于工作 iOS 和 iPadOS 16 或更高版其他设备,运用 StoreKit ExternalPurchase API
  3. 关于低于 iOS 和 iPadOS 16 系统,运用上图的 UI 规划和文本内容提示用户,并且有必要是运用默认浏览器中翻开一个新窗口,而不能运用 App 的 WebView 翻开

在 iOS 和 iPadOS 15.4 工作的代码示例:

@available(iOS 16.0, *)
func externalLinkAccount() {
    // 其时设备不能支付,则不能进行购买~
    guard AppStore.canMakePayments else {
        return
    }
    Task {
        // 判别是否有翻开外部链接帐户的权限
        let canOpen = await ExternalLinkAccount.canOpen
        guard canOpen else {
            print("不能翻开外部链接帐户")
            return
        }
        do {
            // 翻开外部链接帐户
            try await ExternalLinkAccount.open()
        } catch {
            print(error.localizedDescription)
        }
    }
}

留心事项:

  • 获取苹果容许权限后,您才可以在 app 中包含链接到外部网站进行帐户创建或处理
  • 只需用户点击 Continue(继续)后,才能跳转到外部网站进行帐户创建或处理
  • 跳转到外部网站,不能有没有任何重定向、中间链接或着陆页面
  • 不得在 URL 中传递附加参数,以便保护用户 (例如用户的隐私)

App Store Server API

App Store Server API 是苹果上一年 WWDC21 推出的 ,详细可以参看我们之前的文章《WWDC21 – App Store Server API 实践总结》。

本年 WWDC22 苹果新增了三个新接口,并且对部分接口增加了过滤功用,这儿我们列了一个表格:

推出时间 接口 说明 链接
WWDC21 Look Up Order ID 查询用户订单的收据,运用订单ID从收据中获取用户的运用内购买项目收据信息。 GET https://api.storekit.itunes.apple.com/inApps/v1/lookup/{orderId}
WWDC21 Get Transaction History 查询用户前史收据,获取用户在您的 app 的运用内购买生意前史记载。 GET https://api.storekit.itunes.apple.com/inApps/v1/history/{originalTransactionId}
WWDC21 Get Refund History 查询用户内购退款,获取 app 中为用户退款的全部运用内购买项目的列表。 GET https://api.storekit.itunes.apple.com/inApps/v1/refund/lookup/{originalTransactionId}
WWDC21 Get All Subscription Statuses 查询用户订阅项目情况,获取您 app 中用户全部订阅的情况。 GET https://api.storekit.itunes.apple.com/inApps/v1/subscriptions/{originalTransactionId}
WWDC21 Send Consumption Information 提交防欺诈信息,当用户央求退款时,苹果告知(CONSUMPTION_REQUEST)开发者服务器,开发者可在12小时内,供应用户的信息(比方游戏金币是否已消费、用户充值过多少钱、退款过多少钱等),终究苹果收到这些信息,帮助“退款抉择计划系统” 来决定是否答运用户退款。 PUT https://api.storekit.itunes.apple.com/inApps/v1/transactions/consumption/{originalTransactionId}
WWDC21 Extend a Subscription Renewal Date 延伸用户订阅的时长,运用原始生意标识符延伸用户有用订阅的续订日期。(相当于免费给用户增加订阅时长) PUT https://api.storekit.itunes.apple.com/inApps/v1/subscriptions/extend/{originalTransactionId}
WWDC22 Request a Test Notification 检验 App Store 服务器告知,让 App Store 服务器告知向开发者服务器发送检验告知。 POST https://api.storekit.itunes.apple.com/inApps/v1/notifications/test
WWDC22 Get Test Notification Status 获取 App Store 服务器告知的检验效果,获取发送到开发者服务器的 App Store 服务器检验告知的查看情况。 GET https://api.storekit.itunes.apple.com/inApps/v1/notifications/test/{testNotificationToken}
WWDC22 Get Notification History 获取 App Store 服务器告知的前史告知,获取 App Store 服务器检验发送到开发者服务器的告知列表。 POST https://api.storekit.itunes.apple.com/inApps/v1/notifications/history

Filter and Sort(过滤和排序)

其间只需 Get Transaction History 接口供应了过滤和排序的功用:

WWDC22 - In App Purchase 更新总结

现在支撑的查询参数列表:

查询参数 作用 可选值
productType 包含在生意前史记载中的产品类型。您的查询可以指定多个productType。 AUTO_RENEWABLE, NON_RENEWABLE, CONSUMABLE, NON_CONSUMABLE
productId 包含在生意前史记载中的产品标识符。您的查询可以指定多个productID。
subscriptionGroupIdentifier 包含在生意前史记载中的订阅组标识符。您的查询或许会指定多个subscriptionGroupIdentifier。
startDate 生意初步日期,以 UNIX 时间标明的时间跨度的初步日期,以毫秒为单位。
endDate 生意截止日期,以 UNIX 时间标明的时间跨度的截止日期,以毫秒为单位。
inAppOwnershipType 按运用程序内全部权类型约束生意前史记载。 PURCHASED,FAMILY_SHARED。
excludeRevoked 生意前史记载是否打扫退款和吊销的生意。默认值为false。 true, false
sort 生意前史记载的可选排序次第。照应按最近修改的日期对生意记载进行排序。默认值为 ASCENDING(升序),因此您首要会收到最旧的生意记载。 ASCENDING, DESCENDING
revision 获取下一组最多20笔生意的令牌。全部回复都包含一个revision令牌。留心:关于运用revision令牌的央求,请包含与初始央求相同的查询参数。运用上一个History中的revision令牌。除初始央求外,全部央求都需求revision。

查询示例:

WWDC22 - In App Purchase 更新总结

productIdproductTypesubscriptionGroupIdentifier 查询参数可以一起指定多个值。例如,要按 NON_CONSUMABLE(非消耗型) 和 AUTO_RENEWABLE(自动续期产品类型)字符来选择生意前史记载,央求中包含以下内容:

GET https://api.storekit.itunes.apple.com/inApps/v1/history/{originalTransactionId}?productType=NON_CONSUMABLE&productType=AUTO_RENEWABLE

其实更高雅的办法或许是 App Store Connect API 的方式:&filter[appStoreVersions.appStoreState]=READY_FOR_SALE,PREORDER_READY_FOR_SALE,READY_FOR_REVIEW

终究,生意前史记载接口回来效果只支撑以下情况:

  • 自动续期订阅
  • 非续订订阅
  • 非消耗型运用内购买项目
  • 消耗型运用内购买项目:假设生意被退款、吊销或 app 没有结束生意处理等。

特别留心:消耗型运用内购买项目假设调用了 finishTransaction(_:),则不会在出现在舞台的生意前史列表中,所以,消耗型运用内购买项目不能运用这个接口作为校验接口!!!

New Notification API(新的告知接口)

检验 App Store 服务器告知

Request a Test Notification 让 App Store 服务器告知向开发者服务器发送检验告知。

POST https://api.storekit.itunes.apple.com/inApps/v1/notifications/test

WWDC22 - In App Purchase 更新总结

接口照应的 testNotificationToken 字段是 App Store 服务器告知发送到开发者服务器的告知检验的检验告知令牌,每次央求获取的仅有标识 Token,这个 Token 用于下面的接口参数。

获取 App Store 服务器告知的检验效果

Get Test Notification Status,获取发送到开发者服务器的 App Store 服务器检验告知的查看情况。

GET https://api.storekit.itunes.apple.com/inApps/v1/notifications/test/{testNotificationToken}

根据 Request a Test Notification 接口获取到的 testNotificationToken 央求检验效果:

WWDC22 - In App Purchase 更新总结

回来的照应有两个参数:

  • firstSendAttemptResult:标明 App Store 服务器检验向开发者服务器发送 TEST 告知的效果,假设不是 SUCCESS,则如上图会回来原因,假设 TIMED_OUT 标明超时,SSL_ISSUE 标明开发者服务器的 SSL 证书有问题。根据这个字段就能检验和查看 App Store 服务器和开发者服务器之前的连通性。
  • signedPayload:JWS 格式的签名有用负载,包含 App Store 服务器发送到您的服务器的 TEST 告知。

详细的 signedPayload 解码后的格式内容如下示例:

WWDC22 - In App Purchase 更新总结

获取 App Store 服务器告知的前史告知

Get Notification History,获取 App Store 服务器检验发送到开发者服务器的告知列表。

POST https://api.storekit.itunes.apple.com/inApps/v1/notifications/history

此接口的目的是,由于 App Store 服务器告知是苹果推送的告知,开发者是被动接收,总会由于各种情况(服务器宕机,运营商链路或云服务供应商缺点等)导致无法按时接收到 App Store 服务器告知。所以,可以通过这个接口查询 App Store 服务器告知的前史记载:

WWDC22 - In App Purchase 更新总结

  • 只支撑 App Store 服务器告知 V2 版其他照应(即 JWS 格式)
  • 最多可以查询 6 个月以内的前史列表(180天内)
  • 可以过滤告知类型、告知子类型或用户
  • 开发者服务器宕机后可运用接口自动获取告知记载,直到开发者服务器可接收 App Store 服务器告知停止

查询接口的示例:

WWDC22 - In App Purchase 更新总结

接口每次最多回来20条告知前史记载,所以照应会回来一个 paginationToken 字段,用来查询更多分页的告知效果。paginationToken 获取下一组最多 20 条告知前史记载,全部有更多前史记载的照应都包含 paginationToken 字段。

New properties(新特性)

除了 StoreKit 2 增加了 environmentrecentSubscriptionStartDate 字段,App Store Server API 的 JWS 格式的签名生意也包含。

JWS transaction info Decoded Payload:

WWDC22 - In App Purchase 更新总结

JWS renewal info Decoded Payload:

WWDC22 - In App Purchase 更新总结

详细说明可以查看官方文档:environment 和 recentSubscriptionStartDate,这儿不在复述。

App Store Server Notifications V2

同理 App Store Server Notifications 也有新增相应的 environment 和 recentSubscriptionStartDate 字段。

WWDC22 - In App Purchase 更新总结

从这个图片可以看出,App Store Server API 是 App Store 服务器和开发者服务器之前,彼此可以照应的流程。而 App Store Server Notifications V1 和 V2 告知,是 App Store 服务器自动告知开发者服务器,开发者服务器不能自动央求,所以导致了一些场景的缺点。

App Store 服务器告知宕机

服务器宕机是很常见的问题,但是宕机后,开发者就无法接收 App Store 服务器的告知。

WWDC22 - In App Purchase 更新总结

所以,App Store Server Notifications V2 告知在初度检验告知后没有收到来自开发者服务器的照应时会进行重试:

WWDC22 - In App Purchase 更新总结

  • App Store Server Notifications V1:重试三次;在前次检验后 6、24 和 48 小时。
  • App Store Server Notifications V2:重试五次;在前次检验后 1、12、24、48 和 72 小时。

重试成功后,开发者服务器接收到的告知,可以并不再是次第闪现:

WWDC22 - In App Purchase 更新总结

所以,开发者需求通过 signedDate 字段,保证告知的次第逻辑正确,也就是说告知的效果情况以最新的 signedDate 时间来准,来更新用户能享受的服务。而重试的告知或许会出现重复的告知照应,所以开发者可以通过 notificationUUID 字段去重告知。

留住订阅者

用户需求不断从订阅中获得价值,才会继续地订阅您的 App。定期更新您的 App,供应新内容和增强功用,以鼓动订阅者继续订阅。

App Store Server Notifications V2 供应了更多的告知类型,抵达 28 个,未来还会增加更多。

WWDC22 - In App Purchase 更新总结

这儿一个用户订阅进程的或许会发生的告知:

WWDC22 - In App Purchase 更新总结

从这个图中,开发者可以思考到什么?

Subscription loyalty(订阅忠诚度)

WWDC22 - In App Purchase 更新总结

从苹果的 自动续期订阅 文档可以获取这样的思考:

通过运用 获取全部订阅情况 接口和 获取生意前史记载 接口,可承认用户的订阅情况并查看生意前史记载,帮助您辨认并实行以下操作:

  • 自愿丢失。运用 获取全部订阅情况 接口承认订阅者是不是已关闭特定订阅的自动续订。您还可以运用 App Store 服务器告知来获取有关用户情况改动的实时更新以及与其 App 内购买项目相关的要害工作,例如退款告知。运用这一信息来采用相应的举动,例如,您可以供应促销优惠以鼓动他们继续订阅,建议更符合他们需求的备用等级,或许在订阅到期后确定相关订阅内容的访问权限。请务必向用户奉告您所做的任何更改,以及他们是否需求结束任何操作,还有从头订阅的办法。
  • 非自愿丢失。当订阅者遇到账单问题 (如信用卡过期问题) 时,就会发生非自愿丢失。选择接收服务器告知以了解何时由于账单问题而导致订阅续订失利,或运用 获取全部订阅情况 接口承认订阅是不是由于账单问题而处于计费重试情况。根据上述信息采用相应措施,例如,您可以在 App 中闪现信息或发送电子邮件,提示订阅者更新他们之前挂号的付款办法,并供应其 App Store 帐户中“付款信息”区域的链接。一旦问题得到处理,您就可以恢复服务。Apple 将在 60 天内检验收取付款。假设订阅在 60 天内续订,则付费服务的天数从续订日期初步继续累积。

为防止由于账单问题而导致服务间断,请在 App Store Connect 中启用账单宽期限。Apple 将检验处理账单问题,并在订阅者保留订阅访问权限的一起恢复订阅。假设订阅在这个期限内恢复,则付费服务天数的计数和您的收入都不会间断。假设用户在 60 天后从头订阅,则付费服务的天数将重置,您将收到一年的标准订阅费用,直到付费服务满一年停止。

  • 价格上调附和情况。当您进步订阅价格时,Apple 会问询受影响的订阅者是否附和这个新价格,您可以在价格变化收效之前跟踪用户的附和情况。在向受影响的用户闪现价格上调单之前,您可以闪现一条 App 内信息,说明订阅的长处和价值,以及价格上调将如何改善服务。假设用户没有对上调做出反应,他们的订阅将在其时结算周期完毕时到期。

简单来说,通过订阅告知,分析用户的忠诚度,根据用户不同的行为习惯和选择决定(告知),然后分析用户行为的背面原因,然后优化开发者的服务,然后进步订阅的忠诚度!

App Store Connect

App Store 相关的调整不多,都是细节优化。

Sandbox & Test

开发人员将可以更轻松地创建沙盒用户,并检验沙盒购买。比较从前少了 安全提示问题安全提示问题答案出生日期 三个选项。

WWDC22 - In App Purchase 更新总结

增加了 Allow Purchase & Renewals 开关,用于检验订阅到期自动扣费和失利重试。

WWDC22 - In App Purchase 更新总结

Xcode StoreKit 检验中增加了更多检验用例,例如退款央求、优惠代码兑换、订阅涨价、账单扣款重试等。这是一个不错的改善,但现在检验内购功用的开发者还不多,详细参看 What’s new in StoreKit testing – WWDC22。

WWDC22 - In App Purchase 更新总结

App Store Connect API

App Store Connect API 增加了查询沙盒账号、根除沙盒内购前史记载、设置间断内购情况等,也增加内购、用户商铺议论内容和回复、App 挂起确诊数据等接口。

最重要是,增加了内购项目的创建!

WWDC22 - In App Purchase 更新总结

内购品项和订阅品项的相关 API:

WWDC22 - In App Purchase 更新总结

  • 新建订阅品项
  • 创建、编辑和删去品项
  • 处理定价
  • 提交审理
  • 创建优惠和促销代码

现在截止本文宣布,苹果 App Store Connect API 文档,依然还没有看到这些接口的描绘!

终究,是苹果弃用 XML 流文档的方式与 App Store Connect 的交互,未来开发者,都需求迁移到 App Store Connect API!

WWDC22 - In App Purchase 更新总结

这个怎样了解?参看我们之前开源的一款苹果 macOS 东西:《AppleParty(苹果派)》,它运用到了苹果 Transporter 指令东西,批量上传内购产品列表和上传 IAP 包文件等。猜测 Reporter 和 altool 等指令也会被弃用。

苹果标明,本年秋天初步停用 XML 提交,强制引荐运用 App Store Connect API 接口。但现在还没有看到官网相关的说明文档!

App Store

本年 App Store 相关更新,或许最引人重视的功用,就是这个 Benchmarks in App Analytics(App 分析中的基准)功用,,基准通过将与获客率、运用和盈余情况相关的绩效方针置于详细情境中,在整个客户旅程期间供应有价值的见地,这样您就可以很容易地看到您与同行比较的表现,并做出相应抉择计划以结束事务方针。

WWDC22 - In App Purchase 更新总结

查看自己 app 与同行比较的表现,并做出结束事务方针的抉择计划。运用差异隐私技术,以保证机密信息的安全和私密性。苹果标明这个功用下一年 2023 年头才上线,现在官方文档也没有找到详细的介绍。差异隐私技术介绍可以参看我们之前的文章《WWDC22 – Apple 隐私技术探求》。

关于 app 数据,Xcode 供应了功率、性能方针和确诊等新接口。

  • 分析宽和决 App 挂起(hangs:延时、慢、卡顿)
  • 查看确诊签名
  • 下载详细日志

WWDC22 - In App Purchase 更新总结

详细功用可以参看:Identify trends with the Power and Performance API – WWDC20 和 Track down hangs with Xcode and on-device detection – WWDC22。

在 App Store Connect app 中可以送审内购、新版别、In-App Event、产品面优化、自定义产品而等。

WWDC22 - In App Purchase 更新总结

现在苹果支撑送审的内容:

WWDC22 - In App Purchase 更新总结

可以看到 iOS 除了新版别 app 送审,现在支撑 In-App Event、自定义产品、产品面优化检验等。而 tvOS 和 macOS 现在还没有,或许下一年 WWDC23 应该就支撑一波了吧!

其他,需求提示一下,送审新版别 app 、In-App Event、自定义产品、产品面优化检验等,苹果是建议开发者可以兼并提交一起送审,由于这样苹果会以其时送审的内容一起审理,进步苹果的审理功率?总之,提审这些项目后,假设有项目审理不通过,可以独自发布审理通过的内容。

WWDC22 - In App Purchase 更新总结

关于 App Store 的优化,2022 年 1 月 20 日 推出适用于订阅的自定优惠代码,开发者可以自定义,如 VIP888 的优惠代码,用于推行活动,自定代码可通过直接 URL 或在您的 app 中兑换。2022 年 4 月 29 日 说明 App Store 改善流程的标准和新的期限延伸,苹果清晰了 App 长期不更新被下架的细则,当一款 App 在曩昔三年内从未更新且未抵达最低下载量 (即该 App 在接连 12 个月内彻底没有或只需极低的下载量) 时,其开发者将会收到电子邮件,奉告该 App 已被辨认并或许从 App Store 中被移除,开发者收到告知起,有 90 天的时间来更新他们的 App。

总结

关于 In App Purchase 和 App Store,跟着这几年苹果的敞开,现已很大程度上处理了开发者大多数的问题,从退款查询到全部订单查询,从被动告知到自动获取告知,从内购税率下降到进步 App 曝光量,苹果现已供应了非常多的接口、事例展示和建议。比方,自动续期订阅类型,现在现已杂乱到不能再杂乱,订阅群组、免费试用期限、推介促销优惠、促销优惠、优惠代码、计费重试、从头激活、续期等。

终究,我们觉得 In App PurchaseApp Store 还有什么疑惑或痛点吗?

欢迎我们议论区一起议论交流~

欢迎重视我们,了解更多 iOS 和 Apple 的动态~

参看引证

  • 苹果iOS内购三步曲:App内退款、前史订单查询、绑定用户防掉单!— WWDC21 –
  • AppStore Small Business Program 发布 – Apple Developer
  • 注册新的 AppStore Small Business Program – Apple Developer
  • 全新的 App Store 小型企业计划让开发者看到无尽或许 – Apple (中国大陆)
  • App Store Small Business Program – Apple Developer
  • 要求在线集体活动需运用 App 内购买办法的截止日期已延伸 – Apple Developer
  • 针对在线集体活动服务的 app内购买项目规矩更新 – Apple Developer
  • 针对在线多人活动的 app 内购买项目规矩提示 – Apple Developer
  • App Store 审理攻略 – Apple Developer
  • Apple 与美国开发者就 App Store 更新抵达共同 – Apple (中国大陆)
  • 小型事务开发者帮助央求提交将于 5 月 20 日截止 – Apple Developer
  • Cameron et al. v. Apple Inc.
  • 日本公正生意委员会完毕对 App Store 的查询 – Apple (中国大陆)
  • “阅览器”app 分发的更新 – Apple Developer
  • Update on dating apps distributed on the App Store in the Netherlands – Apple Developer
  • Distributing dating apps in the Netherlands – Apple Developer
  • Additional details available for dating apps in the Netherlands – Apple Developer
  • Update on StoreKit External Entitlement for dating apps – Apple Developer
  • Further updates on StoreKit External Entitlement for dating apps in the Netherlands storefront – Latest News – Apple Developer
  • 订阅告知更新 – 最新动态 – Apple Developer
  • 处理自动续期订阅的定价 – App Store Connect 帮助
  • 针对在韩国分发 App 的更新 – Apple Developer
  • Distributing apps using a third-party payment provider in South Korea – Apple Developer
  • AppTransaction | Apple Developer Documentation
  • Message | Apple Developer Documentation
  • applicationUsername | Apple Developer Documentation
  • appAccountToken | Apple Developer Documentation
  • External Purchase | Apple Developer Documentation
  • External Link Account | Apple Developer Documentation
  • App Store Server API | Apple Developer Documentation
  • App Store Server Notifications | Apple Developer Documentation
  • App Store Connect API | Apple Developer Documentation
  • WWDC21 – App Store Server API 实践总结 –
  • 开源一款苹果 macOS 东西 – AppleParty(苹果派) –
  • WWDC22 – Apple 隐私技术探求 –
  • Transporter 用户攻略
  • altool 攻略
  • Reporter 用户攻略
  • 充分运用 App Store – Apple Developer
  • 自动续期订阅 – App Store – Apple Developer
  • 说明 App Store 改善流程的标准和新的期限延伸 – Apple Developer
  • 现已推出适用于订阅的自定优惠代码 – Apple Developer