在SwiftUI小部件中添加观察者的位置

问题描述

我正在尝试构建更好的小部件,我希望每次电池状态或电量变化时都刷新小部件。我知道两者都需要通知。所以我的逻辑是当有关电池状态的通知更改时,我想刷新时间轴。

但是我无法理解将观察者放在TimelineProvider或Widget视图下的什么位置?

struct timeWidgetEntryView : View {
    var entry: Provider.Entry
    let NC = NotificationCenter.default
    
    init(entry:Provider.Entry) {
        self.entry = entry

    }

    func batterylevelDidChange(_ notification: Notification) {
        UIDevice.current.isBatteryMonitoringEnabled = true
        var level = UIDevice.current.batterylevel
        level = level * 100
        WidgetCenter.shared.reloadAllTimelines()
        NSLog("Level changed / state changed")
    }
    
    var body: some View {
        vstack {
            Text(entry.date,style: .time).foregroundColor(.black).frame(minWidth: /*@START_MENU_TOKEN@*/0/*@END_MENU_TOKEN@*/,idealWidth: 100,maxWidth: 100,minHeight: /*@START_MENU_TOKEN@*/0/*@END_MENU_TOKEN@*/,idealHeight: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/,maxHeight: 50,alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
            Text("Battery : \(entry.batteryState)").foregroundColor(.black).frame(minWidth: /*@START_MENU_TOKEN@*/0/*@END_MENU_TOKEN@*/,idealWidth: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/,maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/,alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
        }
        .cornerRadius(10)
        .frame(width:.infinity,height:.infinity,alignment: .center)
        .onReceive(NotificationCenter.default.publisher(for: UIDevice.batteryStateDidChangeNotification))
               { obj in
                  // Change key as per your "userInfo"
                  if let userInfo = obj.userInfo,let info = userInfo["info"] {
                     print(info)
                  }
            
            WidgetCenter.shared.reloadAllTimelines()
        }
    }
}

但是它没有按预期工作,所以我的问题是我应该将观察者移到时间轴提供者吗?如果是,在哪里?

解决方法

您需要改用主应用程序中的通知-如Apple教程中所述:

然后,当您收到UIDevice.batteryStateDidChangeNotification时,只需致电:

WidgetCenter.shared.reloadAllTimelines()

要在看不见您的应用时继续接收通知,您可能需要启用后台通知。看到这个线程: