如何在 iOS 14 Home Widget 中显示当前时间(实时)

use*_*291 6 widget swift widgetkit swiftui ios14

我正在为 ios 14 Home Widget 开发一个应用程序,在显示当前时间(数字时钟)时遇到一个问题,即该小部件没有每秒更新。众所周知,苹果不允许每秒触发时间线,有没有其他方法可以实时更新显示当前时间?

我尝试了这些方法,但没有按预期工作

class NetworkManager: ObservableObject {
    @Published var dateIs = Date()
    
    init() {
        startTimer() // fetch data must be called at least once
    }
    private  func startTimer() { 
        let t = RepeatingTimer(timeInterval: 3)
                t.eventHandler = {
                    DispatchQueue.main.async() {
                        // your UI update code
                        print("Timer Fired")
                     self.dateIs = Date()
                        WidgetCenter.shared.reloadAllTimelines() // reload timelines
                    }
                    if(false){   //I know this makes no sense, but it works. Go figure...
                        t.suspend()
                    }
                }
                t.resume()

    }
}


struct Provider: TimelineProvider {

    init() {
        networkManager = NetworkManager()
    }

    
    @AppStorage("storedData", store: UserDefaults(suiteName: "group.com.name"))
    var data: Data  = Data()
    
    func placeholder(in context: Context) -> WidgetEntry {
        let entry = WidgetEntry(date: Date(), storedData: storedData[0], dateIs: networkManager.dateIs)
        return entry
    }
    
    func getSnapshot(in context: Context, completion: @escaping (WidgetEntry) -> Void) {
        
        guard let storedData: WidgetTemplate = try? JSONDecoder().decode(WidgetTemplate.self, from: data) else { return }
        let entry = WidgetEntry(date: Date(), storedData: storedData, dateIs: networkManager.dateIs)
          
        completion(entry)
    }
    
    func getTimeline(in context: Context, completion: @escaping (Timeline<WidgetEntry>) -> Void) {
    
        guard let storedData: WidgetTemplate = try? JSONDecoder().decode(WidgetTemplate.self, from: data) else { return }
        let entry = WidgetEntry(date: Date(), storedData: storedData, dateIs: networkManager.dateIs)
        
        let currentDate = Date()
        let refreshDate = Calendar.current.date(byAdding: .minute, value: 5, to: currentDate)!
        
        let timeline = Timeline(entries: [entry], policy:  .after(refreshDate))
        completion(timeline)
    }
    
}
Run Code Online (Sandbox Code Playgroud)

paw*_*222 3

您\xe2\x80\x99 不允许每秒刷新该Widget 。那\xe2\x80\x99是Apple的限制。

\n

您能做的最好的事情就是使用日期样式显示带秒的timer日期:

\n
/// A style displaying a date as timer counting from now.\n///\n///     Text(event.startDate, style: .timer)\n///\n/// Example output:\n///    2:32\n///    36:59:01\npublic static let timer: Text.DateStyle\n
Run Code Online (Sandbox Code Playgroud)\n
\n
    \n
  1. 您需要一个简单的Entry属性Date
  2. \n
\n
struct SimpleEntry: TimelineEntry {\n    let date: Date\n}\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 在 中传递给定日期的午夜日期,并在下一个午夜Entry后刷新时间线:
  2. \n
\n
struct SimpleProvider: TimelineProvider {\n    ...\n\n    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {\n        let midnight = Calendar.current.startOfDay(for: Date())\n        let nextMidnight = Calendar.current.date(byAdding: .day, value: 1, to: midnight)!\n        let entries = [SimpleEntry(date: midnight)]\n        let timeline = Timeline(entries: entries, policy: .after(nextMidnight))\n        completion(timeline)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 使用以下样式显示日期timer
  2. \n
\n
struct SimpleWidgetEntryView: View {\n    var entry: SimpleProvider.Entry\n\n    var body: some View {\n        Text(entry.date, style: .timer)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

请注意,当您刷新时间线(通过指定TimelineReloadPolicy或通过调用WidgetCenter)时,您设置了刷新 Widget 的最早时间。

\n

不保证在该特定时间刷新。

\n