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: SetWKRefreshBackgroundTask) {
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
Post
Replies
Boosts
Views
Activity
I find that there are no issues when running on the simulator but on the device it stops updating.
I have now raised a Code Level Support Ticket so will update this discussion if I get any news.
When you create timeline entries you specify a start and end date, for me I have used 24 hours (as in Apples sample) but I guess this could be changed.
The engineer seemed to suggest that the watch could update 4 times per hour, so you could try updating every hour to be safe.
// Calculate the start and end dates.
var current = date.addingTimeInterval(minute)
let endDate = date.addingTimeInterval(24.0 * 60.0 * 60.0)
while (current.compare(endDate) == .orderedAscending) && (entries.count limit) {
if let timeline = createTimelineEntry(complication: complication, forDate: current) {
entries.append(timeline)
}
current = current.addingTimeInterval(minute)
}
From the documentation getTimelineEntries should work. It is only called once every 24 hours and creates an array of entries.
It says that: If two entries are less than one minute apart, ClockKit discards one of the entries.
Apologies, I started a new Post as I accidentally clicked Resolved on the old one.
Using the official sample, Coffee Tracker, it provides timeline entries every 5 minutes.
My app is doing the same thing every 1 minute and works fine for 5 days.
It does not use background updates (maximum 4 per hour), just timeline entries.
// Return future timeline entries.
func getTimelineEntries(for complication: CLKComplication,
after date: Date,
limit: Int,
withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) - Void) {
let fiveMinutes = 5.0 * 60.0
let twentyFourHours = 24.0 * 60.0 * 60.0
// Create an array to hold the timeline entries.
var entries = [CLKComplicationTimelineEntry]()
// Calculate the start and end dates.
var current = date.addingTimeInterval(fiveMinutes)
let endDate = date.addingTimeInterval(twentyFourHours)
// Create a timeline entry for every five minutes from the starting time.
// Stop once you reach the limit or the end date.
while (current.compare(endDate) == .orderedAscending) && (entries.count limit) {
entries.append(createTimelineEntry(forComplication: complication, date: current))
current = current.addingTimeInterval(fiveMinutes)
}
handler(entries)
}
I accidentally clicked solved but I still need to share the debug info and source! Hopefully an engineer will still pick up.
I have the sysdiagnose tar and some source to share. What is the best way to get you the files?
Hi, and thanks for the reply. The app tells the time in German. As such it needs to update every minute.
The logging profile you have sent says it will expire after 3 days and I am only seeing the issue after 5-6 days.
Does this mean I will have to re-enable it after it expires?
If needed I can provide you the full source for the app to debug/profile locally.