With the release of WatchKit, developers are able to create new experiences that extend the functionality of a given iOS app onto the Apple Watch.

There are a few different ways that the user can encounter your app on the Apple Watch:

  • Glances
    • Glances are non-interactable views that take up the full screen. They conform to a set of templates and are used to show information that the user will find most relevant and convenient.
    • Tapping on the glance opens the app.
  • Custom Notifications
    • Taking advantage of custom notification types that were introduced in iOS 8, these apps can also customize how the expanded, or long-look form of a notification will look on the Apple Watch.
  • Watch App
    • This is the Watch App itself. These are not truly native apps yet, as all the code driving the app will run on the iPhone that the Apple Watch is paired with.

Since there is no such thing as a standalone Apple Watch App (for now), one of the hurdles that developers will encounter is how to share information between the Extension and the containing iOS App. The strategies and methods discussed here will work just as well for other types of extensions as well, such as the Today Extensions, or Share Extensions.

Anatomy of a WatchKit App

If you are creating an Apple Watch app today, it’s going to consist of a couple of different parts:

The first is the “Apple Watch App” bundle. This is the bundle that gets copied to the Watch itself and consists primarily of the Storyboard files that make up the App UI, as well as additional resources such as images and fonts. The interface for Glances, notifications and the App reside in the same storyboard file.

The second is the WatchKit Extension Target that is created. This is where your code actually runs. This Extension is bundled as part of the containing iOS app.

  • This extension runs as a different process than your iOS app within iOS. However, sandbox resources can still be shared, using App Groups, and a form of interprocess communication (IPC) can be achieved using Darwin notifications. We’ll talk about how to do this more below.

Apple provides an excellent overview of the architecture and lifecycle here:

WatchKit App Architecture

App Groups

App Groups are a concept that allows apps access to shared data sandbox data containers and allow for forms of interprocess communication. App Groups are added to iOS targets by declaring the capability in the target’s entitlements section. Enabling this capability is necessary in order to allow for all sorts of sharing of sandbox data and other IPC. The group name is a typical reverse DNS string and must start with “group”.

Note: You will need a valid iOS developer membership in order to do this, as app group names must correspond to a valid Identifier on the Apple Developer Provisioning Portal.

Sharing files, core data and otherwise

Once App groups are enabled for each target, (in this case, the Extension target and the iOS app itself), and use a common app group identifier, then you may take advantage of the following API:

NSFileManager -containerURLForSecurityApplicationGroupIdentifier:

This call will return a URL that specifies a sandbox location that all members of the App Group specified by the App Group identifier will be able to write to and read from.

In practice, this could be anything from a simple plist file to SQL database.

Additionally, if your main iOS app is using Core Data, and you need access to that from the extension, you’ll want to create your Persistent Store using this shared App Group URL. You’ll also need to make your Core Data model classes available to the extensions. This can be done using an Embedded Framework.

Sharing Code with an Embedded Framework

It will likely be the case that you want to share some amount of code between your host iOS app and the Extension. This is best accomplished using an embedded framework.

Setting up an embedded framework is explained in the Apple Documentation here:

Embedded Frameworks and App Extensions

Ideally, the embedded framework(s) you create from the source of the containing app will be as small as possible and only contain the bare essentials. In fact, the link above sets some hard and fast rules for what CANNOT be in the embedded framework:

Code you will want to include will be items such as model classes, web services, and perhaps code handling user credentials. None of these items should contain any of the restricted APIs, but it will make for a good refactoring exercise if they do.

This Embedded Framework is what the name suggests — it is a framework that is embedded into the binary of the containing app. Unfortunately, if the containing app still needs to support iOS 7, then you will have to jump through some hoops in order to get an embedded framework running happily. Apple, of course, provides guidance on how to get this working here:

Backwards Compatibility with Embedded Frameworks

Keychain Sharing

Many apps require authenticating against a web service of some sort, and in these cases, most apps will choose to store the user’s credentials in the iOS Keychain — a secure place for usernames and passwords. Access to these credentials is normally restricted to the app that created them but not always.

Keychain Sharing is another capability, like app groups that must be enabled for each participating target’s Info.plist. In this case, that is the Containing App and the extension.

Credentials intended to be shared among an app group need to be created using the kSecAttrAccessGroup, where the corresponding value is a common string of the form “{YourBundleID}.com.example.app.group”.

More resources on enabling Keychain Sharing are here:

Enabling Keychain Sharing

A sample project using the Keychain and showing how to use groups is also available here: Generic Keychain Sample Code.

OpenParentApplication:reply: and Other forms of IPC

A recent addition to the Developer preview is the WKInterfaceController +openParentApplication:reply: api.

This API call allows the app to launch the containing app in the background if necessary. (If your app is already foregrounded or running in the background, the launch is not necessary). The reply object allows for errors to be detected as well as for information to be passed back from the containing app after launch.

This is extremely useful if your app does something like playing audio in the background, and you want to allow the user to initiate playback of that audio from the Watch.

Another form of IPC that can be used is Darwin notifications. These are system level notifications that can be sent across app groups. An in-depth look at Darwin notifications is available here: Darwin Notifications, but they are pretty low level.

Fortunately, an excellent wrapper library around the Darwin notifications system for use with extensions has been released by Mutual Mobile and is called MMWormhole:

General Resources

Developer response has been pretty good. Apple provides excellent design and development resources to make sure you create the best experience possible.

Leave a Reply

Your email address will not be published. Required fields are marked *