如何保持 WidgetKit 上的现有条目刷新?

问题描述

我在我的小部件中使用了 HealthKit 数据。如果手机被锁定,则无法获取 HealthKit 数据,只有在手机解锁时才能获取。但是,即使手机被锁定,我的小部件时间线也会尝试更新。

是否有可能以某种方式返回一个空的完成,以便保持当前小部件数据不变?

这是我的代码

struct Provider: IntentTimelineProvider {
    private let healthKitService = HealthKitService()
    func getTimeline(for configuration: ConfigurationIntent,in context: Context,completion: @escaping (Timeline<Entry>) -> ()) {
        let currentDate = Date()
        let refreshDate = Calendar.current.date(byAdding: .minute,value: 5,to: currentDate)!
        
        healthKitService.getHeartRate() { data,error in
            
            //Create an empty entry
            var entry = SimpleEntry(date: currentDate,configuration: ConfigurationIntent(),data: nil)

            //If no errors,set data
            if(error == nil) {
                entry.data = data
            } else {
                print(error) //this runs when a locked phone does the widget update
            }
            
            //Return response
            let timeline = Timeline(entries: [entry],policy: .after(refreshDate))
            completion(timeline)
        }
    }
}

我能做的是将条目数据存储在 UserDefaults 中并将其加载到错误路由中?我不确定这是否是一个好的解决方案。

解决方法

主要问题是您在 function getdata(){ var email=document.getElementById("email").value; firebase.database().ref('0/'+email).once('value').then(function(snapshort){ var total=snapshort.val().total; document.getElementById("total").innerHTML=total; })} 函数中没有 state。这与 How to refresh multiple timers in widget iOS14? 中的问题类似 - 您需要某种方式将信息存储在 getTimeline 之外。

正如您已经提到的,一个可能的解决方案是将最后一个条目存储在 getTimeline 中。

不过,您也可以尝试创建自己的 UserDefatuls

EntryCache
class EntryCache {
    var previousEntry: SimpleEntry?
}
struct SimpleEntry: TimelineEntry {
    let date: Date
    var previousDate: Date?
}

注意

我没有找到有关何时可以重新创建 struct IntentProvider: IntentTimelineProvider { private let entryCache = EntryCache() // ... // in this example I'm testing if the `previousDate` is loaded correctly from the cache func getTimeline(for configuration: TestIntentIntent,in context: Context,completion: @escaping (Timeline<SimpleEntry>) -> Void) { let currentDate = Date() let entry = SimpleEntry(date: currentDate,previousDate: entryCache.previousEntry?.date) let refreshDate = Calendar.current.date(byAdding: .minute,value: 1,to: currentDate)! let refreshEntry = SimpleEntry(date: refreshDate,previousDate: entryCache.previousEntry?.date) let timeline = Timeline(entries: [entry,refreshEntry],policy: .atEnd) // store the `entry` in the `entryCache` entryCache.previousEntry = entry completion(timeline) } } 的任何信息。在我的测试中,Widget 每次刷新都使用相同的 TimelineProvider,但更安全的做法是假设 Provider 可能会在未来某个时间点重新初始化。然后,理论上,对于一个刷新周期,Provider 将为 previousEntry