Create a weather app for Apple Watch. Part 1: Startup and user interface - Bouvet Norge blogmask-mobile

Create a weather app for Apple Watch. Part 1: Startup and user interface

Mathias Lidal 
17. okt. 2016

In this tutorial I will show how to create a simple weather app for an Apple Watch running WatchOS2 (or 3). This tutorial will show the following:

  • Add Apple Watch support to an existing app
  • Set up the Apple Watch interface to show data
  • Communicate with the main app to get weather information from a third-party web service.

The basis for this tutorial is an IOS app which shows free weather data from the Norwegian Meteorological Service, It will show the weather for your current location and allow you to search for locations worldwide. The code for this project can be found on github. This app uses data from three external services to get location- and weather data.

  • SSR (Norwegian placename database), used for location search in Norway
  •, free worldwide placename database for location search in the rest of the world
  • to obtain weather data worldwide.

Note that the call to uses the "demo" user, which may fail due to usage limitations. To avoid this, create a new free account on, login to your account and enable web services, and update the value for "geonames username" in Info.plist.

Getting started

Start by cloning the project from github, opening it in Xcode then build and run. You will get a screenshot like the following: Simulator Screen Shot 12 Jul 2016 13.01.19 This app will show the weather for your current location (provided you give it access) and allow you to search for locations worldwide and show the weather.

Add WatchKit target

First step is adding the WatchKit app target. Go to File -> New -> Target... and choose watchOS -> Application -> WatchKit App. See screenshot below. Add Watch target Set Product Name to "Watch" and click Finish. Leave the rest of the options unchanged. WeatherWatch_xcodeproj When asked to active the new Watch scheme, click "Activate" This has now given you two new groups in the project, Watch and Watch Extension. Watch contains the user interface storyboard and image assets, Watch Extension contains the code to be run on the Apple Watch. Note that if you build the project now it will fail due to a naming conflict in the image Assets. You now have two Assets.xcassets, both containing an AppIcon. To fix this, change the name of the app icon inside the watch group to WatchAppIcon and change the App Icons Source for the watch target in the project view. Assets_xcassetsWeatherWatch_xcodeproj

Create user interface

First step in creating this app is to build the user interface. Open the file Interface.storyboard. Here you'll see three items. Ignore the two bottom ones, they are for showing notifications. Instead we'll focus on Interface Controller, which contains the user interface for the initial screen. The watch app will allow you to either see the weather for your current location or allow you to select weather from one of your saved locations. Therefore, start by dragging two buttons onto the Interface Controller. Name the first one "Current position" and the second one "Saved positions"Interface_storyboard_—_Edited Once this is done you can try running your app. Choose the Scheme 'watch' and run on the simulator. Once xcode has built the project the watch simulator will start and launch the app. Next step is to implement the interface controller to show weather for a location. Open the storyboard and drag a new Interface Controller onto the board. First, drag a label to the interface. Set width to Relative to Container, and height to Size To Fit Content. Center align the text and replace it with the text "Bergen". In the sidebar, change the name of the view to Placename Next, drag an image onto the screen. Increase the size to almost fill the rest of the screen, leaving the same amount of space as that used by the Placename label above. Set width to Relative to Container. Change the name of this view to WeatherSymbol. This Image will show a symbol representing the current weather. These images are stored in the Assets.xcassets folder for the main app and need to be added to the Watch target. Open WeatherWatch and select Assets.xcassets, in Target Membership, add "watch" Go back to the watch storyboard and select the image. Write 01d in Image, set Mode to Aspect Fit and set alignment to Center (both horizontal and vertical. Interface_storyboard_—_Edited Next, add a Group to the interface. This will initially place itself above the image. Set Horizontal alignment to center and vertical alignment to bottom and it will move to the bottom, below the image. Set width to Relative to Container and Height to size to fit content. Next, drag a button to the group. Set horizontal alignment to left and change the text to "20 °". Set the name of the view to Temperature. Finally drag another button to the group, set horizontal alignment to right and change text to "0 mm". Change the name of this button to Precipitation. Finally, we need a segue to launch this Interface. Ctrl-drag from the button "Current position" to the interface, choose push segue and set the identifier to "Show Weather"


    Next, we need to create the interface showing our saved locations. Drag another interface controller onto the storyboard and change the name to "Locations Controller". Add a Table to the interface. You will see that you get a Table Row Controller containing a group. To reference this table row later it needs an identifier. Select the table row controller, go to Attributes inspector and set the identifier to LocationRow, and make Selectable is checked. Interface_storyboard_—_Edited       Interface_storyboard_—_Edited For this table we only need a name, so drag a Label onto the group. Set Width and Height to Relative to Container. Set text on the label to Bergen and set text alignment to Center. Change the name of the label to Name. Interface_storyboard_—_EditedFinally we need to set up segues to show this interface and to show the weather for each location. Ctrl-drag from the button Saved Positions to the new interface and choose Push, set the identifier to "Saved Locations". Ctrl-drag from the Table Row Controller to Weather Controller, choose Push again and set the identifier to "Show Weather" The storyboard should now look like this. Interface_storyboard_—_Edited  

Create interface controller classes

After creating the interfaces we need to create the controllers. This will be part of the watch extension target. First, we'll create the class for Weather Controller. Choose File -> New -> File... and watchOS -> Source -> WatchKit Class Name the class WeatherController, click next, change Group and targets to "watch Extension" and click Create. Screenshot_12_07_16_15_22 Go back to the storyboard, choose the new interface and click on Show the Identity Inspector. Change the class to WeatherController. Interface_storyboard_—_Edited Change to the Assistent Editor and choose the new file (WeatherController.swift). Ctrl-drag from the top label to the class and create a new outlet, calling it placename. Do the same for the rest of the views, calling them weatherSymbol, temperature and precipitation, respectively, giving you the following outlets: WeatherController_swift_—_Edited Next, we'll create the class for the Location list. Again, choose File -> New -> File... and watchOS -> Source -> WatchKit Class. Name the new class LocationsController and set group and target to watch_extension. Go to the storyboard, choose the Locations Controller, go to Identity Inspector and set classname to LocationsController Interface_storyboard_—_Edited Go to the Assistant Inspector, choose the new file (LocationsController.swift) and ctrl-drag from the table to create a new outlet. Name this outlet locationsTable Insert_Connection_and_Interface_storyboard_—_Edited     If you start the project now you will notice that the WeatherController works and shows the data we've set in the storyboard. However, LocationsController will just show an empty screen. To show information here we need to setup the table in code. Open LocationsController.swift. Later we'll retrieve the saved locations list from the iphone app, but for now we'll use some hardcoded values. Add the following array to the class: [crayon-590cd5bc63b72582493636/] Unlike in normal IOS apps, in watchkit you need to setup the table manually. This requires four steps:

  1. Define one or more row controller types in your storyboard. (Already done)
  2. Define a custom data class to manage the contents of each row type.
  3. Tell the table object how many rows (and of what type) to display at runtime.
  4. Use instances of your custom data class to configure each row’s contents.

For more details, see the documentation for WKInterfaceTable.

1. Define row controller

We already did this when setting up the storyboard above.

2. Define custom data class

We need a class containing outlets for the views in the table row. Choose File -> New -> File... and watchOS -> Source -> Swift File. Set the filename to LocationRow and set group and targets to watchExtension Screenshot_13_07_16_10_26   Add the following code to this file: [crayon-590cd5bc63b80332990941/] This creates a new class LocationRow and adds an outlet variable for the name label in the table row. Next we need to connect the outlet. Open the storyboard and choose the table row (LocationRow), go to the Identity Inspector and set Class to LocationRow. Interface_storyboard_—_Edited Ctrl-drag from LocationRow to the Name label, and choose the outlet name.Interface_storyboard_—_Edited

3. Tell the table object how many rows (and of what type) to display at runtime.

Next, you need to declare how many rows the table should contain. You do this with the following function call: [crayon-590cd5bc63b86243329015/]

4. Use instances of your custom data class to configure each row’s contents.

Finally you need to create a controller instance per row and set the correct value for each label. [crayon-590cd5bc63b89552653436/] Here we iterate over each element in locations, instantiate a new row controller and cast it to our custom class, and finally set the name outlet. The full awakeWithContext function for LocationsController should look like this: [crayon-590cd5bc63b8c239355900/]   Now you can build the project and run it on your watch. The interface and navigation is completed but all the data is hardcoded. To show actual data requires that we connect the watch app to the main IOS app, which will be covered in part 2. If you want to see the final code, checkout branch tutorial_part1 of the git repository.