Guides and Sample Code

Developer

App Programming Guide for watchOS

On This Page

Sharing Data

Often the Watch app and WatchKit extension both need to access the same file; for example, when programatically setting a custom font, or playing media files. There are three common use cases:

  • Place a separate copy of custom fonts in each bundle at design time. Each process then access its own copy of the font.

  • Place media clips that ship with your app inside your WatchKit extension. Your WatchKit extension is located inside your Watch app bundle, so your Watch app can access any files in the extension’s bundle directory. In your extension code, use the methods of the NSBundle class to locate the files inside your extension’s bundle.

  • Place media files that you download from the network (or transfer from your iOS app) in a shared group container. A shared group container provides common storage for your Watch app and WatchKit extension. In your extension code, create URLs for any media files inside the container, and use them to configure the media interfaces.

Additionally, your WatchKit extension can communicate with its parent iOS app using either the Watch Connectivity framework or app preferences.

The Watch Connectivity framework provides a bidirectional communications channel for sending files and data dictionaries between the WatchKit Extension and the iOS app. The framework also supports sending data in the background so that it is waiting when the other app launches.

Additionally, iOS automatically forwards a read-only copy of your iOS app’s preferences to Apple Watch. Your WatchKit extension can read those preferences using an NSUserDefaults object, but it cannot make changes directly to the defaults database.

If your Watch app needs to change the values stored in the defaults database, use the Watch Connectivity framework to send the values back to your iOS app, and save the values there.

Sharing Files Between a Watch App and WatchKit Extension at Runtime

Use a shared app group to share media files between the Watch app interface and WatchKit extension at runtime. An app group creates a secure container that multiple processes can access. Normally, each process runs in its own sandbox environment, but an app group lets both processes share a common directory.

To set up a shared app group
  1. Open the Capabilities tab of your project in Xcode.

  2. Enable the App Groups capability. This adds an entitlement file (if needed) to the selected target and adds the com.apple.security.application-groups entitlement to that file.

For more information, see Configuring App Groups in App Distribution Guide.

To access the container directory
  1. Use the containerURLForSecurityApplicationGroupIdentifier: method of NSFileManager to retrieve the base URL for the directory.

  2. Use the provided URL to enumerate the directory contents, or create new URLs for files in the directory.

For more information on working with files and directories, see File System Programming Guide.

Communicating with Your Companion iOS App

Use the Watch Connectivity framework to communicate between your WatchKit extension and iOS app. That framework provides bidirectional communications between the two processes and lets you transfer data and files in the foreground or background.

Choosing the Right Communication Option

The Watch Connectivity framework offers several options for sending data between your iOS app and WatchKit extension. Each option is intended for a different usage. Most options perform a one-way transfer of data in the background and are a convenient way to deliver updates. Foreground transfers let your app send a message immediately and wait for a reply. Table 4-1 lists the methods you use for communication and usage guidelines for each.

Table 4-1Communicating with a counterpart app

Methods

Usage

updateApplicationContext:error:

Send small amounts of state information to a counterpart app. The receiving app should use the information to synchronize its behavior or update its interface.

The data you send using this method is considered volatile. Each successive call replaces the dictionary sent by the previous call.

Data is transferred in the background at an appropriate time to minimize power usage. Transfers may happen at any time, including when neither app is running.

This method supports background transfers.

transferUserInfo:

transferCurrentComplicationUserInfo:

Send a dictionary of information in the background. The receiving process need not be running for the data to be transferred. Data is transferred in the background and queued for delivery.

Use the transferCurrentComplicationUserInfo: method to send complication-related data from your iOS app to your Watch app. This method sends a high priority message to your WatchKit extension, waking it up as needed to deliver the data and update the complication’s timeline.

Be aware, however, that your complication has a limited daily budget for updates. Call remainingComplicationUserInfoTransfers to determine how many updates you have remaining. If this method returns 0, then the system transfers data using the transferUserInfo: method instead.

Data is transferred in the background at an appropriate time to minimize power usage. Transfers may happen at any time, including when neither app is running.

These methods support background transfers.

transferFile:metadata:

Transfer files in the background. The receiving app must move the file to a new location if it intends to keep it. Files not moved in the session:didReceiveFile: method are deleted after that method returns.

Data is transferred in the background at an appropriate time to minimize power usage. Transfers may happen at any time, including when neither app is running.

This method supports background transfers.

sendMessage:replyHandler:errorHandler:

sendMessageData:replyHandler:errorHandler:

Send data immediately to a counterpart app. If you do not want a response, you may specify nil for the replyHandler parameter.

The counterpart app must be reachable before calling this method. The iOS app is always considered reachable, and calling this method from your Watch app wakes up the iOS app in the background as needed. The Watch app is considered reachable only while it is installed and running.

Data is transmitted immediately and messages are queued and delivered in the order in which they were sent.

These methods must initiate their transfers in the foreground .

For most types of transfers, you provide an NSDictionary object with the data you want to send. The keys and values of your dictionary must all be property list types, because the data must be serialized and sent wirelessly. (If you need to include types that are not property list types, package them in an NSData object or write them to a file before sending them.) In addition, the dictionaries you send should be compact and contain only the data you need. Keeping your dictionaries small ensures that they are transmitted quickly and do not consume too much power on both devices.

For more information about how to transfer data using the Watch Connectivity framework, see Watch Connectivity Framework Reference.

Guidelines for Communicating Between Apps

Here are some guidelines to consider when adding support for Watch Connectivity to your app:

  • Use Background App Refresh to push new data to your Watch app. If your iOS app wakes up periodically to handle tasks, use some of that time to prepare data and send it to your Watch app using the updateApplicationContext:error: method.

  • Move files synchronously in your delegate method. The system deletes a file transferred to a device after calling the session:didReceiveFile: method of the appropriate delegate object. Deleting files prevents them from taking up space unnecessarily, but it also means that you must explicitly move files to a new location if you want to keep them.

    You must move the files synchronously. Otherwise, the session:didReceiveFile: method may end, and the file may be deleted before your asynchronous code can run.

  • Transfer only the data that you need. All transfers involve sending data wirelessly to the counterpart app. Do not waste power by sending data that you do not need.

  • Use the application context mode for transient data that changes. The updateApplicationContext:error: method is intended as a way to communicate a snapshot of state information between your Watch app and iOS app. Calling the method a second time replaces data from any previous calls. If you want to ensure that all the data is delivered (not just the most recent copy), use the transferUserInfo: method instead.

  • Provide a graceful fallback in the case of errors. Errors can occur if there is insufficient space for the data, if the data is malformed, or if there is a communications error. Check for errors in your handler code and take appropriate actions.

  • Remember that background transfers may not be delivered immediately. Files and contextual data are delivered as quickly as possible, but transfers are not instantaneous. Data files involving large files or large amounts of data also take a commensurately long time to complete.

Managing Your Data

When designing your Watch app, consider whether the following data management scenarios affect your implementation:

  • Data placement. WatchKit extensions must take an active role in managing your data. The container directory for your WatchKit extension has the same basic structure as the container for your iOS app. Place user data and other critical information in the Documents directory. Place files in the Caches directory whenever possible so that they can be deleted by the system when the amount of free disk space is low.

  • Data backups. Apple Watch does not automatically back up the files saved by your WatchKit extension. If your need to back up your Watch app’s data, you must explicitly transfer that data back to your iOS app and save it there.

  • iCloud interactions. Starting with watchOS 3, the WatchKit extension can communicate directly with CloudKit and other iCloud technologies.