WatchKit tutorial: Creating a simple Watch App

Apple Watch will be available on the market in the beginning of 2015, so it’s exactly the right time to start preparing apps for the new iOS device. Apple has already released the new Xcode, which contains WatchKit, so we have a chance to take a closer look on it. This tutorial will cover in details the creation of a simple WatchKit app.

Quick Overview of WatchKit

Apps for Apple Watch are similar to application extensions, because they require the presence of an iPhone app. Thus, Apple doesn’t want developers to write completely new apps for Apple Watch, but rather extend the functionality of existing apps to integrate with watch devices. Watch apps are actually using the technology of app extensions: a watch app itself contains only storyboards and resource files, all the code is sitting in extensions.

When a Watch app is opened, Apple Watch finds an appropriate storyboard scene. After that, Watch OS asks the paired iOS device to start the extension and load needed code based on loaded user interface files. Watch app extension is running as long as the WatchKit app is being used.

There are different types of options that can be utilised by the app developer:

Watch app contains a minimised user interface and features of the main application. The user launches it from the home screen and uses like an ordinary app.

Notification views are used to handle push or local notifications of the application. They have many customisation points. If the main application supports notifications, it doesn’t mean that the Watch app should also support them. Notification interfaces are optional, but provide a convenient way to interact with users.

– A glance is another optional interface. It should provide the most relevant data for app users.

WKInterfaceController

All WatchKit controllers should subclass WKInterfaceController. WKInterfaceController is very similar to an ordinary UIViewController, but its lifecycle is a little bit different.

WKInterfaceController has three important lifecycle methods:

 awakeWithContext should be used to prepare the controller for use. Despite the fact that outlets are available also in the init: method, Apple advices to do all UI-related preparations in the awakeWithContext method. The context object is provided by the previous controller to exchange the data. If it is the root view controller, the context object will be nil.

willActive is called for the main interface controller to notify that interface is onscreen. It’s similar to viewDidLoad.

didDeactivate should be used for cleaning app the controller and is called, when the interface is no longer onscreen. Thus, overriding didDeactivate is similar to overriding dealloc.

The demo app

We will build a simple app that shows a list of upcoming events.

WatchKit

Complete code

You can find the complete code here (tested with Xcode 6.3):

Getting started

First create a dummy iOS app to represent our main application.

Open Xcode and create a new project by choosing the Single View Application template. Choose iPhone under “Devices”. Choose whether Swift or Objective-C on the screen. This tutorial covers both Swift and Objective-C.

WatchKit

Now let’s design the main user interface. Open Main.storyboard that should already have a single ViewController. Open the Object Library and find the UILabel object.

Drag it to the ViewController’s view. Setup autolayout constraints to center the label. Put some dummy text to the label. It’s all for the main application.

WatchKit

Adding Watch App target

Now press File -> Add Target -> Watch App.

WatchKit

Press Next, mark both “Include Notification Scene” and “Include Glance Scene” checkboxes. It will generate automatically all needed storyboard interfaces and add a json payload for testing notifications. Select the programming language of your choice.

WatchKit

Let’s look around what Xcode has created for us.

We see that there’s a WatchKit Extension with all needed interface controllers (for main interface, notifications and glance).

There’s also a separate Watch App that contains only the storyboard and assets folder.

WatchKit

If we open this storyboard, we see that all needed scenes (for main interface, notifications and glance) are also created.

WatchKit

Let’s try to launch the Watch App. Select the Watch App target and run it on iPhone 6. Select Hardware -> External Displays -> Apple Watch. It will open the Apple Watch Simulator. We see that our dummy Apple Watch app is already working!

WatchKit

Watch App Interface Builder Basics

Designing interfaces for Apple Watch is similar to designing for iOS, but a few things are simplified. 

1. The Object Library contains less objects, which are customised for Apple Watch (e.g Image or Table). A few objects are completely new (e.g menu or separator). 

WatchKit

2. Connecting IBOutlets and IBActions is same as for iOS.

3. Positioning views on screen is simplified. There is no frames, no autolayout and no view hierarchies. All items are stacked vertically on different lines – one below the other. There is also a possibility to use View Groups to layout items horizontally. The size and position of items can be configured in Attributes inspector.

All objects have to be added in Interface builder – new  objects cannot be added programmatically. The only option is to add all possible items in Interface builder and then show/hide them, when necessary. Hiding the object will free its space and other items will be laid out according to new space options.

WatchKit

Creating a Watch App

1. Rename the InterfaceController to HomeInterfaceController (refactor -> rename).

2. Open the storyboard of the Watch app. Select Home Interface Controller Scene. Open the Object Library and drag Table object to the scene.

WatchKit

3. Now open the Attributes Inspector and change the “Rows” attribute to 2. The “Rows” attribute sets the number of different row types that will be in the table. In that case, there will be 2 different row types: one for ordinary events and another for important events.

WatchKit

4. Add two new classes to WatchKit extension: OrdinaryEventRow and ImportantEventRow. Both should be subclasses of NSObject. They will represent table rows. If you’re writing in Swift, it’s important to subclass NSObject!

5. Add all needed outlets to those classes. 

Objective-C:

Swift:

Objective-C:

Swift:

6. Select the first row controller in the storyboard. Set both its class and identifier to “OrdinaryEventRow”.

WatchKit

WatchKit

7. Select the group inside the first row controller. Change its layout to Vertical.

WatchKit

8. Drag two labels to this group. Change their fonts to “System Bold 12.0” and “System 10.0”.

WatchKit

WatchKit

9. Connect labels to their outlets in the OrdinaryEventRow class.

WatchKit

10. Select the second row controller and set its class and identifier to “ImportantEventRow”.

11. Don’t change the group’s layout. Change group’s spacing setting to 10. Drag an Image and Group objects to this group.

WatchKit

12. Change size of image: its width should be relative to container with multiplier 0,4. Its height should be fixed with value 55. Connect the image to its outlet in the ImportantEventRow class.

screenshot20

13. Change the layout of new group to vertical. Also set its size to have a relative width to container with multiplier 0,6 and fixed height with value 60.

14. Drag two labels to this group. Change their fonts to “System Bold 12.0” and “System 10.0”. Change the text color of title label to red. Also change number of lines of both labels to 2.  Connect label to their outlets in the ImportantEventRow class.

WatchKit

WatchKit

15. Add a data file with name event.plist to the extension target.

This file will contain some dummy data to show. Also add event images to extension’s assets. You can find demo images HERE.

16. Add a new class named “Event” to the extension. It is data model for events objects and contains convenience method to retrieve all data.

Objective-C:

Swift:

17. Let’s now show this data in already created table! Add a table outlet to HomeInterfaceController and connect it in the storyboard.

Objective-C:

Swift:

18. Add a new empty method to HomeInterfaceController and name it setupTable. Call it from willActivate.

Objective-C:

Swift:

19. To fill the table with data two methods will be used: setRowTypes: and rowControllerAtIndex:

setRowTypes: takes an array of string identifiers that represent row controllers created earlier. This array also defines the total number of rows in the table and at which indexes which row types will be used.

There’s also another method available: setNumberOfRows:withRowType:. It can be used, when there’s only one type of rows. It is more convenient, because there’s no need to create an array of identifiers. However, in this demo app setRowTypes: will be used, because we need 2 types of rows.

After setting row types, you can use a method rowControllerAtIndex: to retrieve the row. Watch OS creates the row for you with correct class and all defined outlets.

So our method setupTable would look like this:

Objective-C:

Swift:

First, it retrieves events data and creates an array of row identifiers. If the event has an image, it is important. Otherwise, it’s ordinary.

After that, it sets row types and queries each created row controller from table. According to its class, appropriate outlets are used.

The result looks really nice:

WatchKit

Congrats! We have just created a simple Watch App.

Complete code

You can find the complete code here (tested with Xcode 6.3):

What’s next?

In the next part of this tutorial, we’ll take a look at more advanced WatchKit topics, including navigation between interface controllers, creating a menu, showing a map and dynamically changing properties of objects (e.g text color of label, hiding/showing objects). New parts will be available soon.

8 Comments
  1. praveenkumar
  2. Robert Moore
  3. Kevin
    • Kevin
      • iOSDev iOSDev
  4. Senry
  5. Darren
  6. Miles

Leave a Reply

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

*