Guides and Sample Code

Developer

App Programming Guide for watchOS

On This Page

Managing Complications

To support a complication for your app, do the following:

  1. Identify the data you want to display in your complication.

  2. Select the templates you support for each family.

  3. Implement a data source object to provide your data to ClockKit.

  4. Configure your WatchKit extension to tell ClockKit that you support a complication.

When creating a new Watch app, you can ask Xcode to create the resources you need for a complication. Xcode provides you with a data source class and configures your project to use that class. If you did not enable complication support when creating your Watch app, you can add that support later.

Designing the Complication

Before creating a complication, you need to determine the complication’s content. Consider the following factors when determining what you intend to show in your complication:

  • Can you fit your data into the available complication templates? Space for data is limited. You can choose which templates you want to use for each family, but for many templates there may only be space for a few characters of text or for a small image. Can you use the available space to convey your information to the user?

  • Do you already use notifications to convey timely information to the user? If you are using notifications to deliver updates to the user, a complication might serve as a more unobtrusive way to deliver the same data. For example, a sports app might use a complication to post updated sports scores rather than send notifications when the scores change.

  • How much data can you provide in advance? If your app’s data changes frequently, it might be difficult to provide enough data to display in a complication. Worse, if you refresh your complication data too frequently, you may exceed your background execution or transfer budgets.

    Watch apps with a complication on the active watch face are given larger budgets for background tasks, but the background execution time per hour is still limited. Alternatively, you can generate the complication data on the user’s iPhone and transfer it to the Watch app, but you are given only 50 complication transfers a day. Be sure that you can provide useful and timely information within these constraints.

You should strongly consider creating complications for your app, even if they only act as a launcher for your Watch app; however, users are more likely to add your complication to their watch faces when they provide timely, up-to-date, and useful information at a glance.

After you have determined what you intend to show in your complication, the next step is to define your data source object and use it to provide information about your complication and to create timeline entries.

Implementing the Data Source Object

ClockKit interacts with your complication through your app’s complication data source object. The data source object is an instance of a class that conforms to the CLKComplicationDataSource protocol. You define the class, but you do not create instances of that class at runtime. Instead, you specify the name of the class in your Xcode project settings and ClockKit instantiates that class as needed. During instantiation, ClockKit initializes your data source class using the standard init method.

The job of your data source class is to provide ClockKit with any requested data as quickly as possible. The implementations of your data source methods should be minimal. Do not use your data source methods to fetch data from the network, compute values, or do anything that might delay the delivery of that data. If you need to fetch or compute the data for your complication, do it in your iOS app or in other parts of your WatchKit extension (for example, by scheduling a background app refresh task), and cache the data in a place where your complication data source can access it. The only thing your data source methods should do is take the cached data and put it into the format that ClockKit requires.

For detailed information about the methods of the CLKComplicationDataSource protocol, see CLKComplicationDataSource Protocol Reference.

Providing Your Timeline Data

Packaging your app-specific data into a template that ClockKit can then display onscreen is your data source’s most important job. Each family of complications has one or more templates that you can use to build your content. The templates define the position of text and images within the space allotted for the complication. After creating the template object with your data, assign it to a CLKComplicationTimelineEntry object, specify an appropriate date at which to display the data, and return the timeline entry to ClockKit.

When specifying the data for your templates, you use CLKTextProvider and CLKImageProvider objects to specify values instead of raw strings and images. Provider objects take raw data and format it in the best way possible for the corresponding template. ClockKit provides several text providers for handling dates and times, including relative time values that update dynamically without affecting your complication’s budgeted execution time.

Listing 18-1 illustrates how to create the current timeline entry for a complication. After fetching the needed data from the extension delegate, the method configures the template object for the specified complication family and assigns it to a timeline entry object. The date you specify for the current entry must be equal to or earlier than the current time. For past and future entries, set the date to the appropriate time at which to display the corresponding data.

Listing 18-1Creating a timeline entry

Objective-C

  1. // Keys for accessing the complicationData dictionary.
  2. extern NSString* ComplicationCurrentEntry;
  3. extern NSString* ComplicationTextData;
  4. extern NSString* ComplicationShortTextData;
  5. - (void)getCurrentTimelineEntryForComplication:(CLKComplication *)complication
  6. withHandler:(void(^)(CLKComplicationTimelineEntry *))handler {
  7. // Get the current complication data from the extension delegate.
  8. ExtensionDelegate* myDelegate = (ExtensionDelegate*)[[WKExtension sharedExtension] delegate];
  9. NSDictionary* data = [myDelegate.myComplicationData objectForKey:ComplicationCurrentEntry];
  10. CLKComplicationTimelineEntry* entry = nil;
  11. NSDate* now = [NSDate date];
  12. // Create the template and timeline entry.
  13. if (complication.family == CLKComplicationFamilyModularSmall) {
  14. CLKComplicationTemplateModularSmallSimpleText* textTemplate =
  15. [[CLKComplicationTemplateModularSmallSimpleText alloc] init];
  16. textTemplate.textProvider = [CLKSimpleTextProvider
  17. textProviderWithText:[data objectForKey:ComplicationTextData]
  18. shortText:[data objectForKey:ComplicationShortTextData]];
  19. // Create the entry.
  20. entry = [CLKComplicationTimelineEntry entryWithDate:now
  21. complicationTemplate:textTemplate];
  22. }
  23. else {
  24. // ...configure entries for other complication families.
  25. }
  26. // Pass the timeline entry back to ClockKit.
  27. handler(entry);
  28. }

Swift

  1. // Keys for accessing the complicationData dictionary.
  2. let ComplicationCurrentEntry = "ComplicationCurrentEntry"
  3. let ComplicationTextData = "ComplicationTextData"
  4. let ComplicationShortTextData = "ComplicationShortTextData"
  5. func getCurrentTimelineEntryForComplication(complication: CLKComplication,
  6. withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) {
  7. // Get the complication data from the extension delegate.
  8. let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate
  9. var data : Dictionary = myDelegate.myComplicationData[ComplicationCurrentEntry]!
  10. var entry : CLKComplicationTimelineEntry?
  11. let now = NSDate()
  12. // Create the template and timeline entry.
  13. if complication.family == .ModularSmall {
  14. let longText = data[ComplicationTextData]
  15. let shortText = data[ComplicationShortTextData]
  16. let textTemplate = CLKComplicationTemplateModularSmallSimpleText()
  17. textTemplate.textProvider = CLKSimpleTextProvider(text: longText, shortText: shortText)
  18. // Create the entry.
  19. entry = CLKComplicationTimelineEntry(date: now, complicationTemplate: textTemplate)
  20. }
  21. else {
  22. // ...configure entries for other complication families.
  23. }
  24. // Pass the timeline entry back to ClockKit.
  25. handler(entry)
  26. }

Updating Your Complication Data

ClockKit provides several ways for you to update your complication data at runtime:

  • Update the data explicitly when your WatchKit extension is running.

  • Schedule background app refresh tasks to update your complication data.

  • Transfer complication data from your iOS app.

  • Use push notifications to update your data.

Whenever your app has new data for your complication, call the CLKComplicationServer object’s reloadTimelineForComplication: or extendTimelineForComplication: method to update your timeline. The reloadTimelineForComplication: method deletes and replaces your entire timeline, while the extendTimelineForComplication: method adds data to the end of your existing timeline. In either case, ClockKit instantiates your data source object and requests the required data from it.

Do not call these methods unless you have new data for your complication. Note that both background tasks and complication transfers are budgeted. If you exceed your budget, you cannot update your complications until that budget is restored.

Be sure to keep you Watch app, your notifications, and your complications in a constant state. Whenever you update your app’s data, be sure to also update your complication. If you receive a push notification with new data, update both the app and your complication to keep them consistent with the notification.

If your data changes at predictable times, consider scheduling a background app refresh tasks to update your complication. When the background task is triggered, gather the new data (for example, using an NSURLSession background transfer). As soon as you have the updated data, call your data source’s reloadTimelineForComplication: or extendTimelineForComplication: method to update the timeline, and schedule the next background app refresh task.

Alternatively, you can perform more-complex or expensive data gathering tasks in your iOS app, and then transmit that data to the watch. Use the Watch Connectivity framework to send the update to the watch by calling your WCSession object’s transferCurrentComplicationUserInfo: method. This method sends a high priority message to your WatchKit extension, waking it as needed to deliver the data. As soon as the watch receives the data, it calls your session delegate’s session:didReceiveUserInfo: method. In this method, update your complication data using the provided user info dictionary, and then call your data source’s reloadTimelineForComplication: or extendTimelineForComplication: method to update your timeline.

Providing Placeholder Templates

During customization of the clock face, ClockKit displays the localizable placeholder template returned by your data source’s getLocalizableSampleTemplateForComplication:withHandler: method. You must provide placeholder templates for each family of complications you support. ClockKit asks for placeholder templates only once after your app is installed on Apple Watch. It caches the templates you provide and does not ask for them again until your app is reinstalled or updated. For more information, see Placeholder Templates.

Configuring Your Xcode Project’s Complication Support

To run your extension, ClockKit needs to know the name of your data source class and the complication families that you support. Xcode provides an interface for specifying this information in the General tab of your WatchKit extension’s project, as shown in Figure 18-1. If you asked Xcode to configure your complication when you created your Watch app, the fields should already contain default values.

Figure 18-1Configuring the complication settings image: ../Art/complication_project_settings_2x.png

The data you specify in the General tab is added to the Info.plist file of your WatchKit extension. Xcode adds the following keys and sets the values appropriately based on the information you provide.

  • CLKComplicationsPrincipalClass. The value of this key is a string containing the name of the data source class that provides your app’s complication data.

  • CLKSupportedComplicationFamilies. The value of this key is an array of strings containing the complication styles your app supports. The value for each string is the name of one of the constants in the CLKComplicationFamily enumerated type. For example, if you support only modular complications, you would include entries with the strings CLKComplicationFamilyModularLarge and CLKComplicationFamilyModularSmall.

Complications and the Watch App Gallery

Users can configure their watch faces on the iPhone using the gallery area of the Apple Watch app . To add your complication to the gallery, you must create a complication bundle that gives the user a preview of your complication. The complication bundle is stored in your iOS app bundle and used by the Apple Watch app to populate the gallery.

For instructions on creating the complication bundle, see Adding Complications to the Gallery