SwiftUI自动续订订阅测试异常:isPremium莫名变为false求助
1. StoreKit测试订阅到期
你使用的StoreKit配置文件中,测试订阅是带有固定到期时间的(比如5分钟、1小时),到期后StoreKit会自动标记订阅失效,purchasedSubscriptions数组会移除对应产品,此时isPurchased返回false,isPremium就会被重置为false。
解决办法:
- 打开StoreKit配置文件,编辑订阅产品的测试订阅期限,改为更长时长(比如1天),或者设置为「永不过期」(仅适用于测试场景);
- 订阅到期后,通过Xcode的「Window > StoreKit > StoreKit Test」窗口手动续订测试订阅。
2. purchasedSubscriptions未实时同步订阅状态
你的isPurchased逻辑依赖purchasedSubscriptions数组,但如果这个数组没有监听StoreKit的订阅状态变化(比如续订、过期、退款),就会出现状态不同步,导致检查结果错误。
解决办法:
在StoreManager中监听Transaction.updates流,实时更新purchasedSubscriptions:
class StoreManager: ObservableObject { @Published var purchasedSubscriptions: [Product] = [] @Published var subscriptions: [Product] = [] init() { Task { await loadSubscriptions() await listenForTransactionUpdates() } } private func loadSubscriptions() async { do { // 替换为你的订阅产品ID数组 subscriptions = try await Product.products(for: ["com.yourapp.premium"]) } catch { print("加载订阅产品失败:\(error)") } } private func listenForTransactionUpdates() async { for await transaction in Transaction.updates { await updatePurchasedSubscriptions() } } private func updatePurchasedSubscriptions() async { var purchased: [Product] = [] for await result in Transaction.currentEntitlements { guard case .success(let transaction) = result else { continue } if let product = subscriptions.first(where: { $0.id == transaction.productID }) { purchased.append(product) } await transaction.finish() } purchasedSubscriptions = purchased } }
3. load()函数仅执行一次,未响应状态变化
当前load()只在ContentView的.task中执行一次,但订阅状态发生变化(比如续订、过期)时,不会重新调用load()更新isPremium,导致isPremium停留在旧值,或后续被错误覆盖。
解决办法:
监听storeManager.purchasedSubscriptions的变化,自动触发load()更新isPremium:
struct ContentView: View { @EnvironmentObject private var storeManager: StoreManager @AppStorage("isPremium") private var isPremium = false var body: some View { TabView { FirstView() SecondView() } .task { await load() } .onChange(of: storeManager.purchasedSubscriptions) { _ in Task { await load() } } } private func load() async { guard let subscription = storeManager.subscriptions.first else { return } isPremium = (try? await storeManager.isPurchased(subscription)) ?? isPremium } }
4. Product实例的Equatable比较逻辑问题
默认情况下,Product的contains比较可能基于实例引用而非产品ID,如果storeManager.subscriptions中的Product实例和purchasedSubscriptions中的不是同一个,contains会返回false。
解决办法:
修改isPurchased函数,基于产品ID判断订阅状态:
func isPurchased(_ product: Product) async throws -> Bool { return purchasedSubscriptions.contains(where: { $0.id == product.id }) }
内容的提问来源于stack exchange,提问作者Alexnnd
相关产品推荐
相关产品推荐

