Thoughts on adding Apple Watch features to your iOS app

By Michael Argentini
Managing Partner, Technology and Design

With the release of the Apple Watch, developers have been scrambling to add support for the device to their apps. But there are a couple considerations that need to be top of mind.

  1. Not every app will benefit from projecting features onto the watch.
  2. Apps can only project content and functionality to the device, limiting their usefulness until WatchOS 2 is released this fall.

Apps that can provide value by adding features to the device (like Twitter sending tweets) are limited to projecting a template-based user interface and limited interactivity to an external display of sorts. The template presets are varied, and you can create your own. But you are limited to simple stacking of objects like text and images, grouping, and aligning them. You can't make granular changes like adjusting the line spacing. But that can be freeing. Apple has created a limited set of objects (which I'll refer to as controls) and has styled them to look good on its device. So you need to trust in that to some degree.

In a way these limitations make coding these interfaces easier; fewer features and available controls shrink the learning curve. And the fact that content is syndicated to the device from an iPhone makes coding for it much easier than a Notification Center widget, which requires group membership and other steps to communicate bi-directionally and otherwise access parent app resources.

Updating the Totem 2 app to support the watch was a case where there was clear value, since I wanted to duplicate the Notification Center "Quote of the Day" feature. This feature simply displays a random daily quotation with attribution, so it was perfectly suited for a watch app.

Glances

Glances are single screens that show important app information, and which are quickly accessible with a swipe up gesture. They can't scroll, and they have no interactions. Tapping them simply opens the parent app for a more rich experience.

At first, I thought that having a Glance was a natural fit for Totem. But since Glances can't scroll, I'd have to skip that feature. Truncating quotations to get them to fit on a single screen could work, but making the user tap the Glance to go to the app and read the entire quotation would be tedious.

The App

Coding the app itself is pretty straightforward. Once you add the target to your project, you use storyboards to assemble the user interface. Dropping groups onto the Interface Controller scene and embedding your controls in them is definitely a solid approach. This helps ensure a responsive layout on various watch sizes, and other future devices.

Of course you'll wire up your user interface elements, like labels and images, as weak outlets in the header files and target them in your code just like any other iOS app. The real limit here revolves around the choice of controls and breadth of functions available within the parent Interface Controller.

In the Quote of the Day app, I wanted to provide a button at the bottom to load a new random quote. This was fairly easy to do. In the watch app, a simple call to WKInterfaceController triggers the AppDelegate to execute a callback function named handleWatchKitExtensionRequest. Below is a call from the watch app to the AppDelegate (in Objective-C):

[WKInterfaceController openParentApplication:@{@"action" : @"getQuote"} reply:^(NSDictionary *replyInfo, NSError *error) {

        if (error) {
              NSLog(@"Error from parent: %@", error);
        } else {
              [self.quote setText:[replyInfo objectForKey:@"quote"]];
              [self.author setText:[replyInfo objectForKey:@"author"]];
              [self.attribution setText:[replyInfo objectForKey:@"attribution"]];
              [self.nextButton setHidden:NO];
        }
}];

And below is a portion of the AppDelegate callback function:

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo))reply {

    if ([[userInfo objectForKey:@"action"] isEqualToString:@"getQuote"])
    {
        // Do stuff to set up the quote, author, and attribution variables
        ...
    }

    reply(@{@"quote": quote,@"author":author,@"attribution":attribution});
}

But I realized that there was no way to force the Interface Controller to scroll to top after the button press. This was necessary because the new quote could be much longer and leave the user lost in the middle of a paragraph. Apparently, only the Watchkit Interface Tables support this feature. I did eventually resolve it, using a simple, pragmatic strategy:

Since the button press called the parent to retrieve the new quote data in a threaded callback function, I simply set the various labels to empty text values immediately after the callback declaration.

This forced the interface to scroll to top since the labels were set to dynamic heights based on their values. No value meant no height. Soon after the callback would return with a real quote, and redraw the UI a second time. This was one instance where Apple's tight control over the UI worked in my favor.

Icons and the iPhone Watch App

The Watch app target is embedded in your project as two folders: one for the watch extension, and one for the app itself. Even though controls seem to have access to the resources within the parent app, they don't. So any images (for example) that you want to display must come from the watch app Image Asset Catalog or as files within the app folder itself.

Within the Watchkit App Image Asset Catalog you must have an AppIcon group, with 8 uniquely sized images for various uses, like the app icon on the Watch. Below are the image sizes you'll need:

  1. 48x48 pixels
  2. 55x55 pixels
  3. 58x58 pixels
  4. 80x80 pixels
  5. 87x87 pixels
  6. 88x88 pixels
  7. 172x172 pixels
  8. 196x196 pixels

With the catalog set up, you'll see that the Watch app in the simulator now shows your app icon, allowing you to turn your watch app on and off, like any other watch app. It's all automatic. Pretty cool.

The Simulator

The first thing you'll notice when building a Watchkit app is that there is no proper Apple Watch simulator. This threw me straight away. The watch is treated as an extension of the display, and as such, runs as an external display within the simulator (via the Hardware >External Displays menu). When you test the watch app, you must make sure that you've selected the correct Scheme (see below).

You can attach the main app process to the debugger to test both at once, but so far I haven't found that to be necessary. Where it gets tricky is in debugging the callback functions. If they fail, NSLog commands won't output to the console, since you're testing the watch app, not the parent app. One strategy for handling this is to return a reply dictionary item with the exception information.

In many respects, this all reminds me of the advent of native apps for the iPhone. Development options were limited, and apps had varying levels of "suck" (remember all the fart sound apps?). But we're going to quickly discover all the great things we can build, and as Apple evolves and opens the platform, it will only get better.

Article last updated on 4/21/2018