Create complications for Apple Watch

Description: When you add complications to a Watch app, people can access glanceable and up to date information directly from their watch face. We’ll show you how to create and build complications from the ground up and introduce you to Multiple Complications. Learn how to construct timelines, use families and templates, and discover best practices on crafting a thorough complication experience.

Timelines

  • Representation of your complication's data over time
  • Enables ClockKit to query your app once and get all information needed
  • Extend or invalidate as necessary to ask ClockKit to re-query your app
  • Your complication will show an entry until the date of the next one

Complication building blocks

Providing data

  • When providing a timeline, we're giving WatchKit a list of CLKComplicationTimelineEntry instances.
  • These will populate your complications
  • Each entry represents what your complications should look like at a certain point in time.
  • Each entry has two properties:
    • Date, which is the date that this entry should be visible
    • Complication template, which is the template containing the data you want to display for this entry
  • Your main interaction with ClockKit is through an object you create that conforms to CLKComplicationDatasource.
  • There's only one required method in this protocol:
class ComplicationController: NSObject, CLKComplicationDataSource {
    func getCurrentTimelineEntry(
        for complication: CLKComplication, 
        withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
        // Call the handler with the current timeline entry
        handler(createTimelineEntry(forComplication: complication, date: Date()))
    }
}
  • This function is used to get the current entry only, if we can/want to provide future entries as well, we will need to implement the following methods as well:
extension ComplicationController {

    // Specifies how far in the future you can provide entries 
    func getTimelineEndDate(
        for complication: CLKComplication, 
        withHandler handler: @escaping (Date?) -> Void) {
        handler(timeline(for: complication)?.endDate)
    }

    // lets you provide as many entries as is appropriate up to the limit after the given date
    func getTimelineEntries(
        for complication: CLKComplication, 
        after date: Date, 
        limit: Int, 
        withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
       handler(timeline(for: complication)?.entries(after: date, limit: limit))
    }
}

Reloading complications

Data Providers

  • Provided by ClockKit to adapt the display of the same data/values in different templates or families of complications.
  • CLKDateTextProvider will take care of displaying a date for you
let longDate: Date = DateComponents(year: 2020, month: 9, day: 23).date ?? Date()
let units: NSCalendar.Unit = [.weekday, .month, .day]
let textProvider = CLKDateTextProvider(date: longDate, units: units)
let timerStart: Date = …
let units: NSCalendar.Unit = [.hour, .minute, .second]
let textProvider = CLKRelativeDateTextProvider(date: timerStart, style: .timer, units: units)

Multiple complications

Getting information back to your app

  • Tapping a complication launches your app
  • Based on the CLKComplicationDescriptor description define above, the app will be launched with:
    • A userActivity
    • A userInfo dictionary

Missing anything? Corrections? Contributions are welcome 😃

Related

Written by

Federico Zanetello

Federico Zanetello

Software engineer with a strong passion for well-written code, thought-out composable architectures, automation, tests, and more.