Brian Coleman

  • Home
  • ABOUT
  • SERVICES
  • PORTFOLIO
  • BLOG
  • Contact

Watch 4

Tutorial: Building an Apple Watch App

The new Apple Watch is going to be released soon, we are going to take a little time to build a quick app that displays the North American time zones. This app will allow the user to swipe between the timezones so they can easily know what time it is anywhere in Canada and the US.

This app is built on top of the Tutorial: Today Widget in Swift tutorial, since in that app we also made a timezone view. Since the Today Widget and the Apple Watch apps are very similar because they are both built using extensions to an existing app it should make it a little easier to build.

What is a Watch App?

If you don’t know much about the framework of what makes up a watch app, you should first read Get Started with Apple Watch and WatchKit. This will give you a great introduction to what a Watch App is, and how glances and notifications work with the watch.

Setup the Application Extension

  1. Select File > New > Project. Select the Single view application template, and call it WatchApp.
    Screen Shot 2015-04-17 at 8.49.00 AM
    Screen Shot 2015-04-17 at 8.49.16 AM

  2. Add the Application Extension Target. Select File > New > Target…. Then in the left pane, select Apple Watch and under that choose WatchKit App.
    Screen Shot 2015-04-17 at 8.56.49 AM
    Set the language to Swift if is isn’t already and check both Include Notification Scene and Include Glance Scene are not checked. Click Finish and Xcode will set up the target and the files needed for the Watch interface.
    Screen Shot 2015-04-17 at 9.00.58 AM

  3. A message will popup asking if you want to activate the “WatchApp WatchKit App” scheme. Click Activate.
    Screen Shot 2015-04-17 at 9.19.04 AM

  4. Adding a WatchKit App target to your Xcode project creates two new executables and updates your project’s build dependencies. Building your iOS app builds all three executables (the iOS app, WatchKit extension, and WatchKit app) and packages them together.
    Screen Shot 2015-04-17 at 9.27.10 AM
    The WatchKit app is packaged inside your WatchKit extension, which is in turn packaged inside your iOS app. When the user installs your iOS app on an iPhone, the system prompts the user to install your WatchKit app if there is a paired Apple Watch available.
    target_structure_2x

Create the Watch App View

The terminology for Watch Apps are a little different than iOS apps, instead of calling them “views”, Apple uses the term “Interface”. WatchKit apps do not use the same layout model as iOS apps. When assembling the scenes of your WatchKit app interface, you do not create view hierarchies by placing elements arbitrarily in the available space. Instead, as you add elements to your scene, Xcode arranges the items for you, stacking them vertically on different lines. At runtime, Apple Watch takes those elements and lays them out for you based on the available space.

storyboard_layout_2x

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

  1. We are going to start by adding a label into the Watch App Interface, in Interfaces the label type is WKInterfaceLabel. This one is the name of the time zone for the time we are going to display. Drag the label out from the Objects inspector just like you would in an iOS app. Also be sure to align the label text to center so it looks nice, also set the Position – Horizontal to “Center” as well.

    Screen Shot 2015-04-17 at 9.43.41 AM

  2. Next we need to add another label for the time. We’ll use a standard label so we can easily change the date per time zone> Watch Kit comes with its own Date label called WKInterfaceDate (but that only displays the current date and time). This can be customized, for our purposes we only want to see the time, not the date, so change the Date format to “None” and customize the font to “System” with a size of 30, and make it “Bold” so the time stands out, also set the Position – Horizontal to “Center” and Vertical to “Center”.

    Screen Shot 2015-04-17 at 9.54.57 AM

    Xcode supports customizing your interface for the different sizes of Apple Watch. The changes you make in the storyboard editor by default apply to all sizes of Apple Watch, but you can customize your storyboard scenes as needed for different devices. For example, you might make minor adjustments to the spacing and layout of items or specify different images for different device sizes.

  3. Now that we have our UI defined, let’s connect the IBOutlets with the code in the “InterfaceController.swift” file. You can do this many ways, just like an iOS app. Either Control-drag the UI object from the storyboard into the InterfaceController.swift or define the code and link up using the Connections Inspector.
    Here is the code for the two objects we are linking:

    //
    //  InterfaceController.swift
    //  WatchApp WatchKit Extension
    //
    //  Created by Brian Coleman on 2015-04-17.
    //  Copyright (c) 2015 Brian Coleman. All rights reserved.
    //
    
    import WatchKit
    import Foundation
    
    
    class InterfaceController: WKInterfaceController {
    
        @IBOutlet var timeInterfaceDate : WKInterfaceDate? = WKInterfaceDate()
        
        override func awakeWithContext(context: AnyObject?) {
            super.awakeWithContext(context)
            
            // Configure interface objects here.
        }
    
        override func willActivate() {
            // This method is called when watch view controller is about to be visible to user
            super.willActivate()
        }
    
        override func didDeactivate() {
            // This method is called when watch view controller is no longer visible
            super.didDeactivate()
        }
    
    }
    

Watch App 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 user’s 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.

For our project we are going to use a page based navigation so the user can swipe between the four time zones.

You configure a page-based interface in your app’s storyboard by creating a next-page segue from one interface controller to the next.

To create a next-page segue between interface controllers:

  1. In your storyboard, add interface controllers for each of the pages in your interface. Let’s add one for each of our time zones.
    Screen Shot 2015-04-17 at 10.58.52 AM

  2. Control-click your app’s main interface controller, and drag the segue line to another interface controller scene.
  3. The second interface controller should highlight, indicating that a segue is possible.
  4. Release the mouse button.
    Screen Shot 2015-04-17 at 11.01.16 AM

  5. Select “next page” from the relationship segue panel.
  6. Using the same technique, create segues from each interface controller to the next.
    Screen Shot 2015-04-17 at 11.02.27 AM

  7. The order in which you create your segues defines the order of the pages in your interface.

Add in Live Dynamic Data

We are almost done making our watch app, let’s add in the clocks to finish it up. The updateClocks() method is called every second to keep the time up to date.

//
//  InterfaceController.swift
//  WatchApp WatchKit Extension
//
//  Created by Brian Coleman on 2015-04-17.
//  Copyright (c) 2015 Brian Coleman. All rights reserved.
//

import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {

    @IBOutlet var easternLabel : WKInterfaceLabel? = WKInterfaceLabel()
    @IBOutlet var centralLabel : WKInterfaceLabel? = WKInterfaceLabel()
    @IBOutlet var mountainLabel : WKInterfaceLabel? = WKInterfaceLabel()
    @IBOutlet var pacificLabel : WKInterfaceLabel? = WKInterfaceLabel()
    
    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)
        
        // Create a timer to refresh the time every second
        var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("updateClocks"), userInfo: nil, repeats: true)
        timer.fire()
    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }
    
    func updateClocks() {
        var time: NSDate = NSDate()
        
        let formatter:NSDateFormatter = NSDateFormatter();
        var timeZone = NSTimeZone(name: "UTC")
        formatter.timeZone = timeZone
        formatter.dateFormat = "h:mm a"
        var formattedString = formatter.stringFromDate(time)
        var formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
        formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
        
        timeZone = NSTimeZone(name: "US/Eastern")
        formatter.timeZone = timeZone
        formatter.dateFormat = "h:mm a"
        formattedString = formatter.stringFromDate(time)
        formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
        formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
        self.easternLabel?.setText(formatDateString)
        
        timeZone = NSTimeZone(name: "US/Pacific")
        formatter.timeZone = timeZone
        formatter.dateFormat = "h:mm a"
        formattedString = formatter.stringFromDate(time)
        formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
        formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
        self.pacificLabel?.setText(formatDateString)
        
        timeZone = NSTimeZone(name: "US/Mountain")
        formatter.timeZone = timeZone
        formatter.dateFormat = "h:mm a"
        formattedString = formatter.stringFromDate(time)
        formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
        formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
        self.mountainLabel?.setText(formatDateString)
        
        timeZone = NSTimeZone(name: "US/Central")
        formatter.timeZone = timeZone
        formatter.dateFormat = "h:mm a"
        formattedString = formatter.stringFromDate(time)
        formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
        formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
        self.centralLabel?.setText(formatDateString)

    }

}

Test Your Watch App

  1. When you run the app you’ll see a blank view since our app doesn’t do anything except create the Watch App and the watch is shown in an External Display.
  2. Build and Run your app against the Watch App target.
    Screen Shot 2015-04-17 at 1.44.56 PM

  3. Then, switch over to your simulator and check that you have the External Display set for the watch. iOS Simulator > Hardware > External Displays (try both sizes to see how it looks).
    Screen Shot 2015-04-17 at 1.44.26 PM

  4. You should see your app in the Apple Watch simulator. Swipe left to see the other time zones.
    Screen Shot 2015-04-17 at 1.49.09 PM

You can grab the full source code for this tutorial. Note: Built for Xcode 6.3 (Swift 1.2).

If you would like to continue on and add a Glance to your watch app, read Tutorial: Building a Apple Watch Glance or add a Dynamic Notification Interface, read Tutorial: Building a Apple Watch Notification

April 20, 2015 Swift, Tutorials, Watchios8, swift, tutorial, watch

Tutorial: Building an Apple Watch Glance

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 user’s next meeting, whereas the glance for an airline app might display gate information for an upcoming flight. WatchKit apps may have only one glance interface. Do not add more than one glance interface controller to your app’s storyboard.

To build a Glance you need to already have a Watch App, if you’d like to learn how to do that, read
Tutorial: Building an Apple Watch App In that tutorial we walk through building an app that shows the time across all four Canadian and U.S. timezones.

Glance Guidelines

Xcode provides fixed layouts for arranging the contents of your glance. After choosing a layout that works for your content, use the following guidelines to fill in that content:

  • 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.

For our app we’re going to add a Glance that contains all timezones for the user to view at once.

Add a Glance

  1. Begin by adding all of the labels needed for the Interface.
    Screen Shot 2015-04-20 at 8.37.23 AM

  2. Now that we have our UI defined, let’s connect the IBOutlets with the code in the “GlanceController.swift” file. You can do this many ways, just like an iOS app. Either Control-drag the UI object from the storyboard into the GlanceController.swift or define the code and link up using the Connections Inspector.
  3. After the UI is all hooked up, let’s add some code as we did for the Watch app so our times will update every second.
    //
    //  GlanceController.swift
    //  WatchApp WatchKit Extension
    //
    //  Created by Brian Coleman on 2015-04-17.
    //  Copyright (c) 2015 Brian Coleman. All rights reserved.
    //
    
    import WatchKit
    import Foundation
    
    
    class GlanceController: WKInterfaceController {
    
        @IBOutlet var easternLabel : WKInterfaceLabel? = WKInterfaceLabel()
        @IBOutlet var centralLabel : WKInterfaceLabel? = WKInterfaceLabel()
        @IBOutlet var mountainLabel : WKInterfaceLabel? = WKInterfaceLabel()
        @IBOutlet var pacificLabel : WKInterfaceLabel? = WKInterfaceLabel()
        
        override func awakeWithContext(context: AnyObject?) {
            super.awakeWithContext(context)
            
            // Create a timer to refresh the time every second
            var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("updateClocks"), userInfo: nil, repeats: true)
            timer.fire()
            
        }
    
        override func willActivate() {
            // This method is called when watch view controller is about to be visible to user
            super.willActivate()
        }
    
        override func didDeactivate() {
            // This method is called when watch view controller is no longer visible
            super.didDeactivate()
        }
        
        func updateClocks() {
            var time: NSDate = NSDate()
            
            let formatter:NSDateFormatter = NSDateFormatter();
            var timeZone = NSTimeZone(name: "UTC")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            var formattedString = formatter.stringFromDate(time)
            var formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            
            timeZone = NSTimeZone(name: "US/Eastern")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            formattedString = formatter.stringFromDate(time)
            formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            self.easternLabel?.setText(formatDateString)
            
            timeZone = NSTimeZone(name: "US/Pacific")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            formattedString = formatter.stringFromDate(time)
            formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            self.pacificLabel?.setText(formatDateString)
            
            timeZone = NSTimeZone(name: "US/Mountain")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            formattedString = formatter.stringFromDate(time)
            formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            self.mountainLabel?.setText(formatDateString)
            
            timeZone = NSTimeZone(name: "US/Central")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            formattedString = formatter.stringFromDate(time)
            formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            self.centralLabel?.setText(formatDateString)
        }
    }
    

Test Your Glance

  1. When you run the app you’ll see a blank view since our app doesn’t do anything except create the Watch App and the watch is shown in an External Display.
  2. Build and Run your app against the Glance target.
    Screen Shot 2015-04-20 at 8.47.53 AM

  3. Then, switch over to your simulator and check that you have the External Display set for the watch. iOS Simulator > Hardware > External Displays (try both sizes to see how it looks).
    Screen Shot 2015-04-17 at 1.44.26 PM

  4. You should see your app in the Glance in the Watch simulator.
    Screen Shot 2015-04-20 at 8.48.58 AM

You can grab the full source code for this tutorial. Note: Built for Xcode 6.3 (Swift 1.2).

If you would like to continue on and add a Dynamic Notification Interface to your Watch App, read Tutorial: Building a Apple Watch Notification

April 20, 2015 Swift, Tutorials, Watchios8, swift, tutorial, watch

Tutorial: Building an Apple Watch Notification

Notifications on Apple Watch facilitate quick, lightweight interactions for local and remote notifications. These interactions occur in two stages, which are managed by the short-look and long-look interfaces. The short-look interface appears when a local or remote notification first arrives. A short look presents a discreet, minimal amount of information to the user—preserving a degree of privacy. If the wearer’s wrist is lowered, the short-look interface disappears. The long-look interface appears when the wearer’s wrist remains raised or when the wearer taps the short-look interface. It provides more detailed information and more functionality—and it must be actively dismissed by the wearer.

Static vs Dynamic Interfaces

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 notification’s 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 notification’s content.

notification_static_dynamic_2x

notification_process_2x

Use the static notification interface to define a simple version of your custom notification interface. The purpose of a static interface is to provide a fallback interface in the event that your WatchKit extension is unable to configure the dynamic interface in a timely manner.

A dynamic notification interface lets you provide a more enriched notification experience for the user. With a dynamic interface, you can display more than just the alert message. You can incorporate additional information, configure more than one label, display dynamically generated content, and so on.

To implement a dynamic notification interface, you must create a custom WKUserNotificationInterfaceController subclass. How you implement that subclass determines what information is displayed in the notification interface.

We’ll cover how to customize a dynamic notification, since for the static ones, “it just works”.

To build a Dynamic Notification you need to already have a Watch App, if you’d like to learn how to do that, read
Tutorial: Building an Apple Watch App In that tutorial we walk through building an app that shows the time across all four Canadian and U.S. timezones.

Customize a Dynamic Notification

  1. Begin by adding all of the labels needed for the Interface within the Storyboard under the Dynamic Notification Interface.
  2. Drag in a Group object from the Object Library for each one of the timezones.
    Screen Shot 2015-04-20 at 3.55.05 PM

  3. Now that we have our UI defined, let’s connect the IBOutlets with the code in the “NotificationController.swift” file. You can do this many ways, just like an iOS app. Either Control-drag the UI object from the storyboard into the NotificationController.swift or define the code and link up using the Connections Inspector.
  4. After the UI is all hooked up, let’s add some code for the NotificationController.swift so when we receive a notification we’ll show the current timezone times to the user.
  5. The following is to define our labels that will be in the notification. Don’t forget to add the alertLabel and bodyLabel or else the user will not see the pay load for the remote notification sent to them.
        @IBOutlet var easternLabel : WKInterfaceLabel? = WKInterfaceLabel()
        @IBOutlet var centralLabel : WKInterfaceLabel? = WKInterfaceLabel()
        @IBOutlet var mountainLabel : WKInterfaceLabel? = WKInterfaceLabel()
        @IBOutlet var pacificLabel : WKInterfaceLabel? = WKInterfaceLabel()
        
        @IBOutlet var alertLabel : WKInterfaceLabel? = WKInterfaceLabel()
        @IBOutlet var bodyLabel : WKInterfaceLabel? = WKInterfaceLabel()
    
  6. Next are the methods for handling the local and remote notifications. You need to add code in here for the Dynamic Interface to be enabled, if you leave it blank you will get the Static Interface for the notification with the title displayed.
        override func didReceiveLocalNotification(localNotification: UILocalNotification, withCompletion completionHandler: ((WKUserNotificationInterfaceType) -> Void)) {
            // This method is called when a local notification needs to be presented.
            // Implement it if you use a dynamic notification interface.
            // Populate your dynamic notification interface as quickly as possible.
            
            self.alertLabel?.setText(localNotification.alertTitle)
            
            self.updateClocks()
            
            // After populating your dynamic notification interface call the completion block.
            completionHandler(.Custom)
        }
        
        override func didReceiveRemoteNotification(remoteNotification: [NSObject : AnyObject], withCompletion completionHandler: ((WKUserNotificationInterfaceType) -> Void)) {
            
            self.updateClocks()        
    
            if let remoteaps:NSDictionary = remoteNotification["aps"] as? NSDictionary{
                if let remoteAlert:NSDictionary = remoteaps["alert"] as? NSDictionary{
                    handleNotification( remoteAlert );
                }
            }
            
            completionHandler(.Custom)
        }
        
        func handleNotification( alert : AnyObject? ){
            
            if let alert: AnyObject = alert, let remotetitle = alert["title"] as? String{
                println( "didReceiveRemoteNotification::remoteNotification.alert \(remotetitle)" )
                self.alertLabel!.setText(remotetitle);
            }
            if let alert: AnyObject = alert, let remotebody = alert["body"] as? String{
                //println( "didReceiveRemoteNotification::remoteNotification.alert \(remotetitle)" )
                self.bodyLabel!.setText(remotebody);
            }
        }
    
  7. Lastly below is the method to return the time per timezone to be displayed in the notification.
        func updateClocks() {
            var time: NSDate = NSDate()
            
            let formatter:NSDateFormatter = NSDateFormatter();
            var timeZone = NSTimeZone(name: "UTC")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            var formattedString = formatter.stringFromDate(time)
            var formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            
            timeZone = NSTimeZone(name: "US/Eastern")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            formattedString = formatter.stringFromDate(time)
            formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            self.easternLabel?.setText(formatDateString)
            
            timeZone = NSTimeZone(name: "US/Pacific")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            formattedString = formatter.stringFromDate(time)
            formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            self.pacificLabel?.setText(formatDateString)
            
            timeZone = NSTimeZone(name: "US/Mountain")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            formattedString = formatter.stringFromDate(time)
            formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            self.mountainLabel?.setText(formatDateString)
            
            timeZone = NSTimeZone(name: "US/Central")
            formatter.timeZone = timeZone
            formatter.dateFormat = "h:mm a"
            formattedString = formatter.stringFromDate(time)
            formatDateString = formattedString.stringByReplacingOccurrencesOfString(" p", withString: "PM", options: nil, range: nil)
            formattedString = formattedString.stringByReplacingOccurrencesOfString(" a", withString: "AM", options: nil, range: nil)
            self.centralLabel?.setText(formatDateString)
        }
    

    Test Your Notification

    1. When you run the app you’ll see a blank view since our app doesn’t do anything except create the Watch App and the watch is shown in an External Display.
    2. Build and Run your app against the Notification target.
      Screen Shot 2015-04-20 at 4.00.35 PM

    3. Then, switch over to your simulator and check that you have the External Display set for the watch. iOS Simulator > Hardware > External Displays (try both sizes to see how it looks).
      Screen Shot 2015-04-17 at 1.44.26 PM

    4. You should see your app in the Notification in the Watch simulator. Since it’s in the simulator it will provide some sample payload “Optional title” and “Test message” to be displayed.
      Screen Shot 2015-04-20 at 4.02.20 PM

    You can grab the full source code for this tutorial. Note: Built for Xcode 6.3 (Swift 1.2).

April 20, 2015 Swift, Tutorials, Watchios8, swift, tutorial, watch

Get Started with Apple Watch and WatchKit

It’s finally here, we’ve been waiting a long time since we heard the rumours of an iWatch, and now with the release of Xcode 6.2 and the iOS 8.2 SDK Apple has included WatchKit so we can begin developing for it at last. What kind of watch app are you going to make?

Let’s look at the three kinds of watch interfaces you can include in your app.

WatchKit Apps

watch1

A Watch app is the basis for interacting with your content on Apple Watch. Watch apps are accessible from the home screen and usually provide only a portion of the functionality of their containing iOS app. The purpose of a Watch app is to give the user quick but more in-depth access to app-related data.

The Watch app works in tandem with a corresponding WatchKit extension running on the user’s iPhone. The Watch app contains no custom code and is used only to store the storyboards and resource files associated with your user interface. The WatchKit extension is the brains of the operation. It contains the business logic and code you use to manage your content, respond to user interactions, and update your user interface. And because it runs on the user’s iPhone, the WatchKit extension can easily coordinate with your iOS app to gather location updates or perform other long-running tasks.

Learn how to make a Watch App, Tutorial: Building an Apple Watch App

Glances

watch2
A glance is a focused interface for presenting important information that the user needs right now. Glances are aptly named because they are intended to be looked at quickly by the user. Glances do not scroll, so 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 Watch app.

The code for managing a glance resides in your WatchKit extension. The classes you use to manage your glance interface are the same ones you use for your Watch app. Even though the classes and basic behaviour are the same, a glance is simpler to implement because it does not respond to user interactions.

Learn how to make a Glance, Tutorial: Building an Apple Watch Glance

Actionable Notifications

watch3
Apple Watch works with its paired iPhone to display local and remote notifications. Initially, Apple Watch uses a minimal interface to display incoming notifications. When the user’s movement indicates a desire to see more information, the minimal interface changes to a more detailed interface displaying the contents of the notification. Apps can provide their own customized version of this detailed interface and add custom graphics or arrange the notification data differently than the default interface provided by the system.

Apple Watch supports the interactive notifications that were introduced in iOS 8. Interactive notifications are a way to add buttons to a notification that reflect immediate actions the user can take. For example, an incoming calendar event might include buttons to accept or reject a meeting invitation. When your iOS app registers support for interactive notifications, Apple Watch automatically adds appropriate buttons to both the custom and default notification interfaces. All you need to do is handle the actions selected by the user in your WatchKit extension.

Learn how to make a Dynamic Notification, Tutorial: Building an Apple Watch Notification

Getting Started with WatchKit video

Apple has made a great video to help us understand the architecture, the APIs available and how the interface works.
Screen Shot 2014-11-18 at 8.11.32 PM

Development Resources

  • Apple Watch Human Interface Guidelines
  • Xcode 6.2 beta, including iOS 8.2 SDK with WatchKit
  • iOS 8.2 beta in iOS Dev Center
  • WatchKit Programming Guide
  • WatchKit Framework Reference
  • WatchKit Catalog: Using WatchKit Interface Elements
  • Lister: A Productivity App (Obj-C and Swift)
  • WatchKit Catalog: Using WatchKit Interface Elements
November 18, 2014 News, Tutorials, Watchios8, tutorial, watch
Recent Posts
  • Classix for iPhone, iPad & Apple TV
  • Tutorial: How to test your app for IPv6 compatibility
  • Tutorial: Testing SSL using Charles Proxy on an iOS Device
  • Tutorial: 3D Touch – Quick Actions in Swift
  • tvOS Tutorial: Top Shelf in Swift
Featured Apps
Classix
Sportsnet
TAGS
tutorialswiftios8iosobjective-cvideogamesstrategynewsframeworkappsmonitizefacebookwatchappleios7toolstvosios9apiprovisionsocialtutorialsbooksdesignbookiapIPv6iTunes Connect
Search
TAGS
tutorialswiftios8iosobjective-cvideogamesstrategynewsframeworkappsmonitizefacebookwatchappleios7toolstvosios9apiprovisionsocialtutorialsbooksdesignbookiapIPv6iTunes Connect
ABOUT
Brian is a Lead iOS/tvOS Developer from Toronto with over 18 years of multifaceted experience including development, design, business analysis and project management.

FOLLOW ME
    
Email Subscription
Sign up for my newsletter to receive the latest news and tutorials posted.

Enter your email address:

2023 © Brian Coleman