Swift自动续订订阅:如何在paymentQueue代理中区分新购买?
在Swift自动续订订阅中区分新购买与已有购买
针对你遇到的「已有活跃订阅时点击购买确定后,代理方法进入.purchased状态,无法区分新购买」的问题,可以通过以下几种可靠方式解决:
1. 利用originalTransaction属性直接判断
苹果的SKPaymentTransaction对象中,新购买的交易originalTransaction属性为nil;而当用户已有活跃订阅、重复触发购买操作时,回调的交易originalTransaction会指向用户最初订阅时的原始交易记录。
修改你的代理方法代码如下:
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { switch transaction.transactionState { case .purchased: hideLoader() if let transactionID = transaction.transactionIdentifier { print("Transaction ID: \(transactionID)") // 核心判断:originalTransaction为nil则是新购买 let isNewPurchase = transaction.originalTransaction == nil SubscriptionViewController.store.complete(transaction: transaction) if isNewPurchase { // 仅新购买时执行服务器更新逻辑 validateReceipt(transId: transactionID) } } break case .failed: self.currentSubscription = nil hideLoader() SubscriptionViewController.store.fail(transaction: transaction) break case .restored: hideLoader() break case .deferred: hideLoader() break case .purchasing: break @unknown default: hideLoader() print("Unknown case happens") break } } }
2. 结合服务器收据验证做二次校验(更安全)
客户端的判断可能存在边缘场景漏洞,建议配合服务器端的收据验证逻辑:
- 每次新购买成功并验证通过后,将有效的
transactionIdentifier存储到服务器的用户订阅记录中 - 收到
.purchased回调时,先调用validateReceipt验证收据合法性 - 在服务器端对比当前交易ID是否已存在于用户的历史记录中:
- 不存在则判定为新购买,执行用户状态更新
- 已存在则判定为重复触发的回调,跳过更新逻辑
3. 前置拦截:发起购买前先检查订阅状态
在用户点击购买按钮时,先通过本地缓存或服务器接口查询当前订阅状态:
- 如果用户已有活跃订阅,直接弹出「您已有活跃订阅」的提示,不发起
SKPayment请求 - 仅当订阅已过期或未订阅时,才触发购买流程,从根源避免冗余的
.purchased回调
内容的提问来源于stack exchange,提问作者Gurpal Rajput
相关产品推荐
相关产品推荐

