使用StoreKit 2时订阅到期未收到交易更新的问题
问题:StoreKit 2自动续订订阅到期无法触发交易更新
我正在用StoreKit 2实现自动续订订阅,但订阅到期时收不到交易更新。需求是通过监听钩子更新用户已购产品,目前在Xcode里通过取消订阅并等待到期测试。
我用Transaction.updates监听交易更新,也参考了苹果官方内购实现示例。
监听交易更新的代码:
func listenForTransactions() -> Task<Void, Error> { return Task.detached { //Iterate through any transactions that don't come from a direct call to `purchase()`. for await result in Transaction.updates { do { let transaction = try self.checkVerified(result) //Deliver products to the user. await self.updateCustomerProductStatus() //Always finish a transaction. await transaction.finish() } catch { //StoreKit has a transaction that fails verification. Don't deliver content to the user. print("Transaction failed verification") } } } }
更新已购订阅的代码:
@MainActor func updateCustomerProductStatus() async { var purchasedProducts: [Product] = [] // Iterate through all of the user's purchased products. for await result in Transaction.currentEntitlements { do { // Check whether the transaction is verified. If it isn’t, catch `failedVerification` error. let transaction = try checkVerified(result) // Check the `productType` of the transaction and get the corresponding product from the store. switch transaction.productType { case .autoRenewable: if let revocationDate = transaction.revocationDate { //do nothing if transaction was revoked print("Transaction was revoked on \(revocationDate)") return } else if let expirationDate = transaction.expirationDate, expirationDate < Date() { // Do nothing, this subscription is expired. return } else { if let subscription = subscriptions.first(where: { $0.id == transaction.productID}) { // Provide access to the product purchasedProducts.append(subscription) } } default: break } } catch { //storekit has a transaction that fails verification, don't delvier content to the user print("Failed - error retrieving products \(error)") } } //finally assign the purchased products self.purchasedSubscriptions = purchasedProducts }
目前必须手动调用updateCustomerProductStatus()才能检查订阅是否到期,猜测订阅到期不被视为交易更新,想问有没有其他钩子可以监听订阅到期事件?
解决方案
核心结论:订阅到期不会触发Transaction.updates事件
StoreKit 2中,Transaction.updates仅监听主动交易行为产生的更新,比如用户主动购买、续订、退款、退款式取消订阅等操作。订阅自然到期属于被动状态变更,不会触发这个流。
正确的到期状态处理方式
定期主动检查权益
不需要依赖钩子,在这些时机主动调用updateCustomerProductStatus():- App启动/从后台回到前台时
- 用户进入需要订阅权限的页面时
- 订阅到期前1-2小时触发提醒同步检查
监听App生命周期自动触发
通过NotificationCenter监听前台激活事件,自动更新状态:func setupLifecycleListeners() { NotificationCenter.default.addObserver( self, selector: #selector(onAppEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil ) } @objc func onAppEnterForeground() { Task { await updateCustomerProductStatus() } }修复
updateCustomerProductStatus()逻辑
原代码遇到过期交易直接return会忽略后续有效订阅,改为跳过过期项继续检查:@MainActor func updateCustomerProductStatus() async { var purchasedProducts: [Product] = [] for await result in Transaction.currentEntitlements { do { let transaction = try checkVerified(result) guard transaction.productType == .autoRenewable else { continue } if let revocationDate = transaction.revocationDate { print("Transaction was revoked on \(revocationDate)") continue } if let expirationDate = transaction.expirationDate, expirationDate < Date() { print("Subscription \(transaction.productID) expired on \(expirationDate)") continue } if let subscription = subscriptions.first(where: { $0.id == transaction.productID }) { purchasedProducts.append(subscription) } } catch { print("Failed - error retrieving products \(error)") } } self.purchasedSubscriptions = purchasedProducts }服务器端验证(推荐)
利用App Store Server API定期拉取用户订阅状态,服务器可以主动获取到期信息,下次用户打开App时同步最新状态,避免完全依赖客户端检查。
测试技巧
在Xcode测试时,可使用App Store Connect的沙盒订阅加速功能,将到期时间缩短至分钟级,无需等待自然到期。
内容的提问来源于stack exchange,提问作者smartinrubio
相关产品推荐
相关产品推荐

