I have developed a Watch app that features a complication.
It updates every minute and runs happily for 5 or 6 days, then stops updating. I.e. getTimelineEntries stops being called.
I have tried to replicate the issue using the simulator but it updates without problems.
The app tells the time in German and update the complication every minute.
I have created: FB9007754 which contains the source code and sysdiagnose log.
It updates every minute and runs happily for 5 or 6 days, then stops updating. I.e. getTimelineEntries stops being called.
I have tried to replicate the issue using the simulator but it updates without problems.
The app tells the time in German and update the complication every minute.
I have created: FB9007754 which contains the source code and sysdiagnose log.
I got some assistance from an Apple engineer and have solved the issue.
The key step is to call CLKComplicationServer.reloadTimeline(for:) as part of a background update. In my case every 6 hours.
class ExtensionDelegate: NSObject, WKExtensionDelegate {
func applicationDidFinishLaunching() {
scheduleBackgroundRefreshTasks()
}
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
for task in backgroundTasks {
switch task {
case let backgroundTask as WKApplicationRefreshBackgroundTask:
let complicationServer = CLKComplicationServer.sharedInstance()
for complication in complicationServer.activeComplications! {
complicationServer.reloadTimeline(for: complication)
}
self.scheduleBackgroundRefreshTasks()
backgroundTask.setTaskCompletedWithSnapshot(true)
case let snapshotTask as WKSnapshotRefreshBackgroundTask:
snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
connectivityTask.setTaskCompletedWithSnapshot(false)
case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
urlSessionTask.setTaskCompletedWithSnapshot(false)
case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask:
relevantShortcutTask.setTaskCompletedWithSnapshot(false)
case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask:
intentDidRunTask.setTaskCompletedWithSnapshot(false)
default:
task.setTaskCompletedWithSnapshot(false)
}
}
}
func scheduleBackgroundRefreshTasks() {
let watchExtension = WKExtension.shared()
let targetDate = Date().addingTimeInterval(360.0 * 60.0)
watchExtension.scheduleBackgroundRefresh(withPreferredDate: targetDate, userInfo: nil) { (error) in
if let error = error {
print("* An background refresh error occurred: \(error.localizedDescription) *")
return
}
print("* scheduleBackgroundRefreshTasks \(targetDate) *")
}
}
}
In case you are having trouble having your extension delegate add this line to your ...App.swift file.
@WKExtensionDelegateAdaptor(ExtensionDelegate.self) var appDelegate
The key step is to call CLKComplicationServer.reloadTimeline(for:) as part of a background update. In my case every 6 hours.
class ExtensionDelegate: NSObject, WKExtensionDelegate {
func applicationDidFinishLaunching() {
scheduleBackgroundRefreshTasks()
}
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
for task in backgroundTasks {
switch task {
case let backgroundTask as WKApplicationRefreshBackgroundTask:
let complicationServer = CLKComplicationServer.sharedInstance()
for complication in complicationServer.activeComplications! {
complicationServer.reloadTimeline(for: complication)
}
self.scheduleBackgroundRefreshTasks()
backgroundTask.setTaskCompletedWithSnapshot(true)
case let snapshotTask as WKSnapshotRefreshBackgroundTask:
snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
connectivityTask.setTaskCompletedWithSnapshot(false)
case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
urlSessionTask.setTaskCompletedWithSnapshot(false)
case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask:
relevantShortcutTask.setTaskCompletedWithSnapshot(false)
case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask:
intentDidRunTask.setTaskCompletedWithSnapshot(false)
default:
task.setTaskCompletedWithSnapshot(false)
}
}
}
func scheduleBackgroundRefreshTasks() {
let watchExtension = WKExtension.shared()
let targetDate = Date().addingTimeInterval(360.0 * 60.0)
watchExtension.scheduleBackgroundRefresh(withPreferredDate: targetDate, userInfo: nil) { (error) in
if let error = error {
print("* An background refresh error occurred: \(error.localizedDescription) *")
return
}
print("* scheduleBackgroundRefreshTasks \(targetDate) *")
}
}
}
In case you are having trouble having your extension delegate add this line to your ...App.swift file.
@WKExtensionDelegateAdaptor(ExtensionDelegate.self) var appDelegate