Tải bản đầy đủ
Chapter 16. Building a watchOS App

Chapter 16. Building a watchOS App

Tải bản đầy đủ

We’ll begin working with watchOS by first discussing how to design for it—from both
a visual and a software standpoint. We’ll then build out a very simple app, making use
of the various features of watchOS, including glances and communicating with iOS.
If you want to learn more about building apps for the Apple Watch,
we recommend the book Swift Development for the Apple Watch
(O’Reilly), by some of the same authors who wrote this book
(hello!). Apple’s documentation is also a good reference.

Designing for the Watch
Before we start looking at building the Notes application for the Apple Watch, let’s
take a closer look at the Apple Watch itself (see Figure 16-1).
Just by looking at the device, we can immediately see a number of constraints that are
placed upon all software:
• The screen is extremely small. This limits both the amount of content that can be
displayed at once, and also the area in which the user can interact with that con‐
tent.
• Because the screen is small, touching the screen means covering up a large per‐
centage of the visible content. The Digital Crown, on the side of the device, is
therefore used to scroll the screen up and down while still keeping everything
visible.
• The device is strapped to the wrist. Because we can’t move our lower arms with
the same precision as our fingers, the device will be moving around underneath
the user’s fingers. At the same time, the user might be doing some other activity,
or holding something, further complicating how the device is moving. Compare
this to the phone or tablet, in which users have a lot of control in the off-hand
that holds the device.

434

|

Chapter 16: Building a watchOS App

Figure 16-1. The Apple Watch
In addition to these physical constraints, there are a number of technical constraints
imposed on your apps. The watch is a very low-powered device and relies on commu‐

Designing for the Watch

|

435

nication with an iPhone to access a number of resources. This means that the archi‐
tecture of the watchOS app is distinct to the Apple Watch.
There are three components at play when working with a watchOS app: the container
iOS app, the WatchKit app, and the WatchKit extension:
• The WatchKit app contains the resources (interface, UI, etc.) used by the
watchOS application.
• The WatchKit extension contains the code; both are installed on the watch.
• Both the WatchKit app and the WatchKit extension are embedded in an iOS
application, which is distributed through the App Store. When the user down‐
loads the app from the App Store, the app and extension are transferred to the
user’s Apple Watch.

Designing Our watchOS App
The watchOS app for Notes needs to be very careful in terms of how it’s designed. We
can’t replicate the entire feature set of the iOS app, and nor should we: users are not
going to want to access every single thing that they can do on their phone. Instead,
we need to focus on the most important and most frequently accessed features.
In our opinion, there are precisely two things that the user will want to do:
• Look at a note
• Make a new note
We’ll therefore gear the entire design around these two features. Just as with the Mac
and iOS apps, we created wireframes as part of our thinking about how the watchOS
app should work.
In order to access notes, the user needs a way to see the list of available notes. To
enable this, we need a screen that presents a list of buttons that, when tapped, displays
the note (see Figure 16-2).

436

|

Chapter 16: Building a watchOS App

Figure 16-2. The note list on the watch
Displaying the note itself is easy; we just need to display a bunch of text (see
Figure 16-3). We’re specifically excluding attachments from the Apple Watch applica‐
tion, because it’s our opinion that the user will care more about the note’s text rather
than the things attached to it.

Designing Our watchOS App

|

437

Figure 16-3. The note content on the watch

Creating the watchOS Extension
The first thing we need to do to create an app for the watch is add a WatchKit app
extension to our project. We do this by adding yet another new target. Let’s get
started.
1. Open the File menu and choose New→Target.
2. In the watchOS section, choose WatchKit App and click Next (Figure 16-4).
You’ll notice that there’s also a template called “WatchKit App for watchOS 1”;
watchOS 1 did not allow apps to actually run on the watch, and instead every‐
thing was done via network to the phone, with the watch handling display only.
watchOS 2 and beyond, which is what we’re using here, actually allows apps to
run on the watch. You shouldn’t ever use the watchOS 1 template at this point.

438

|

Chapter 16: Building a watchOS App

Figure 16-4. Creating the watchOS app
3. Name the application Watch1.
The name “Watch” is only for our internal use. On the Apple
Watch, it will take the name of the container iOS app. Xcode
will make the bundle identifier the same as iOS app’s,
with .Watch appended. This is because Watch apps are embed‐
ded inside iOS app.

4. Ensure that Include Glance Scene is turned on (Figure 16-5). We’ll be adding a
glance, which is a single-screen view of your app that users can access from their
watch face, in “Glances” on page 471.

Creating the watchOS Extension

|

439

Figure 16-5. Configuring the watchOS app target
5. When you click Finish, Xcode will create the target and then ask you if you want
to activate the new scheme. We want to start working on the watchOS app right
away, so click Activate (Figure 16-6).

Figure 16-6. Activating the scheme
Now that the application has been set up, we’ll add the watchOS app’s icons to its asset
catalog. Adding icons to an asset catalog should be very familiar at this point!

440

|

Chapter 16: Building a watchOS App

1. Open the Assets.xcassets file inside the Watch group (not the one in the Watch
Extension group).
The images to use for the icons are provided in the resources
that accompany this book. If you don’t have them already, fol‐
low the instructions in “Resources Used in This Book” on page
ix to get them.

2. Select the AppIcon image set, and drag and drop the images into the slots, as
shown in Figure 16-7. Remember to use the filenames to determine the correct
slot for each image—for example, the slot “Apple Watch Companion Settings
29pt 2x” should use the image Icon-AppleWatch-Companion-Settings@2x.png.

Figure 16-7. Adding the icons for the project
When you’re building a watchOS application, you need to use
the same developer identity for both the iOS app and the
watchOS app. If you only have a single developer account,
you’re fine. If you use more than one, then double-check the
Team setting in the General tab of the Watch and Notes-iOS
project info.

3. In the Scheme Selector at the top left of the Xcode window, set the active scheme
to a simulator plus a watch. Any combination of iPhone and Watch will do.

Creating the watchOS Extension

|

441

If you have an iPhone and an Apple Watch (that is, the real
devices, not just the simulator), you can build and run straight
onto your watch; watches don’t have to leave your wrist for
you to install stuff. Note that testing on the simulator is a lot
easier. If you’re testing on an Apple Watch, you may have to go
to the home screen and tap on the icon to launch it.

4. Press ⌘-R to build and run the app.
Because you’re about to install the app onto a new simulator, the
simulated iPhone on which you’re going to install won’t be signed
in to iCloud. To fix this, once the iPhone appears, sign it into
iCloud by opening the Settings application, selecting iCloud, and
tapping Sign In.

Communicating with the iPhone
By default, the app is blank. Let’s fix that and let the app retrieve the notes from the
phone.
To get access to any data stored on its paired iPhone, you use the WatchConnectivity
framework, which allows you to communicate with the phone by sending messages.
These messages are simply dictionaries containing very small chunks of information,
like strings and numbers.
First, we’ll define the different messages that can be sent back and forth between the
Apple Watch and the iPhone. There are three different types of messages that will be
sent:
List all notes
The watch wants to receive the list of notes. The iPhone should send back an
array of dictionaries; each dictionary will contain the name of the note and its
URL.
Open note
The watch wants to display the content of a note. It will pass the URL of a note;
the iPhone should open it, retrieve its text, and send it back.
Create note
The watch wants to create a note. It will pass the text that the note should con‐
tain; the iPhone will create the note and return the updated list of all notes (that
is, it will have the same reply as “list all notes”).

442

|

Chapter 16: Building a watchOS App

The actual data that’s transferred between the watch and the phone is simply a dictio‐
nary; the contents of this dictionary will depend on what type of message it is, which
is indicated by the value of the “name” entry in the dictionary.
We now need to define the actual messages that will be sent back and forth. Because a
message is just a dictionary, in order to distinguish between the three different types
of messages, the dictionary will need to contain an entry that describes the “name” of
the message. Additionally, each value that can be sent in either direction needs a
name as well so that it can be retrieved from the dictionaries that are sent back and
forth.
The best place to define these is in DocumentCommon.swift, which is the Swift file
that’s currently shared among all of the different targets. We’ll add it to the Watch
extension target, too.
1. Select DocumentCommon.swift and open the File Inspector. Set its Target Mem‐
bership to include the Watch Extension.
Doing this includes the DocumentCommon.swift file in the watchOS application.
2. Next, add the following code to the end of DocumentCommon.swift:
let
let
let
let

WatchMessageTypeKey = "msg"
WatchMessageTypeListAllNotesKey = "list"
WatchMessageTypeLoadNoteKey = "load"
WatchMessageTypeCreateNoteKey = "create"

let
let
let
let

WatchMessageContentNameKey = "name"
WatchMessageContentURLKey = "url"
WatchMessageContentTextKey = "text"
WatchMessageContentListKey = "list"

These strings will be used in the messages that are sent back and forth between
the iPhone and the watch.
In this application, multiple different screens will need to access the iPhone via
WatchConnectivity. Rather than spreading this work over all of the app, it’s better to
centralize it into a single object. To that end, we’ll create a class that handles all
iPhone/watch communication.
1. Open ExtensionDelegate.swift.
2. Import the WatchConnectivity framework by adding it to the list of imports:
import WatchConnectivity

This framework enables the Apple Watch and the iPhone to which it’s tethered to
talk to each other over the network. The practicalities of how this happens are
handled for you: sometimes it might be over Bluetooth, sometimes it might be
over WiFi, and sometimes it’ll be a combination of both. The iPhone to which
Creating the watchOS Extension

|

443

the watch is tethered doesn’t even need to be on the same network for this to
work.
3. Add the following class to the end of the file. Note that it conforms to WCSession
Delegate:
class SessionManager : NSObject, WCSessionDelegate {
}

The WCSessionDelegate protocol defines methods that are called when the
device receives a message. Both the watchOS app and the iOS app will have a
class that implements WCSessionDelegate, since they’ll both need to respond to
messages.
We want this class to be a singleton—that is, a class of which there’s only ever one
instance, and everyone accesses the same instance. We’ve seen this pattern before
—or example, the NSFileManager class’s defaultManager property provides
access to a single, shared instance of the class.
To make a shared instance of this class available, we’ll define a static constant
property that, when then application loads, is initialized to an instance of the
class.
4. Add the following property to SessionManager:
static let sharedSession = SessionManager()

Additionally, when the instance is created, we’ll get in touch with the shared

WCSession and tell it to use this instance as its delegate. Doing this means that

we’ll receive messages from the session.

This won’t happen on the watch, but it will happen on the iPhone, so now’s a
good time to introduce it.
5. Add the following code to SessionManager:
var session : WCSession { return WCSession.defaultSession() }
override init() {
super.init()
session.delegate = self
session.activateSession()
}

When the SessionManager class is created—which happens when the sharedSes
sion variable is created—then the shared WCSession class is told to use the Ses
sionManager as its delegate. This means that the SessionManager will be notified
when a message arrives. We then activate the session, enabling communication
between the watch and the iPhone.

444

|

Chapter 16: Building a watchOS App