SwiftUI集成Glassfy内购成功后如何通过AppStorage更新视图
问题原因
@AppStorage的自动视图刷新能力仅对SwiftUIView内声明的属性生效,你把它写在IAPManager普通单例类中时,它只是个普通属性,修改后不会向SwiftUI发送刷新通知,自然不会触发视图切换。- Glassfy的回调默认运行在后台线程,直接更新UI相关状态会导致刷新延迟甚至不生效。
最简修复方案(仅用AppStorage实现,无需额外状态管理)
第一步:清理IAPManager中的无效属性
删除IAPManager里的这行代码:
@AppStorage("boughtFirst") var boughtFirst = false
第二步:在视图层声明可触发刷新的AppStorage属性
在你写购买/已购买内容切换逻辑的View结构体中,直接声明@AppStorage属性,只有在这里声明的属性变更才会自动触发视图重绘:
struct ContentView: View { // 仅在此处声明boughtFirst状态,修改后自动刷新UI @AppStorage("boughtFirst") private var boughtFirst = false var body: some View { NavigationView { VStack { if !boughtFirst { BuyExtraContent() } else { AllView() } } } .onAppear { // 页面每次展示时拉取最新权限,避免本地缓存状态和实际购买状态不一致 IAPManager.shared.getPermissions() } } }
原来的两个平行if判断可以直接换成if-else,逻辑更清晰。
第三步:修改IAPManager中的状态更新逻辑
@AppStorage本质是监听UserDefaults对应键值的变化,你不需要持有这个属性,只要在任意位置更新UserDefaults中对应key的值,视图就会自动刷新。
同时注意:所有Glassfy的回调都要切回主线程再更新状态,避免线程问题导致不刷新。
把IAPManager三个方法(purchase/getPermissions/restorePurchases)中原来写self.boughtFirst = true的位置,全部替换为以下代码:
// 切回主线程更新存储值 DispatchQueue.main.async { UserDefaults.standard.set(true, forKey: "boughtFirst") }
以purchase方法为例,修改后的核心逻辑是:
func purchase(sku: Glassfy.Sku) { Glassfy.purchase(sku: sku) { transaction, error in guard let t = transaction, error == nil else { return } if t.permissions["numberOne"]?.isValid == true { NotificationCenter.default.post( name: Notification.Name("numberOne"), object: nil ) DispatchQueue.main.async { UserDefaults.standard.set(true, forKey: "boughtFirst") } } } }
getPermissions和restorePurchases里的状态更新逻辑按同样方式修改即可。
方案说明
- 不需要让
IAPManager遵循ObservableObject,不需要加@Published或者其他第三方状态管理工具,完全符合你想用最简逻辑、仅靠AppStorage实现状态同步的需求。 - 只要购买/恢复/权限校验通过,更新UserDefaults后,所有声明了
@AppStorage("boughtFirst")的视图都会立刻自动刷新,切换到已购买内容页。
内容的提问来源于stack exchange,提问作者Alex Karpukhin
相关产品推荐
相关产品推荐

