You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

StoreKit 2自动续期订阅处理及相关技术疑问

StoreKit 2 订阅相关疑问解答

问题解答

1. 试用期内取消自动续期订阅,revocationDate 是否不为空?

不是。用户在试用期内取消自动续期(仅停止后续订阅周期的自动扣费)时,revocationDate 仍然为 nil——此时用户当前的试用期权益依然有效,直到 expirationDate 到期。只有当订阅被苹果主动撤销(比如用户申请退款并通过、苹果因合规问题收回权益)时,revocationDate 才会被赋值,且此时订阅权益立即失效。

2. Transaction.currentEntitlements 是否仅包含当前有效的产品?是否无需检查 expirationDate?

Transaction.currentEntitlements 会返回用户当前拥有的、未被撤销且未过期的权益对应的交易记录,但存在特殊场景:如果用户取消了自动续期订阅,但当前订阅周期(含试用期)尚未结束,该交易仍会出现在 currentEntitlements 中,直到 expirationDate 到期。

理论上该序列返回的交易都是有效状态,但为了避免设备时间偏差、时区差异等极端情况,建议额外检查 expirationDate 是否晚于当前时间,同时结合 revocationDate == nil 来双重验证,确保权益判断的准确性。

3. 是否推荐在 MainThread 中执行相关代码?

是的,推荐在主线程执行 StoreKit 相关的业务逻辑,尤其是涉及 UI 更新的部分。你的代码中使用 @MainActor 标记函数是正确的做法:@MainActor 会自动将异步任务调度到主线程执行,避免因 UI 更新在非主线程触发的崩溃或异常。另外,StoreKit 的部分回调(如交易状态更新)本身也要求在主线程处理,所以保持主线程执行是安全且符合苹果规范的。

代码优化建议

针对你的实现,补充两点小建议:

  • 处理自动续期订阅时,建议增加 expirationDate 的有效性检查,避免设备时间异常导致的误判:
    case .autoRenewable:
        guard transaction.revocationDate == nil, 
              let expirationDate = transaction.expirationDate, 
              Date() < expirationDate else { continue }
        KeychainHelper.Subscription.setExpiryOrCancelledDate(expirationDate)
        activeSubscriptions.append(subscription)
    
  • 非续期订阅的有效期完全由开发者自行管理,确保 getNonRenewingExpirationDate 函数的计算逻辑准确(比如根据产品定义的时长正确推算到期时间),这部分是权益判断的关键。

内容的提问来源于stack exchange,提问作者Jaythaking

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 09:40:09