如何为iOS应用的两个订阅产品配置互斥免费试用期
实现互斥试用期的方案(StoreKit2)
核心逻辑
通过查询用户的历史交易记录,判断是否已经使用过任意目标产品的试用期,以此限制另一个产品的试用入口,同时在购买前做二次校验防止绕过。
1. 查询用户是否使用过任意试用期
利用StoreKit2的Transaction.all()获取用户所有交易记录,筛选出类型为试用且属于目标产品的有效记录:
import StoreKit func hasUsedAnyTrial() async -> Bool { let targetProductIDs = ["com.myProduct.monthly", "com.myProduct.yearly"] do { let allTransactions = try await Transaction.all() // 筛选未被撤销的试用交易 let validTrials = allTransactions.filter { guard let productID = $0.productID, targetProductIDs.contains(productID) else { return false } return $0.type == .trial && !$0.isRevoked } return !validTrials.isEmpty } catch { print("获取交易记录失败:\(error.localizedDescription)") return false } }
2. 动态调整产品展示UI
根据查询结果,隐藏已使用过试用期产品的试用入口,只显示直接购买选项:
// 提前定义目标产品ID数组 let targetProductIDs = ["com.myProduct.monthly", "com.myProduct.yearly"] func configureProductUI(for product: Product) async { let hasUsedTrial = await hasUsedAnyTrial() guard targetProductIDs.contains(product.id) else { return } if hasUsedTrial { // 隐藏试用标签,显示原价 trialBadge.isHidden = true priceLabel.text = product.displayPrice buyButton.setTitle("立即购买", for: .normal) } else { // 展示试用信息 trialBadge.text = "免费试用1个月" priceLabel.text = "试用结束后¥\(product.price)" buyButton.setTitle("开始试用", for: .normal) } }
3. 购买前的二次校验
为避免用户通过篡改UI绕过限制,发起购买请求前再次验证试用状态:
func initiatePurchase(for product: Product) async { let hasUsedTrial = await hasUsedAnyTrial() guard targetProductIDs.contains(product.id) else { // 处理非目标产品购买逻辑 return } if hasUsedTrial { let alert = UIAlertController(title: "提示", message: "您已享受过免费试用期,无法重复使用", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) present(alert, animated: true) return } // 正常发起购买流程 do { let purchaseResult = try await product.purchase() switch purchaseResult { case .success(let verification): let transaction = try verification.payloadValue // 处理交易完成逻辑(比如解锁权限) await transaction.finish() case .userCancelled: break case .pending: // 处理待确认状态(如家庭共享审批) break @unknown default: break } } catch { print("购买失败:\(error.localizedDescription)") } }
4. 特殊场景处理
- 退款后重置试用:如果业务允许用户退款后再次试用,可以移除
!$0.isRevoked的判断,或者单独处理已撤销的交易记录。 - 跨设备同步:若需要多设备同步试用状态,建议将用户的试用记录同步到自有服务器,避免仅依赖本地StoreKit查询可能出现的延迟或不一致。
内容的提问来源于stack exchange,提问作者Irfan Saeed
相关产品推荐
相关产品推荐

