The Watch App Architecture

When the user selects your Watch app from the Home screen, watchOS launches it into the foreground. Your app remains in the foreground until the user dismisses it. Even when not in the foreground, your app may still run periodically. Specifically, apps run in the background when their complication is on the current watch face, when the app is in the dock, and when they are handling notifications. In addition, apps in the dock and apps with an active complication remain in memory, which lets the system launch them more quickly.

A Watch app consists of two bundles: the Watch app bundle and the WatchKit extension bundle. Figure 3-1 shows the relationship between these two bundles. The Watch app bundle contains your app’s storyboards, while the WatchKit extension contains your app’s code and additional resources. Communication between your WatchKit extension and your iOS app is also possible through the Watch Connectivity framework.

Note

Complications exist entirely in the WatchKit extension. Their user interface is not defined in the Watch app. Instead, it is defined by an object implementing the CLKComplicationDataSource protocol. When watchOS needs to update your complication, it launches your WatchKit extension. However, the Watch app interface is not loaded.

Figure 3-1Relationship between the Watch app interface, the WatchKit extension, and the iOS app

Implementing the Extension Delegate

Your WatchKit extension has an extension object (WKExtension) and a corresponding delegate object to manage behavior that is central to your app. The WKExtension object is a shared object that is available when the system displays your main Watch interface or your custom notification interfaces. It is also available whenever your complications are updating. The extension object has an associated delegate object that conforms to the WKExtensionDelegate protocol.

At launch time, the WatchKit extension automatically instantiates your extension delegate class. It gets the name of this class from the WKExtensionDelegateClassName key of the WatchKit extension’s Info.plist file. Xcode provides an extension delegate class automatically for every WatchKit extension target, and it configures the Info.plist file accordingly. All you have to do is add your code to the source file that Xcode provides.

Managing the Watch App Life Cycle

The WatchKit extension notifies the extension delegate at various points as the app transitions to and from different states. You use those notifications to implement the life cycle behaviors that your app requires. Figure 3-4 shows the state transitions that occur when your Watch app is launched and the methods of the WKExtensionDelegate protocol that are called for each transition. At launch time, use these methods to prepare your app’s data structures, check for data from the counterpart iOS app, and initiate requests for any new data.

The WatchKit extension delivers life cycle events to your extension delegate only when your Watch app runs. It does not deliver these events when your extension is launched for your notification interfaces or complications.

At launch time, a Watch app normally transitions from the inactive state directly to the active state. It transitions back to the inactive state when the user exits the app, and at some point later may transition to the background and become suspended. If the app is in the dock or one of its complications is on the active watch face, the app remains in the suspended state; otherwise it silently transitions to the Not running state.

The delivery of life cycle events may be intermixed with the delivery of activation and deactivation events to the app’s interface controllers, and the order of delivery is not guaranteed. In other words, the willActivate method of an interface controller may be called before or after the applicationDidBecomeActive method of the extension delegate. Your app must respond appropriately regardless of the order.

Managing Scenes

Like an iOS app, the Watch app consists of one or more scenes, where each scene represents a full screen of content. Each scene in the Watch app bundle’s storyboard is managed by a single interface controller object in the WatchKit extension. The interface controller is a subclass of the WKInterfaceController class. An interface controller in watchOS serves the same purpose as a view controller in iOS: it presents and manages content on the screen and responds to user interactions with that content. Unlike a view controller, an interface controller does not manage the actual views of your interface. Those views are managed for you by watchOS.

The main Watch app interface typically contains multiple scenes, with each one displaying a different type of information. Because the system displays only one scene at a time, an app presents new scenes in response to user actions. The navigation style of an app determines how scenes are presented. Apps can also present scenes modally as needed. For information on how to present new scenes, see Interface Navigation.

Note

While the WatchKit extension also uses interface controllers to manage custom notification interfaces, these controllers behave somewhat differently than those used by the main Watch app. For information about the implementing custom notification interfaces, see Notification Essentials.

The Interface Controller Life Cycle

At launch time, watchOS automatically loads the storyboard scene that is appropriate for the current interaction. If the user is viewing a notification, watchOS selects the correct notification scene. Otherwise, watchOS loads the initial scene for your app. After loading the scene, watchOS asks the WatchKit extension to create the corresponding interface controller object, which you use to prepare the scene for display to the user. Note shows the steps for this sequence. You’ll learn more about how interface controllers work in UI Essentials.

Figure 3-3Launching a Watch app

Use your interface controller’s init and awakeWithContext: methods to load any required data, set the values for any interface objects, and prepare your interface to be displayed. Do not use the willActivate to initialize your interface controller, instead use the willActivate method to make last-minute updates before your interface appears onscreen. The WatchKit extension also calls the didAppear method to let you know when your interface is actually onscreen.

While a scene is onscreen, user interactions are handled by the interface controller’s custom action methods. As the user interacts with tables, buttons, switches, sliders, and other controls, the WatchKit extension calls your action methods so that you can respond. Use action methods to update your interface or perform other relevant tasks. To perform tasks at other times, schedule a background refresh task to update your app. For more information on scheduling background tasks, see Background Refresh Tasks in WKExtensionDelegate Protocol Reference.

Note

Complication, and notification interfaces do not support action methods. Tapping your app’s complication always launches the app, while actionable notifications trigger the appropriate extension delegate methods. For more information on actionable notifications, see Configuring Actionable Notifications.

Your WatchKit extension remains running only while the user is interacting with your app on Apple Watch. Interactions with Apple Watch are meant to be brief, so interface controllers should be lightweight and never perform long-running tasks. When the user exits your app explicitly or stops interacting with Apple watch, iOS deactivates the current interface controller and eventually suspends execution of your extension, as shown in The Interface Controller Life Cycle.

Figure 3-4The life cycle of an interface controller

When the user reboots the paired iPhone, Watch apps are still able to run, but they cannot communicate with the iPhone until after the user unlocks it.

Background Tasks

Background tasks are a way for you to keep your app’s interfaces up-to-date. Receiving a background task object from the system is your signal to perform specific types of operations. The task object defines the type of task to perform and contains any data needed to complete the task. The system delivers background task objects to your app by calling the handleBackgroundTasks: method of your app’s extension delegate.

watchOS supports the following types of background tasks:

Background App Refresh Tasks. Use a WKApplicationRefreshBackgroundTask object to handle general updates to your app’s state. For example, you might use this type of task to check in with your company’s server or begin downloading new content. You schedule this type of background task explicitly from your your app’s WKExtension object.

Background Snapshot Refresh Tasks. Use a WKSnapshotRefreshBackgroundTask object to update your app’s interface in preparation of having its snapshot taken. The system automatically takes the snapshot when this task completes. The system schedules background snapshot refresh tasks periodically to update your snapshot. You can also schedule a task of this type explicitly from your app’s WKExtension object when your interface changes.

Background Watch Connectivity Tasks. Use a WKWatchConnectivityRefreshBackgroundTask object to receive data sent by your iOS app using the Watch Connectivity framework. The system automatically creates this type of task when your Watch app receives data from the its corresponding iOS app running on the paired iPhone. You do not schedule tasks of this type yourself.

Background NSURLSession Tasks. Use a WKURLSessionRefreshBackgroundTask object to receive data you previously requested using an NSURLSession object. This task is triggered when a background transfer requires authorization or when a background transfer completes (successfully or unsuccessfully). You do not schedule tasks of this type yourself.

Snapshots and the Dock

The dock is a way for users to launch your app or view its content quickly. Tapping the side button displays the dock, which holds up to ten apps. As the user scrolls through the apps, they see a snapshot of each app’s content—that is, they see a static image of the app’s interface. (The system also displays this static image at launch time.) If the user lets the dock settle for a moment, watchOS wakes up the corresponding app and replaces its snapshot with a live view of the app’s interface.

Always keep your app’s snapshot up-to-date to ensure that the information seen by the user is current and does not become stale. Apple Watch periodically sends a WKSnapshotRefreshBackgroundTask object to the extension delegate of apps in the dock. Use that task object to update your content and your app’s currently presented interface controller. When your interface changes in a meaningful way, you can also ask watchOS to update your snapshot by calling the scheduleSnapshotRefreshWithPreferredDate:userInfo:scheduledCompletion: method of your WKExtension object.

Debugging Your Activation Code in iOS Simulator

During testing, you can lock and unlock the simulator to verify that your activation and deactivation code is working as expected. Use the Hardware > Lock command to lock the Simulator. This simulates the screen turning off after the user lowers their wrist. In response, watchOS calls the didDeactivate method of the current interface controller. When you subsequently unlock the Simulator, watchOS calls the controller’s willActivate method.