iOS StoreKit 2:家庭共享组内设备如何接收待处理购买通知?
跨设备同步待处理购买状态(StoreKit 2 + 家庭共享场景)
核心问题原因
StoreKit 2的Transaction.updates和SubscriptionStatus.updates监听器仅在发起购买的设备上触发待处理状态通知,跨设备的家庭共享场景下,未发起购买的设备无法通过StoreKit原生API获取待处理购买的实时状态。
解决方案:iCloud Key-Value Storage 同步状态
利用家庭共享组内设备可共享访问的iCloud键值存储,手动同步待处理购买标记,实现多设备统一禁用付费墙。
1. 配置iCloud能力
- 在Xcode项目的「Signing & Capabilities」中添加「iCloud」能力
- 勾选「Key-Value Storage」,并创建/选择共享容器(容器ID需在开发者后台开启家庭共享权限)
2. 设备A:发起购买时写入待处理标记
在调用Product.purchase()前,立即写入iCloud KV存储标记,告知其他设备当前有未完成购买:
import Foundation // 替换为你的iCloud容器ID private let sharedSuiteID = "iCloud.com.yourcompany.yourapp" func initiatePurchase(for product: Product) async { // 先标记待处理状态 let sharedDefaults = UserDefaults(suiteName: sharedSuiteID)! sharedDefaults.set(true, forKey: "hasPendingPurchase") sharedDefaults.synchronize() // 发起购买 do { let result = try await product.purchase() switch result { case .success(let verification): // 处理验证逻辑... // 交易完成后清除标记 clearPendingPurchaseFlag() case .userCancelled, .pending: // 用户取消或仍在待处理,根据情况处理 if case .userCancelled = result { clearPendingPurchaseFlag() } default: clearPendingPurchaseFlag() } } catch { print("购买失败: \(error)") clearPendingPurchaseFlag() } } private func clearPendingPurchaseFlag() { let sharedDefaults = UserDefaults(suiteName: sharedSuiteID)! sharedDefaults.removeObject(forKey: "hasPendingPurchase") sharedDefaults.synchronize() }
3. 所有设备:监听KV存储变化并更新付费墙
在应用启动时添加监听器,实时同步待处理状态:
func setupPendingPurchaseListener() { let sharedDefaults = UserDefaults(suiteName: sharedSuiteID)! // 启动时先检查一次当前状态 updatePaywallStatus(hasPending: sharedDefaults.bool(forKey: "hasPendingPurchase")) // 监听KV存储变化 NotificationCenter.default.addObserver( self, selector: #selector(handleSharedDefaultsChange), name: UserDefaults.didChangeNotification, object: sharedDefaults ) } @objc private func handleSharedDefaultsChange() { let sharedDefaults = UserDefaults(suiteName: sharedSuiteID)! let hasPending = sharedDefaults.bool(forKey: "hasPendingPurchase") updatePaywallStatus(hasPending: hasPending) } // 根据待处理状态更新付费墙(禁用/启用) private func updatePaywallStatus(hasPending: Bool) { paywallView.isUserInteractionEnabled = !hasPending // 禁用付费墙交互 purchaseButton.isEnabled = !hasPending pendingIndicator.isHidden = !hasPending // 显示"处理中"提示 }
兜底与边缘场景处理
- 离线设备同步:设备离线时KV存储变化不会实时推送,应用每次启动时主动检查KV存储状态即可
- 未登录iCloud的设备:此类设备无法共享KV存储,可在启动时提示用户登录iCloud以获得跨设备同步体验;同时依赖本地StoreKit查询确保已购权限不会被误拦截
- 多类型购买区分:若应用有多种付费产品(订阅/终身权限),可将标记改为具体产品ID(如键
pendingProductID,值为产品ID),实现精准禁用对应付费选项
内容的提问来源于stack exchange,提问作者xav
相关产品推荐
相关产品推荐

