Can't understand apple watch complications life cycle & get it to update

411 views Asked by At

I know there are many questions & examples out there but still, I can't understand how exactly complications updates so please help me out.

Here is my code to run & update the complications on watch os 5 to 7:

I want to update my complications every hour or less...

the setup functions I should implement are these:

Here is my "ComplicationController" class:

func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
    let future = localDate().addingTimeInterval(15.0 * 60.0 * 60.0)
    let template = createTemplate(forComplication: complication, date: future)
    handler(template)
}

  func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
    handler(createTimelineEntry(forComplication: complication, date: Date()))
}

func getTimelineStartDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
    handler(nil)
}

func getPrivacyBehavior(for complication: CLKComplication, withHandler handler: @escaping  (CLKComplicationPrivacyBehavior) -> Void) {
        handler(.showOnLockScreen)
}

func getTimelineEndDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
    handler(Date().addingTimeInterval(24.0 * 60.0 * 60.0))
}

func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler:@escaping (CLKComplicationTimeTravelDirections) -> Void) {
    handler([.forward])
}

func getTimelineEntries(for complication: CLKComplication, after date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
        let fifteenMinutes = 15.0 * 60.0
        let twentyFourHours = 24.0 * 60.0 * 60.0
        var entries = [CLKComplicationTimelineEntry]()
        var current = date.addingTimeInterval(fifteenMinutes)
        let endDate = date.addingTimeInterval(twentyFourHours)
        while (current.compare(endDate) == .orderedAscending) && (entries.count < limit) {
            if let entry = createTimelineEntry(forComplication: complication, date: current) {
                entries.append(entry)
                current = current.addingTimeInterval(fifteenMinutes)
            }
        }
        handler(entries)
 }

@available(watchOSApplicationExtension 7.0, *)
    func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
        print("ComplicationController getComplicationDescriptors called")
        let descriptors = [
            CLKComplicationDescriptor(identifier: "complication", displayName: "aaaaa", supportedFamilies: CLKComplicationFamily.allCases)
        ]
        handler(descriptors)
}

@available(watchOSApplicationExtension 7.0, *)
    func handleSharedComplicationDescriptors(_ complicationDescriptors: [CLKComplicationDescriptor]) {
}

 private func createTemplate(forComplication complication: CLKComplication, date: Date) -> CLKComplicationTemplate? {
    var platform =  emptyPlatform
    if let ps = ExtensionDelegate.platforms {
        if let p = ps.first {
            platform = p
        }
    } else {
        loadOfflinePlatforms { (plats) in
            if let p = plats.first {
                platform = p
            }
        }
    }
    switch complication.family {
    case .modularSmall:
        return createModularSmallTemplate(platform: platform)
    case .utilitarianSmall, .utilitarianSmallFlat:
        return createUtilitarianSmallFlatTemplate(platform: platform)
    case .circularSmall:
        return createCircularSmallTemplate(platform: platform)
    case .utilitarianLarge:
        return createUtilitarianLargeTemplate(platform: platform)
    case .graphicCorner:
        return createGraphicCornerTemplate(platform: platform)
    case .graphicCircular:
        return createGraphicCircleTemplate(platform: platform)
    case .graphicRectangular:
        return createGraphicRectangularTemplate(platform: platform)
    case .graphicBezel:
        return createGraphicBezelTemplate(platform: platform)
    case .extraLarge:
        return createExtraLargeTemplate()
    case .modularLarge:
        return createModularLargeTemplate(platform: platform)
    case .graphicExtraLarge:
        if #available(watchOSApplicationExtension 7.0, *) {
            return createGraphicExtraLargeTemplate(platform: platform)
        } else {
            fatalError("Graphic Extra Large template is only available on watchOS 7.")
            return createModularSmallTemplate(platform: platform)
        }
    @unknown default:
        fatalError("*** Unknown Complication Family ***")
        return nil
    }
}

Here is my ExtensionDelegate class:

 static var platforms:[Platform]!
 func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
    print("ExtensionDelegate handle called")
    for task in backgroundTasks {
        switch task {
        // Handle background refresh tasks.
        case let backgroundTask as WKApplicationRefreshBackgroundTask:
            WatchConnectivityHelper().getPlatforms { (platforms) in
                ExtensionDelegate.platforms = platforms
                self.scheduleBackgroundRefreshTasks()
                let server = CLKComplicationServer.sharedInstance()
                if let compli = server.activeComplications {
                    for complication in compli {
                        server.reloadTimeline(for: complication)
                    }
                }
                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() {
    print("ExtensionDelegate scheduleBackgroundRefreshTasks called")
    let watchExtension = WKExtension.shared()
    let targetDate = Date().addingTimeInterval(15.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("*** Background Task Completed Successfully! ***")
    }
}

So where are my mistakes?!

1

There are 1 answers

0
Mona On

In case still haven't figured this out, you should initiate the first call to your scheduleBackgroundRefreshTasks method in your applicationDidEnterBackground or applicationDidFinishLaunching delegate method.