Introduction to Apple Watch Apps

WatchOS is the operating system of the Apple Watch. In this tutorial, we will provide a basic overview of watchOS development and help you create your first user interface for the Watch. This should help you get started on your journey to create more complex applications.

This articles assumes that you have basic knowledge in developing iOS applications.


WatchOS applications are a great way of improving the user experience of your iOS application. They provide a convenient way for your user to be up to date with the latest information from your application and also interact with it.

Some examples would be:

  • a weather forecast application
  • reminders application.
  • a music player

Overview of a WatchOS application.

User Interface

The WatchKit framework is where all of the UI elements are defined. Due to the limited space on the watch screen, the user interface of your application must be stripped down to its essentials. Some of the building blocks of a typical WatchOS application are WKInterfaceController, WKInterfaceLabel or WKInterfaceTable. These classes are similar to UIViewController, UILabel and UITableView, respectively, but they are adjusted to the context of the Watch. For example, WKInterfaceController doesn’t manage any view and its visual components are defined in the storyboard. Another example of adjustment would be in the way we create the layout of our UI elements, which we will look later in the tutorial in more detail.




Complications are everything you can see on your Watch face except the time. Implementing a complication gives the user the possibility to quickly see information by just looking at his watch. If you don’t have information which is suitable for a complication, Apple recommends that you still implement it. It is a fast way to launch the application. In order to implement complications, we have to use the ClockKit framework.


Notifications are another important part of the application. watchOS supports both local notifications and remote notifications. When you raise your wrist to look at a notification the watch can sense how long you looked at it. The reason for this is to divide the interface of the notification into two modes: the short look interface (non-customizable) and the long look interface (customizable). For more about notifications on the Apple Watch we suggest: Notifications Essentials and UserNotifications

Watch Connectivity

WatchConnectivity is the framework which handles two-way communication between your iOS app and its Watch extension. watchOS applications make use of this kind of communication to fetch the latest data from its iOS counterpart or to send live messages back and forth. The WCSession object and WCSessionDelegate protocol are inevitable when using this framework.

Your first watchOS application

The first application you will create will have a user interface for a music player.

Step 1: Project setup

Create a new project using the “iOS App with Watchkit App” template from the watchOS tab.

Name it MusicPlayer and make sure that only “Include Complication” is checked.

Step 2: Add UI elements

In the Project navigator, there are two groups: MusicPlayer WatchKit App and MusicPlayer WatchKit Extension. The first group is where the user interface is defined and the second group is where the code of the application is written

Let’s add to our application two labels. First, click on the “Interface.storyboard” file from the MusicPlayer WatchkitApp group. Now you will see a black screen which represents an InterfaceController. This is what the user sees when he launches the application.

From the Object library, drag into the black screen a Label object. Do the same for another Label. Under these two Labels, drag three Buttons and a Slider. By now, you should have this on your screen.

Step 3: Edit UI elements

Change the text of the first label to be “Artist” and for the second one “Song”.

Now, we are going to replace the button titles with some images that are suggestive of the action of what will happen when they are pressed. Download these images here. Drag the images from the folder you have just downloaded into the Assets of the MusicPlayer WatchKit App group.

Click the Interface.storyboard file and select the first button. Go to the Attributes Inspector and clear the text field. In the Background image field, select the rewind image.

Repeat this for the next two buttons, but choose Play and Forward images.

Now, select the buttons (by holding CMD and clicking on them), and in the Attributes Inspector, change both Width and Height fields to Fixed.

Notice the gray “+” signs next to many of the fields from Attributes Inspectors. These are there to choose sizes for specific kinds of the Apple Watch screen sizes. Click on the one next to the width value field and select the 42mm option. Now click again and select the 38mm option. There will be two new fields for both of the Apple Watch sizes. In the 42mm field put the value 44 and in the 38mm put the value 40.

You can see how the UI looks on both sizes by clicking on “View As: Apple Watch 38mm/42mm” and then choosing the device.

Step 4: Autolayout

The approach to auto layout in watchOS is different to the one used in iOS. It is simple, but at the same time powerful enough for the watchOS UI. If you know how to use the StackView class from iOS, this approach will feel familiar to you.

In the Interface.storyboard, select the first two labels (by holding CMD and clicking on them). Now, with the labels selected, click on the Editor in the XCode menu. Select Embed In->Vertical Group.

For the buttons, repeat this step, but choose Horizontal Group instead of Vertical Group.

This looks better, but the overall UI seems very crowded. In the Document outline of the storyboard, select the two groups and the slider.

Now embed them into a Vertical Group, as you did for the labels.

We have just made a Vertical Group, which contains two groups and a Slider. The power of this auto layout technique lays in nesting groups into each other in order to form more complicated user interfaces.

The document outline of the storyboard should look like this:

Select the group which contains everything else. Go to the Attributes Inspector and in click on the “+” sign right next to the Spacing field. For the 38mm Watch put the value 15 and for the 42mm Watch put the value 24.

We would also like for the labels and buttons to be centered horizontally. Select the labels and go to the Attributes Inspector. In the Horizontal field from the Alignment section, choose Center. Now, the labels should be centered horizontally.

Choose the group of buttons. In the Horizontal field from Alignment section, choose the option Center. Next, for the Width field in the Size section, choose Size to Fit Content.

Application code

We have just made the visual component of the application. But the application itself doesn’t do anything yet. For your first watchOS application, we will keep it simple and add just a bit of functionality. When the user presses the play button, it should change its image, like in a usual player application. Also, when the user rotates the crown of the watch the volume slider should increase/decrease.

Step 5: Add @IBOutlets and @IBActions

We have mentioned earlier that the application code will be located in the MusicPlayer WatchKit Extension group. Select the InterfaceController.swift file.

Add two IBOutlets, one for the play button and one for the volume slider.

    @IBOutlet var playButton: WKInterfaceButton!
    @IBOutlet var volumeSlider: WKInterfaceSlider!

Create two IBActions, playButtonTapped and sliderAction. The sliderAction function takes a parameter named value, which indicates the new value of the volumeSlider.

    @IBAction func playButtonTapped() {

    @IBAction func sliderAction(_ value: Float) {


From the pictures you have downloaded, drag Play and Pause to the Assets.xcassets from MusicPlayer WatchKit Extension group.

Initially, the button has the Play image. When the user presses the button it should change its image to the Pause one. When it’s pressed again its image will be again Play, and so on.

Step 6: Define the model for a song state

Let’s model the state of the song. A song has two states: playing and paused. This can be represented in Swift using an enumeration. Add the following enumeration in the class body of InterfaceController.swift file.

enum SongState {
    case Playing
    case Paused

Now add a property to the InterfaceController which is initialized to Paused.

var songState: SongState = .Paused

Step 7: songState logic

In the playButtonTapped function, we have to write the code that changes the current state to the other one, along with the button image.

@IBAction func playButtonTapped() {
    if songState == .Paused {
        songState = .Playing
        playButton.setBackgroundImage(UIImage(named: "Pause"))
    } else {
        songState = .Paused
        playButton.setBackgroundImage(UIImage(named: "Play"))

Step 8: Using the Digital Crown

For the InterfaceController to respond when a user rotates the crown of the watch, it must implement the WKCrownDelegate.

class InterfaceController: WKInterfaceController, WKCrownDelegate

The awake(withContext context: Any?) function is called when the InterfaceController is initialized. Here we should set the crown delegate:

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)
        crownSequencer.delegate = self


The crownDidRotate(_ crownSequencer: WKCrownSequencer?, rotationalDelta: Double) function is called when the user rotates the crown. The rotationaldelta parameter contains a value which represents how much the crown has been rotated.

Step 9: Keep track of the volume

In code, we can only set properties of the UI elements, so we will have to keep track of the volume level.

var currentVolumeLevel: Float = 1.0
let numberOfSteps = 3

Make sure currentVolumeLevel is initialized with the value of the value field in the Attributes Inspector of the slider.

Add this line of code in the awake function:


Step 10: Update the volume when a button is pressed.

When one of the buttons of the slider is pressed, we have to update the currentVolumeLevel variable.

@IBAction func sliderAction(_ value: Float) {
    currentVolumeLevel = value

Step 11: Update the volume when the crown is rotated.

Now, let’s write the code which updates the volumeSlider when the crown is rotated. In crownDidRotate add:

    func crownDidRotate(_ crownSequencer: WKCrownSequencer?, rotationalDelta: Double) {
        let predictedVolumeLevel = currentVolumeLevel + Float(rotationalDelta) * 10
        if predictedVolumeLevel > 0.0 && predictedVolumeLevel <= Float(numberOfSteps) {
            currentVolumeLevel = predictedVolumeLevel

The new volume of the slider will be the current one plus how much the crown has been rotated. We multiply by ten, so the user doesn’t have to rotate much until the volume is full.

We only update the slider if the value is valid (between 0 and the number of steps).

For this example to work make sure the values in the slider Attributes Inspector are the ones from this image:

This is to make sure that the values from the Attributes Inspector are consistent with the ones from our code since the properties of the IBOutlets can’t be accessed.

Step 12: Running the application.

In order to run the application you have to select the “MusicPlayer Watchkit App” schema. As an example we’ll run it on a 38mm Watch (watchOS 3) paired with an iPhone 6S.


We have looked into the most important frameworks and basic techniques for creating a watchOS application. It starts to get even more interesting when we try to actually play music on the Watch and make the two devices communicate with each other using WatchConnectivity. Very often, it also makes sense to implement Notifications and Complications, because they create a better user experience.

Thank you for reading!

If you enjoyed this article please take a moment and share it with your friends :)

1 Star2 Stars3 Stars4 Stars5 Stars (7 votes, average: 4.71 out of 5)

  4 comments for “Introduction to Apple Watch Apps

  1. July 13, 2017 at 7:05 am

    Nice it seems to be good post… It will get readers engagement on the article since readers engagement plays an vital role in every blog.. i am expecting more updated posts from your hands.

  2. Jim Slusser
    July 21, 2017 at 5:48 pm

    Caveat – I’m a brand new, 1st time, self-taught Swift coder…

    I’m receiving an error with the line of code from Step 9; volumeSlider.setNumberOfSteps(numberOfSteps)

    Error message: fatal error: unexpectedly found nil while unwrapping an Optional value

    Thread 1: EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0x0)


    Any ideas what I’m doling wrong? Thanks in advance.

    • Bogdan Pop
      July 31, 2017 at 9:02 pm

      It’s the step 5 you are doing wrong. When you create the IBOutlets and IBActions, you also have to connect them to their respective UI elements (in the Interface.storyboard file).

      Another thing that you missed is copying the “Play” and “Pause” images to the Assets from the “MusicPlayer WatchKit Extension” group (you only have them in the “MusicPlayer WatchKit App” group).

      You’re welcome :)

  3. September 9, 2017 at 7:37 am

    thanks for sharing this introduction

Leave a Reply

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

We send about one email per week with our latest tutorials and updates
Never display this again :)