AppleWatchProgrammingGuide PDF
AppleWatchProgrammingGuide PDF
Contents
Overview 8
Developing for Apple Watch 9
Apple Watch and Its Paired iPhone 9
The WatchKit App 10
Glance Interfaces 10
Custom Interfaces for Local and Remote Notifications 11
WatchKit Apps 27
UI Essentials 28
Assembling Your Storyboard Scenes 28
Accommodating Different Display Sizes 29
Updating Your Interface at Runtime 31
Setting Your Apps Key Color 31
Internationalizing Your Interface 32
Contents
Interface Navigation 33
Implementing a Page-Based Interface 33
Implementing a Hierarchical Interface 34
Presenting Interface Controllers Modally 35
Interface Objects 36
Creating an Interface Object 36
Configuring Your Interface at Design Time 38
Changing Your Interface at Runtime 39
Responding to User Interactions 40
Hiding Interface Objects 41
Images 46
Specifying Your Image Assets 46
Using Named Images to Improve Performance 46
Caching Images on the Device 47
Tables 48
Configuring Row Controllers 48
Configuring the Tables Contents at Runtime 51
Handling Row Selections 52
Context Menus 53
Designing Your Menu Items 53
Adding a Context Menu to an Interface Controller 54
Handling Taps in a Menu Item 55
Settings 56
Creating Your WatchKit Settings Bundle 56
Enabling Access to Preference Values for Your WatchKit Extension 57
Accessing Settings at Runtime 57
Glances 58
Glance Essentials 59
Contents
Notifications 64
Notification Essentials 65
The Short-Look Interface 66
The Long-Look Interface 67
Adding Action Buttons to Notifications 69
Responding to Taps in Action Buttons 70
UI Essentials 28
Figure 5-1
Figure 5-2
Interface Objects 36
Figure 7-1
Table 7-1
Listing 7-1
Tables 48
Figure 10-1
Listing 10-1
Listing 10-2
Context Menus 53
Figure 11-1
Settings 56
Listing 12-1
Listing 12-2
Glance Essentials 59
Figure 13-1
Notification Essentials 65
Figure 15-1
Figure 15-2
Listing 15-1
A short-look interface 66
A long-look notification interface 68
Registering actions in a containing iOS app (partial implementation) 69
Objective-CSwift
Overview
With Apple Watch, users can now access data in a way that is both distinctly personal and unobtrusive. Without
having to pull an iPhone out of a pocket, users can get important information quickly just by glancing at their
Apple Watch (Figure 1-1).
Figure 1-1
As a developer of third-party apps for Apple Watch, you support these brief interactions by providing only the
most relevant information in the most straightforward way possible.
User interactions are what make the Apple Watch unique. First, you always provide users with a full-app
experience, which they interact with by opening your app from the Home screen. The full interface, with its
multiple screens of content, makes it easy for user to interact with your apps data.
Besides the full-app experience, you can optionally offer users a read-only interface, known as a glance, which
displays timely and relevant information from your app. Finally, you can change the way local and remote
notifications are displayed to your users by providing custom notification interfaces.
Because a WatchKit app extends the behavior of your existing iOS app, the WatchKit app and WatchKit extension
are bundled together and packaged inside your iOS app bundle. During installation of your iOS app, the system
prompts the user to install the WatchKit app when a paired Apple Watch is present.
Glance Interfaces
A glance is a focused interface that you use to display your apps most important information. Glances are
aptly named because they are intended to be looked at quickly by the user. Glances are nonscrolling; the entire
glance interface must fit on a single screen. Glances are read-only and cannot contain buttons, switches, or
other interactive controls. Tapping a glance launches your WatchKit app.
To create a glance, you do not have to create a separate executable. Instead, you create a specialized set of
objects inside your existing WatchKit app and WatchKit extension. In fact, the classes and techniques you use
to implement a glance are the same ones you use to create your WatchKit app.
To get started creating a glance interface, see Glance Essentials (page 59).
10
11
A WatchKit app requires an existing iOS app. In the Xcode project for your iOS app, you add a new WatchKit
app target, which configures the bundles and initial resources for your WatchKit app and WatchKit extension.
Those bundles are then delivered as part of your iOS app on the App Store.
The WatchKit app target provided by Xcode contains everything you need to get started creating your WatchKit
app, glances, and custom notification interfaces. And iOS Simulator provides you with a runtime environment
for testing the appearance and behavior of all of your interfaces.
Note: WatchKit development requires the iOS 8.2 SDK or later. To get the latest SDK, go to developer.apple.com.
2.
Select File > New > Target, and navigate to the Apple Watch section.
3.
4.
If you plan to implement a glance or custom notification interface, select the appropriate checkboxes.
For notification interfaces, it is recommended that you select the Include Notification Scene checkbox,
even if you do not plan on implementing that interface right away. Selecting that checkbox adds an
additional file to your project for debugging your notification interfaces. If you do not select that option,
later you must create the file manually.
5.
Click Finish.
12
Xcode configures the targets for your WatchKit app and WatchKit extension and adds the needed files to your
iOS project. The bundle IDs for both new targets are configured automatically, based on the bundle ID of your
iOS app. The base IDs for all three bundles must match; if you change your iOS apps bundle ID, you must
update the other bundle IDs accordingly.
13
2.
3.
Duplicate your existing WatchKit app scheme, and give the new scheme an appropriate name.
For example, give it a name like Glance - My WatchKit app to indicate that the scheme is specifically
for running and debugging your glance.
4.
14
5.
In the Info tab, select the appropriate executable for the new scheme.
6.
When you create a build scheme for your notification interfaces, specify a JSON file to use as the notification
payload during testing. For more information about notification payloads, see Specifying a Notification Payload
for Testing (page 15).
15
Note: If you selected the Include Notification Scene option when creating your WatchKit app target,
Xcode provides you with an initial PushNotificationPayload.apns file for specifying your test
data. (The file is located in the Supporting Files directory of your WatchKit extension.) You can also
create payload files manually later.
The PushNotificationPayload.apns file contains most of the keys you need to simulate a remote
notification, and you can add more keys as needed. Figure 2-2 shows the default JSON file that comes with
your project.
16
Figure 2-2
Most of the JSON data is packaged into a dictionary and delivered to your code at runtime. Because iOS
Simulator does not have access to your iOS apps registered actions, you may also use payload files to specify
the action buttons to display in your interface. The WatchKit Simulator Actions key contains an array of
dictionaries, each of which represents an action button to add to your interface. Each dictionary contains the
following keys:
17
titleThe value of this key is the title of the action button. This key is required.
identifierThe value of this key is the string to pass to your interface controllers
application:handleActionWithIdentifier:forLocalNotification:completionHandler:
or application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
method. This key is required.
destructiveThe value of this key is the value 1 or 0, where 1 causes the resulting button to be
rendered in a way that indicates it performs a destructive action. The value 0 causes the button to be
rendered normally. This key is optional.
To test your notification interface with the JSON payload, configure the build scheme with the appropriate
payload file. When you select a notification interface executable, Xcode adds a menu for choosing one of your
payload files. You can create different build schemes for different notification payloads, or you can update the
payload file for an existing build scheme before testing.
18
Your WatchKit app and WatchKit extension work in tandem to implement your apps interface. When the user
interacts with your app on Apple Watch, your WatchKit app chooses the appropriate scene from your storyboards
to handle that interaction. For example, if the user views your apps glance, it chooses your glance scene. After
choosing the scene, WatchKit tells the paired iPhone to launch your WatchKit extension and create the objects
needed to manage that scene. When the scene is fully configured, it is displayed on Apple Watch. This transfer
of information between the WatchKit app and WatchKit extension happens transparently behind the scenes.
Figure 3-1
19
WatchKit apps typically contain multiple interface controllers, with each one displaying a different type of
information. Because only one interface controller at a time is displayed onscreen, an app presents new interface
controllers in response to user actions. Apps can present interface controllers modally. The navigation style of
an app also determines how interface controllers are presented. For information on how to present new
interface controllers, see Interface Navigation (page 33).
Note: Glance and custom notification interfaces use specialized interface controllers that are separate
from your apps other interface controllers. For information about implementing a glance, see Glance
Essentials (page 59). For information about the implementing custom notification interfaces, see
Notification Essentials (page 65).
20
create the corresponding interface controller object, which you use to prepare the scene for display to the
user. Figure 3-2 shows the steps for this sequence. Youll learn more about how interface controllers work in
App Essentials (page 28).
Figure 3-2
Use your interface controllers 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. The willActivate method is called shortly before your interface is
displayed onscreen, so you should use that method only to make last-minute changes. For example, you might
also use that method to start animations or start other tasks that should only happen while your interface is
onscreen.
While your interface controller is onscreen, user interactions are handled by your interface controllers custom
action methods. As the user interacts with tables, buttons, switches, sliders, and other controls, WatchKit calls
your action methods so that you can respond. You use those action methods to update your interface or
perform other relevant tasks. To perform tasks at other times, use an NSTimer object to run code at the time
you designate.
21
Note: Glance interfaces do not support action methods. Tapping your apps glance interface always
launches the app.
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 suspends your extension, as shown in Figure 3-3.
Figure 3-3
Method
Tasks to perform
init
awakeWithContext:
This method lets you configure the interface controller using any available
context data. Use it to load data and update labels, images, tables, and other
interface objects in your storyboard scene. The context data is data you
provide to assist in the configuration of the new interface controller. For
example, when pushing a new interface controller in a hierarchical interface,
you specify a context object that contains the next level of data to display.
Providing a context object is recommended but not required.
22
Method
Tasks to perform
willActivate
This method lets you know that your interface will soon be visible to the
user. Use this method only to make small changes to your interface. For
example, you might use this method to update a label based on new data.
The bulk of your interface initialization should still occur in the init and
awakeWithContext: methods.
didDeactivate
Use the didDeactivate method to clean up your interface and put it into
a quiescent state. For example, use this method to invalidate timers and stop
animations.
You cannot set values for any interface objects from this method. From the
time this method is called to the time the willActivate method is called
again, any attempts to set values for interface objects are ignored.
23
To share preferences data between apps, create an NSUserDefaults object using the identifier of the shared
group. The initWithSuiteName: method of NSUserDefaults creates an object that allows access to the
shared user defaults data. Both processes can access this data and write changes to it.
24
WatchKit extensions have access to the same technologies found in iOS apps but because they are extensions,
the use of some technologies may be restricted and the use of others is not recommended. Here are some
guidelines for deciding when to use a particular technology:
Avoid using technologies that request user permission, like Core Location. Using the technology from
your WatchKit extension could involve displaying an unexpected prompt on the users iPhone the first
time you make the request. Worse, it could happen at a time when the iPhone is in the users pocket and
not visible.
Do not use background execution modes for a technology. WatchKit extensions run only while the user
interacts with the corresponding WatchKit app and are therefore considered foreground extensions. As a
result, WatchKit extensions cannot execute using the background modes supported by some technologies.
Avoid performing long-running tasks with a technology. A WatchKit extension is suspended soon after
the user stops interacting with the corresponding WatchKit app. Because WatchKit app interactions are
typically brief, the extension might already be suspended by the time the requested data arrives.
The best solution for performing any long-running tasks is to let your iOS app perform the task instead. For
example, instead of starting location services in your WatchKit extension, start it in your iOS app. Your iOS app
can gather the needed data and put it in a shared app group so that your extension can access it later. Use
the openParentApplication:reply: method to initiate tasks and receive a reply, or use a shared group
container to communicate details between your iOS app and WatchKit extension. For information about how
to handle communication between your iOS app and WatchKit extension, see Communicating Directly with
Your Containing iOS App (page 24).
Handoff Support
Apple Watch supports the creation of activities that can be completed on other devices using Handoff. You
can use the updateUserActivity:userInfo:webpageURL: method of WKInterfaceController to
create activities and advertise them to other devices.
With the exception of your apps glance, Apple Watch does not handle activities generated by other devices.
In your glance interface controller, you can use an activity dictionary to specify information that might be
useful to your main app. If the user taps your glance to launch your app, WatchKit delivers that activity dictionary
25
to your apps main interface controller. That interface controller can use the contents of the dictionary to
update the apps UI accordingly. For more information about how to pass information from your glance to
your app, see Customizing App Launch From Your Glance (page 62).
The Now Playing glance automatically displays any Now Playing information provided by the currently playing
iOS app. An iOS app provides this information using the MPNowPlayingInfoCenter object. As your app
plays its content, it should update the values of the nowPlayingInfo dictionary. Apple Watch automatically
retrieves this information and displays it. In addition, tapping the track title in the Now Playing glance launches
the apps WatchKit app if one is available.
For information on how to implement support for remote control events and now playing information in your
iOS app, see Remote Control Events.
26
WatchKit Apps
27
UI Essentials
The starting point for implementing your app is to define your storyboard scenes. Each scene defines a portion
of your apps user interface. You can customize scenes for different Apple Watch sizes, and you can configure
different aspects of your interface.
28
UI Essentials
Accommodating Different Display Sizes
Figure 5-1 shows how you can arrange different elements in your storyboard file. The first three elements are
labels, which have different alignments within the interface controllers bounds. Below the labels is a group
object containing two images arranged horizontally. The interface also contains a separator and a button
stacked vertically underneath the group object.
Figure 5-1
When creating your interfaces in Xcode, let objects resize themselves to fit the available space whenever
possible. App interfaces should be able to run both display sizes of Apple Watch. Letting the system resize
objects to fit the available space minimizes the amount of custom code you have to write for each device.
29
UI Essentials
Accommodating Different Display Sizes
To customize an item for a specific device size, use the plus buttons (+) in the Attributes inspector to override
the value of an attribute for a given device. Clicking a plus button adds a new device-specific entry for the
attribute. Changes you make to that version of the attribute affect only the selected device. Figure 5-2 shows
how text scaling is handled differently for Apple Watch 42mm.
Figure 5-2
30
UI Essentials
Updating Your Interface at Runtime
Users should not notice significant differences in your apps interface on different sizes of Apple Watch, so
minimize the customizations you make for different device sizes. Whenever possible, limit interface changes
to layout-related behaviors such as spacing and margins. Although it is possible to remove interface objects
altogether from your interface in different layouts, doing so is not recommended. Try to use the exact same
set of interface objects on all sizes of Apple Watch.
To see customizations applied to different device sizes, use the control at the bottom of the storyboard editor
to toggle between the device sizes. The storyboard editor displays the Any device size by default. Changes
applied in the Any display mode apply to all sizes of Apple Watch. If you change the display mode to a specific
device size, the changes you make while in that mode apply only to the current device.
You cannot add new objects to your interface or change the order of the objects that are already there. Although
you cannot remove objects, you can hide them, which removes them from the layout temporarily. When an
item is hidden, other objects fill in the space previously occupied by the item. To hide an object without filling
in the space, set the items alpha value to 0. For more information about hiding objects in a scene, see Hiding
Interface Objects (page 41).
31
UI Essentials
Internationalizing Your Interface
An apps key color is stored in the Global Tint property of an apps storyboard. To access this property, select
your storyboard and display the File inspector. Select one of several preexisting colors from the pop-up menu,
or use the color picker to specify a custom color.
When used in your WatchKit extension, an NSLocale object returns the locale information configured on the
users Apple Watch. Use that class to get the users preferred languages and other language and locale-related
information.
For more information about internationalizing your app, see Internationalization and Localization Guide .
32
Interface Navigation
For WatchKit apps with more than one screen of content, you must choose a technique for navigating between
those screens. WatchKit apps support two navigation styles, which are mutually exclusive:
Page based. This style is suited for apps with simple data models where the data on each page is not
closely related to the data on any other page. A page-based interface contains two or more independent
interface controllers, only one of which is displayed at any given time. At runtime, the user navigates
between interface controllers by swiping left or right on the screen. A dot indicator control at the bottom
of the screen indicates the users current position among the pages.
Hierarchical. This style is suited for apps with more complex data models or apps whose data is more
hierarchical. A hierarchical interface always starts with a single root interface controller. In that interface
controller, you provide controls that, when tapped, push new interface controllers onto the screen.
Although you cannot mix page-based and hierarchical navigation styles in your app, you can supplement these
base navigation styles with modal presentations. Modal presentations are a way to interrupt the current user
workflow to request input or display information. You can present interface controllers modally from both
page-based and hierarchical apps. The modal presentation itself can consist of a single screen or multiple
screens arranged in a page-based layout.
In your storyboard, add interface controllers for each of the pages in your interface.
2.
Control-click your apps main interface controller, and drag the segue line to another interface controller
scene.
The second interface controller should highlight, indicating that a segue is possible.
3.
4.
33
Interface Navigation
Implementing a Hierarchical Interface
5.
Using the same technique, create segues from each interface controller to the next.
The order in which you create your segues defines the order of the pages in your interface.
The segues you create in your storyboard file define the page-based interface that is loaded when your app
is launched. You can change the set of pages you want to display by calling the
reloadRootControllersWithNames:contexts: method early in the launch cycle. For example, you might
call that method in the init method of your main interface controller to force WatchKit to load a different
set of pages.
All interface controllers in a page-based interface are created and initialized before the interface is displayed,
but only one interface controller at a time is displayed. Normally, WatchKit displays the first interface controller
in the sequence initially. To change the initially displayed interface controller, call the becomeCurrentPage
method from its init or awakeWithContext: method.
As the user navigates from page to page, WatchKit activates and deactivates interface controllers accordingly.
During a transition, the currently visible interface controllers didDeactivate method is called, followed by
a call to the willActivate method of the interface controller that is about to be displayed. Use the
willActivate method to update the contents of your interface controller to reflect any last minute changes.
34
Interface Navigation
Presenting Interface Controllers Modally
When creating a modal segue, connect the segue to the interface controller you want to display. When using
a segue to present multiple interface controllers, first use the next-page segue to connect the modal interface
controllers together, in the same way that you connect them together for a page-based interface. Your modal
segue should connect to the first interface controller in the group. If you connect to an interface controller in
the middle of the group, the interface controllers that precede it in the group are not displayed.
The top-left corner of a modal interface displays the interface controllers title string. When the user taps that
string, WatchKit dismisses the modal interface. Set the title string to reflect the meaning of dismissing the
modal interface. For example, when displaying information, you might set the string to Done or Close. If you
do not specify a title for your interface controller, WatchKit displays the string Cancel by default.
35
Interface Objects
Objective-CSwift
You manipulate your WatchKit apps UI using interface objects. An interface object is an instance of the
WKInterfaceObject class, or more specifically one of its subclasses. The WatchKit framework provides
interface objects for most (but not all) of the visual elements you can add to your UI in your storyboard files.
Interface objects are not views. They are proxy objects that communicate wirelessly with the actual views used
to implement your UI on Apple Watch.
Note: Communication between an interface object and the corresponding view on Apple Watch is
one way, with information flowing from your WatchKit extension to Apple Watch. In other words,
you set values on an interface object but you cannot get the current values of its attributes. There
are performance and latency implications for retrieving data from Apple Watch, making changes,
and writing those changes back to the device. So it is recommended that you maintain information
about the configuration of your interface in your WatchKit extension.
class MySwiftInterfaceController {
@IBOutlet weak var label: WKInterfaceLabel!
}
36
Interface Objects
Creating an Interface Object
Connect each declared property in your interface controller to the corresponding item in your storyboard. A
quick way to create property declarations and connect them to an item is to use the assistant editor in Xcode.
After displaying the assistant editor, control-drag from an element in your storyboard to the interface definition
of your class to create an outlet. (In Swift, drag to your class definition.) After prompting you for the outlets
name, Xcode creates the property declaration in your class and connects it to the storyboard element.
37
Interface Objects
Configuring Your Interface at Design Time
For more information about how to configure interface objects, see the classes for your interface objects in
WatchKit Framework Reference .
38
Interface Objects
Changing Your Interface at Runtime
- (instancetype)init {
// Always call super first.
self = [super init];
if (self){
// It is now safe to access interface objects.
[self.label setText:@Hello New World];
}
return self;
}
override init {
// Initialize variables here.
super.init
To improve performance and battery life, the WatchKit framework optimizes any attempts to set values on
your apps interface objects. Whenever you set the values for one or more interface objects in the same run
loop iteration, the new values are coalesced and transmitted to Apple Watch in a single batch to improve
39
Interface Objects
Responding to User Interactions
efficiency. Coalescing changes means that only that last change to a given property of an object is sent to the
device. More importantly, setting the same property to the same value generates a log message to help you
track down the duplicate calls.
For information about the methods you use to configure your interface objects, see the corresponding class
descriptions in WatchKit Framework Reference .
Object
Objective-C
Swift
Button
- (IBAction)buttonAction
@IBAction func
buttonAction()
Switch
- (IBAction)switchAction:(BOOL)on
@IBAction func
switchAction(value: Bool)
Slider
(IBAction)sliderAction:(float)value
@IBAction func
sliderAction(value: Float)
Menu Item
- (IBAction)menuItemAction
@IBAction func
menuItemAction()
Interfaces can use segues or the table:didSelectRowAtIndex: method of the interface controller to
respond to taps in a table row. Use a segue to display another interface controller. Prior to performing the
segue, WatchKit calls the contextForSegueWithIdentifier:inTable:rowIndex: or
contextsForSegueWithIdentifier:inTable:rowIndex: method of your interface controller so that
you can specify the context objects to use when displaying the interface controller. If you use the
table:didSelectRowAtIndex: method instead of a segue, you can perform whatever actions are appropriate
for tapping on the row.
After your interface controller is initialized and onscreen, WatchKit calls the methods of your interface controller
only when the user interacts with your interface. If you want to update your user interface without user
intervention, you must configure an NSTimer object and use its handler to perform any needed tasks.
40
Interface Objects
Hiding Interface Objects
For tasks that might take more than a second or two, consider handing those tasks off to your parent iOS app
for execution. Long-running tasks such as network access and location monitoring are best handled by the
parent app, which can then communicate that information back to your WatchKit extension through a shared
group container directory. For information about handing off tasks to your parent app, see Communicating
Directly with Your Containing iOS App (page 24).
41
To display text in your WatchKit app, use label objects. Labels support formatted text that can be changed
programmatically at runtime.
To add a label to your interface controller, drag it into the corresponding storyboard scene. From there, configure
the labels initial text string and format. WatchKit supports both standard fonts and custom fonts that you
specify yourself. Figure 8-1 shows the standard font styles available for you to use.
Figure 8-1
For more information about configuring label objects in Xcode and in your code, see WKInterfaceLabel Class
Reference .
Using Fonts
WatchKit apps, glance interfaces, and notification interfaces use the system font for displaying text. The interface
controllers in your main app may also use custom fonts to display text. (Glance and notification interfaces
cannot use custom fonts.) To use custom fonts, you must install those fonts by doing the following:
Include the custom font file in both your WatchKit app and your WatchKit extension bundle.
42
Add the UIAppFonts key to your WatchKit apps Info.plist file, and use it to specify the fonts you
added to the bundle. For more information about this key, see Information Property List Key Reference .
Important: You must include the font in your WatchKit extension so that you can create strings with that
font at runtime. The font information is included with the attributed string when it is sent to Apple Watch,
and the copy of the font in your WatchKit app bundle is then used to render the string there.
To format text using a custom font, create an attributed string using the font information and then use that
string to set the text of your label, as shown in Listing 8-1. The font name and size are encoded with the
attributed string, which is then used to update the label on the users Apple Watch. If the font name you specify
is neither the system font nor one of your custom installed fonts, WatchKit uses the system font.
Listing 8-1
43
currently active interface controller. When presenting the interface, you specify the types of input you support
and a block to execute with the results. You also specify an initial set of phrases to display in the interface. The
user can select from the available phrases or use the controls to input a different phrase.
Listing 8-2 shows how to configure the text input controller and process the results. After you specify the initial
phrases and input modes, the controller runs asynchronously. When the user selects an item or cancels input,
your block is executed on the main thread. Use that block to retrieve the text or emoji image that was selected
by the user and update your app.
Listing 8-2
44
Use Xcodes base internationalization support for storyboards and xib files. Base internationalization lets
you have only one set of storyboard files, which supports all localizations. The localized strings for the
storyboard are stored separately in language-specific strings files.
Use the NSNumberFormatter class to format numerical values using the users region and locale settings.
Use the NSDateFormatter class to format dates using the users region and locale settings.
When internationalizing your app, your main concern should be arranging your interface so that labels (and
other controls with text) have room to expand. For example, rather than using a group to arrange three buttons
horizontally, arrange the buttons vertically to give each one room to grow horizontally when its text becomes
longer.
For more information about internationalizing your app, see Internationalization and Localization Guide .
45
Images
WatchKit provides the following ways to incorporate images into your content:
The WKInterfaceImage class displays a single image or a sequence of images as standalone content.
Always create images that are sized appropriately for your interface. For images whose size you cannot
control, use the setWidth: and setHeight: methods of the interface object to ensure that the image
is displayed at a proper size.
Use image assets to manage your images. Image assets let you specify provide different versions of an
image for each device size.
46
Images
Caching Images on the Device
Any time you create a UIImage object in your extension, that image object exists on the users iPhone and
must be sent to Apple Watch before it can be used. Even using the imageNamed: method of UIImage loads
the image from your WatchKit extensions bundle, not from your WatchKit app. If you try to assign that image
to one of your interface objects, the image data is transferred wirelessly to Apple Watch.
For WKInterfaceImage objects, call the setImageNamed: method, specifying the name of the cached
image.
47
Tables
SwiftObjective-C
Use tables to display lists of data whose content changes dynamically. WatchKit supports single-column tables
using the WKInterfaceTable class. Displaying data in a table requires defining the layout for your data in
advance and writing code to fill the table with the actual data at runtime. Specifically, you need to do the
following in your Xcode project:
Add a table object to your interface controller scene. Create an outlet for that table in your interface
controller.
Configure one or more row controllers for your table as described in Configuring Row Types (page
48).
In your code:
Define a row controller class for each row controller you defined; see Configuring Row Types (page
48).
At initialization time, add rows to the table as described in Configuring the Tables Contents at
Runtime (page 51).
Respond to interactions with table rows as described in Handling Row Selections (page 52).
For each table, you can define multiple row controller types, each with a different appearance. At runtime, you
specify which row types you need and in what order they should be arranged in the table. For additional
information about how to configure a table, see WKInterfaceTable Class Reference .
2.
48
Tables
Configuring Row Controllers
3.
Use the Rows attribute to change the number of available row controllers.
Each row controller contains a single group element initially. To that group, you add the labels, images, and
other objects that you want to include in the row. The content for labels and images in a row controller is
irrelevant at design time. At runtime, you replace the content of each item when you configure the row.
Each row controller is backed by a custom class that you use to access the rows contents. Most row controller
classes contain only properties for accessing the rows interface objectsfew contain any code. However, if
you add buttons or other interactive controls to a row, your row class can also include action methods for
responding to user interactions with those controls.
2.
3.
Add declared properties for each label, image, or control that you plan to access at runtime. Use the
following format for declared properties, changing the class to match the class of the corresponding
interface object:
@property (weak, nonatomic) IBOutlet WKInterfaceLabel* label; //
Objective-C
Listing 10-1 shows a sample row controller class definition. In this example, the class contains outlets for an
image and a label.
Listing 10-1 A sample class for managing a row
@interface MainRowType : NSObject
@property (weak, nonatomic) IBOutlet WKInterfaceLabel* rowDescription;
@property (weak, nonatomic) IBOutlet WKInterfaceImage* rowIcon;
@end
49
Tables
Configuring Row Controllers
You finish the configuration of your row controller in your storyboard file by setting its class and connecting
up any outlets. You must also assign an identifier string to the row. You use that string at runtime when creating
the row.
2.
Set the row controllers Identifier attribute to a unique value for the table.
You use the identifier later on when creating the tables rows. The value must be unique among the
row types of the table but the actual value is at your discretion. Set this value in the Attributes inspector.
3.
Set the class of the row controller to your custom class. Set this value in the Identity inspector.
4.
Connect the labels and other elements to the outlets in your custom class.
Connecting items in your storyboard file to your outlets binds the two together. WatchKit needs this
information to create a rows interface objects at runtime.
Figure 10-1 shows an example of a row controller configured with the identifier mainRowType and the class
MainRowType, which is defined in Listing 10-1 (page 49). The rowDescription and rowIcon outlets in that
class are connected to the image and label objects in the row.
Figure 10-1
50
Tables
Configuring the Tables Contents at Runtime
Determine the number and type of rows you want, based on the data you want to display.
2.
3.
4.
The setRowTypes: and setNumberOfRows:withRowType: methods instantiate the classes associated with
the corresponding row controllers. Immediately after calling one of those methods, you retrieve the newly
created row controller objects and use them to configure the rows. Listing 10-2 uses some provided data to
configure a label and image for a row. The data is provided by an array of custom data objects of type
MyDataObject. (The MyDataObject class exposes a string and image as properties and its implementation
is not shown here.) The rows themselves are instances of the custom MainRowType class, which is defined in
Listing 10-1 (page 49).
Listing 10-2 Creating and configuring the rows of a table
- (void)configureTableWithData:(NSArray*)dataObjects {
[self.table setNumberOfRows:[dataObjects count] withRowType:@"mainRowType"];
for (NSInteger i = 0; i < self.table.numberOfRows; i++) {
MainRowType* theRow = [self.table rowControllerAtIndex:i];
MyDataObject* dataObj = [dataObjects objectAtIndex:i];
[theRow.rowDescription setText:dataObj.text];
[theRow.rowIcon setImage:dataObj.image];
}
}
51
Tables
Handling Row Selections
When configuring tables, you can improve performance by limiting the number of rows you create initially.
But because table rows must all be created up front, creating large numbers of rows can adversely affect the
performance of your app. The precise number of rows depends on the complexity of your data and how long
it takes you to create each one, but consider keeping the total number of rows to 20 or fewer. For tables that
require more rows, consider loading only a subset of rows initially and then provide the user with controls to
load more rows. An even better solution is to display only the most important subset of rows. For example,
you might use location data to limit the number of rows to those that are most relevant to the users current
location.
52
Context Menus
Objective-CSwift
The Retina display with Force Touch found on Apple Watch provides a new way to interact with content.
Instead of just tapping items on the screen, pressing the screen with a small amount of force activates the
context menu (if any) associated with the current interface controller. Context menus are optional. You use
them to display actions related to the current screen. WatchKit displays the menu over your content, as shown
in Figure 11-1.
Figure 11-1
A context menu can display up to four actions. Each action is represented by a title string and an image. Tapping
an actions image dismisses the menu and executes the action method associated with that menu item. Tapping
anywhere else dismisses the menu without any further action.
53
Context Menus
Adding a Context Menu to an Interface Controller
The template images you provide should be smaller than the circular background on which they sit. For more
information about the size of menu images and guidelines for how to create them, see Apple Watch Human
Interface Guidelines .
2.
Drag a menu object from the library and add it to your interface controller scene.
The initial menu contains a single menu item.
3.
4.
For each item, use the Attributes inspector to specify the menus title and image. Both are required.
5.
Connect each menu item to an action method in your interface controller class.
Menu action methods have the following format:
- (IBAction)doMenuItemAction
6.
54
Context Menus
Handling Taps in a Menu Item
If any state information is required to perform the action, it is your responsibility to store and maintain that
information in your interface controller object. For example, if an action relies on the currently selected row
of a table, your interface controller must include a variable to track the most recently selected row. And, if you
want to request more information from the user after tapping a menu action, your action method must present
a modal interface controller.
55
Settings
Preferences and settings are data values that change infrequently and that you use to configure your apps
behavior or appearance. If your WatchKit app uses preferences for its configuration, you can add a
WatchKitspecific settings bundle to your project to present those settings to the user. This settings bundle
lives inside your containing iOS app, and the settings themselves are displayed by the Apple Watch app on
the users iPhone.
A WatchKit settings bundle works in the same way that an iOS settings bundle works. The settings bundle
defines the controls you want displayed by the system and the name of the preference that each control
modifies. The Apple Watch app on the users iPhone takes your settings bundle information and uses it to
display the actual controls to the user. When the user changes the value of a control, the system updates the
underlying preference value.
For general information about how settings bundles work, see Preferences and Settings Programming Guide .
2.
In the Apple Watch section, select WatchKit Settings Bundle and click Next.
3.
Create the settings bundle with the name Settings-Watch.bundle and add it to your iOS app target.
Naming the bundle Settings-Watch.bundle is required to distinguish it from your iOS apps settings
bundle (if any).
The initial contents of the WatchKit settings bundle are the same as for an iOS apps settings bundle and are
shown in Listing 12-1.
Listing 12-1 Contents of a WatchKit settings bundle
Settings-Watch.bundle/
Root.plist
en.lproj/
Root.strings
56
Settings
Enabling Access to Preference Values for Your WatchKit Extension
For information on how to configure the contents of your settings bundle, see Implementing an iOS Settings
Bundle. For detailed information about the keys you can include in a Settings bundle, see Settings Application
Schema Reference .
For more information on how to access preferences values, see NSUserDefaults Class Reference .
57
Glances
58
Glance Essentials
A glance is a supplemental way for the user to view important information from your app. Not all apps need
a glance. A glance provides immediately relevant information in a timely manner. For example, the glance for
a calendar app might show information about the users next meeting, whereas the glance for an airline app
might display gate information for an upcoming flight. Figure 13-1 shows the glance for the Lister sample app,
which displays the number of completed items and the number of remaining items on the users to-do list.
Figure 13-1
Glances are delivered as part of your WatchKit app and WatchKit extension. Your glances interface resides in
your WatchKit apps existing storyboard file, and that interface is managed by a custom
WKInterfaceController object. However, the only job of your glance interface controller is to set the
contents of the glance. Glances do not support interactivitytapping on a glance automatically launches your
WatchKit app.
59
Glance Essentials
Glance Interface Guidelines
For information about the life cycle of interface controllers, see WatchKit Extension Life Cycle (page 20).
Design your glance to convey information quickly. Do not display a wall of text. Make appropriate use
of graphics, colors, and animation to convey information.
Focus on the most important data. A glance is not a replacement for your WatchKit app. Just as your
WatchKit app is a trimmed down version of its containing iOS app, a glance is a trimmed down version of
your WatchKit app.
Do not include interactive controls in your glance interface. Interactive controls include buttons, switches,
sliders, and menus.
Avoid tables and maps in your glance interface. Although they are not prohibited, the limited space
makes tables and maps less useful.
Be timely with the information you display. Use all available resources, including time and location to
provide information that matters to the user. And remember to update your glance to account for changes
that occur between the time your interface controller is initialized and the time it is displayed to the user.
Use the system font for all text. To use custom fonts in your glance, you must render that text into an
image and display the image.
Because an app has only one glance interface controller, that one controller must be able to display the data
you want.
60
When adding a WatchKit app target to your Xcode project, you can specify whether you want a glance interface.
You can also add a glance to your project later if you forget to add one initially. A glance interface controller
has a slightly different appearance in your apps storyboard. Specifically, it has a glance entry point object
attached to it, and it has a default layout, as shown in Figure 14-1.
Figure 14-1
To configure the contents of your glance at runtime, you use a custom WKInterfaceController subclass.
You implement this subclass in the same way that you implement other interface controller classes in your
WatchKit app.
61
2.
3.
Select the glance interface controller in your storyboard and open the Identity inspector.
4.
Set the class of your glance interface controller to the class you created in Step 1.
WatchKit apps may have only one glance interface. Do not add more than one glance interface controller to
your apps storyboard.
Use the init and awakeWithContext: methods to initialize your glance interface and to set the initial
values for its labels and images.
Use the willActivate to update the glance interface as needed before it is displayed onscreen.
To update the content of a glance after it is onscreen, use an NSTimer object to perform periodic updates.
You do not need to update WKInterfaceDate and WKInterfaceTimer objects, which automatically update
themselves.
62
Implement the handleUserActivity: method. Use the provided userInfo dictionary to configure
your UI appropriately.
Calling the updateUserActivity:userInfo:webpageURL: method tells WatchKit to call the main interface
controllers handleUserActivity: method at launch time. In your implementation of the
handleUserActivity: method, use the provided contextual data to configure your UI appropriately. For
example, an app with a page-based interface might use the provided data to select which page to display
initially.
63
Notifications
64
Notification Essentials
Apple Watch takes full advantage of the existing interactive notification support on iOS. If your iOS app supports
notifications, Apple Watch displays those notifications at appropriate times. When one of your apps local or
remote notifications arrives on the users iPhone, iOS decides whether to display that notification on the iPhone
or on the Apple Watch. For notifications sent to Apple Watch, the system lets the the user know subtly that a
notification is available. If the user chooses to view the notification, the system displays an abbreviated version
of the notification first, followed by a more detailed version. The user can dismiss the detailed notification,
launch your WatchKit app, or act on the notification by tapping an available action button.
Apps are not required to do anything to support notifications. The system provides a default notification
interface that displays the alert message from the notification. However, apps can customize the notification
interface and include custom graphics, content, and branding.
65
Notification Essentials
The Short-Look Interface
Note: Apple Watch displays local and remote notifications only if the containing iOS supports them.
For information about how to support local and remote notifications in your iOS app, see Local and
Remote Notification Programming Guide .
A short-look interface
The title string used in the short look provides a brief indication of the intent of the notification. For local
notifications, you specify this string using the alertTitle property of the UILocalNotification object.
For remote notifications, add the title key to the alert dictionary inside the payload. For more information
about adding a title string to your notifications, see Local and Remote Notification Programming Guide .
66
Notification Essentials
The Long-Look Interface
The sash is an overlay that contains the app icon and app name. The sash color is configurable.
The content area contains the detailed information about the incoming notification. For information on
how to customize the content in this area, see Custom Notification Interfaces (page 71).
The bottom area contains a Dismiss button and any action buttons registered by the containing iOS app.
67
Notification Essentials
The Long-Look Interface
Figure 15-2 shows an example of a long-look notification containing several action buttons.
Figure 15-2
Tapping the app icon launches your WatchKit app. Tapping one of the app-defined action buttons delivers
the selected action to either your iOS app or your WatchKit app. Foreground actions are delivered to your
WatchKit app and extension, and background actions are delivered to your iOS app. Tapping the Dismiss button
closes the notification interface without any further actions. Tapping anywhere else does nothing.
For information about how to provide a custom long-look interface for your app, see Custom Notification
Interfaces (page 71).
68
Notification Essentials
Adding Action Buttons to Notifications
categories.addObject(inviteCategory)
69
Notification Essentials
Responding to Taps in Action Buttons
// Configure other actions and categories and add them to the set...
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
}
For information about how to configure categories and actions in your iOS app, see Local and Remote Notification
Programming Guide .
Foreground actions launch your WatchKit app and deliver the ID of the tapped button to the
handleActionWithIdentifier:forRemoteNotification: or
handleActionWithIdentifier:forLocalNotification: method of your main interface controller.
Background actions launch the containing iOS app in the background so that it can process the action.
Information about the selected action is delivered to the
application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
or application:handleActionWithIdentifier:forLocalNotification:completionHandler:
method of the app delegate.
For foreground actions, it is important to note that your WKUserNotificationInterfaceController
subclass does not process the action. Selecting a foreground action launches your app and loads the interface
controller for your apps main entry point. It is this initial interface controller that is responsible for processing
any actions. That interface controller must implement the
handleActionWithIdentifier:forRemoteNotification: and
handleActionWithIdentifier:forLocalNotification: methods (as appropriate) to process actions.
70
The custom long-look notification interface consists of two separate interfaces: one static and one dynamic.
The static interface is required and is a simple way to display the notifications alert message and any static
images and text that you configure at design time. The dynamic interface is optional and gives you a way to
customize the display of your notifications content.
When you add a new notification interface controller to your storyboard file, Xcode creates only the static
interface initially. You can add a dynamic interface by enabling the Has Dynamic Interface property of the
notification category object in your storyboard. (Add a dynamic interface only when you require customizations
that go beyond what is possible with the static interface.) Figure 16-1 shows both the unmodified static and
dynamic interface scenes from a storyboard file. The static and dynamic scenes are associated with the same
notification type, which you configure using the notification category object attached to the static scene.
Figure 16-1
When a notification of the correct type arrives, WatchKit chooses whether to display your static or dynamic
interface based on several factors. WatchKit automatically displays the static interface when a dynamic interface
is not available, there is not enough power to warrant displaying the dynamic interface, or you explicitly tell
WatchKit not to display the dynamic interface. In all other cases, WatchKit displays your dynamic interface.
After making the choice, WatchKit loads the appropriate storyboard resources and prepares the interface as
71
shown in Figure 16-2. The loading process for the dynamic interface is mostly the same as for your apps other
interface controllers, with the exception of processing the notification payload, which is specific to notification
interface controllers.
Figure 16-2
2.
Enable the Has Dynamic Interface attribute of the notification category. This step adds the dynamic
scene to your storyboard file.
3.
Set the class of your dynamic notification interface controller to the class you created in Step 1.
72
Apps may have multiple notification interfaces, which you differentiate using categories. In your storyboard
file, use the Notification Category object to specify the category name associated with each scene. WatchKit
uses the category value to determine which scene to load at runtime. If an incoming notification does not
have a category, WatchKit loads the scene whose category name is set to default.
When generating remote notifications, your server specifies the notification type by including the category
key in the aps dictionary of the payload. For local notifications, you specify this value in the category property
of the UILocalNotification object.
73
Note: The category string also defines which action buttons (if any) are appended to the end of
your notification interface. For more information on supporting custom actions, see Adding Action
Buttons to Notifications (page 69).
The interface must not include controls, tables, maps, or other interactive elements.
The interfaces notificationAlertLabel outlet must be connected to a label. The labels contents are
set to the notifications alert message. The text for all other labels does not change.
74
Figure 16-4 shows the configuration of the static and dynamic scenes for a custom notification interface in a
calendar app. The notification arrow points to the static scene, which contains a custom icon and two labels.
In the static interface, the label containing the string <message> is the one associated with the
notificationAlertLabel outlet and therefore receives the notifications alert message at runtime.
Figure 16-4
75
Use labels, images, groups, and separators for most of your interface.
76
- (void)didReceiveRemoteNotification:(NSDictionary *)remoteNotification
withCompletion:(void(^)(WKUserNotificationInterfaceType interface)) completionHandler
{
// Get the aps dictionary from the payload.
NSDictionary* apsDict = [remoteNotification objectForKey:apsKeyString];
// Extract the date and time from the custom section of the payload.
// The date/time information is stored as the number of seconds since 1970.
77
// Call a custom method to get the localized date format string for the user.
// The default date format string is "EEE, MMM d".
dateFormatter.dateFormat = [self dateFormatForCurrentUser];
NSString *formattedDateString = [dateFormatter stringFromDate:inviteDate];
// Call a custom method to get the localized time format string for the user.
// The default time format string is "h:mm a".
dateFormatter.dateFormat = [self timeFormatForCurrentUser];
NSString *formattedTimeString = [dateFormatter stringFromDate:inviteDate];
78
When calling the completion handler block, if you want WatchKit to display your static interface instead, specify
the WKUserNotificationInterfaceTypeDefault constant.
Note: Notification interfaces support only the use of the system font for labels and other text. If you
need to display text in a custom font, render that text into an image and display the image.
79
Date
Notes
2015-03-09
80
Apple Inc.
Copyright 2015 Apple Inc.
All rights reserved.
No part of this publication may be reproduced,
stored in a retrieval system, or transmitted, in any
form or by any means, mechanical, electronic,
photocopying, recording, or otherwise, without
prior written permission of Apple Inc., with the
following exceptions: Any person is hereby
authorized to store documentation on a single
computer or device for personal use only and to
print copies of documentation for personal use
provided that the documentation contains
Apples copyright notice.
No licenses, express or implied, are granted with
respect to any of the technology described in this
document. Apple retains all intellectual property
rights associated with the technology described
in this document. This document is intended to
assist application developers to develop
applications only for Apple-branded products.
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
408-996-1010
Apple, the Apple logo, Cocoa, Cocoa Touch,
iPhone, Objective-C, OS X, and Xcode are
trademarks of Apple Inc., registered in the U.S.
and other countries.
Retina is a trademark of Apple Inc.
App Store is a service mark of Apple Inc.
IOS is a trademark or registered trademark of
Cisco in the U.S. and other countries and is used
under license.
APPLE MAKES NO WARRANTY OR REPRESENTATION,
EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS
DOCUMENT, ITS QUALITY, ACCURACY,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR
PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED
AS IS, AND YOU, THE READER, ARE ASSUMING THE
ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES RESULTING FROM ANY DEFECT, ERROR OR
INACCURACY IN THIS DOCUMENT, even if advised of
the possibility of such damages.
Some jurisdictions do not allow the exclusion of
implied warranties or liability, so the above exclusion
may not apply to you.