5. Accessing the Apple Watch Hardware

This is what customers pay us for—to sweat all these details so it’s easy and pleasant for them to use our computers. We’re supposed to be really good at this. That doesn’t mean we don’t listen to customers, but it’s hard for them to tell you what they want when they’ve never seen anything remotely like it.

Steve Jobs

In watchOS 1.0, Apple did not provide third-party developers access to the various hardware features of the Apple Watch, such as the accelerometer, microphone, and Taptic Engine. However, in watchOS 2, Apple has exposed some of these features to developers so that they can create more exciting watch apps.

In this chapter, you learn how to access some of these hardware features and see how they can be useful to the apps you are building.

Making Phone Calls and Sending Messages

In watchOS 2, your watch app can now directly make a phone call or send a message. To do so, follow these steps:

1. Using Xcode, create a new iOS App with WatchKit App project and name it NewCapabilities. Uncheck the option Include Notification Scene so that we can keep the WatchKit project to a bare minimum.

2. Select the Interface.storyboard file to edit it in the Storyboard Editor.

3. Drag and drop two Button controls onto the Interface Controller, as shown in Figure 5.1.

Image

Figure 5.1 Populating the Interface Controller

4. Create two actions for the buttons in the InterfaceController.swift file:

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {

    @IBAction func btnCallPhone() {
    }
    @IBAction func btnSendMessage() {
    }

5. Add the following statements in bold to the InterfaceController.swift file:

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {

    @IBAction func btnCallPhone() {
        if let url = NSURL(string: "tel:1234567") {
            WKExtension.sharedExtension().openSystemURL(url)
        }
    }

    @IBAction func btnSendMessage() {
        if let url = NSURL(string: "sms:1234567") {
            WKExtension.sharedExtension().openSystemURL(url)
        }
    }

The sharedExtension method of the WKExtension class returns a copy of the WatchKit Extension object, which you can use to open URLs. The openSystemURL: method allows you to launch another application using a URL scheme. In the current version of WatchKit, only the tel: (for making a phone call) and sms: (for sending messages) schemes are supported.

6. Select the WatchKit App scheme and run the project on a real Apple Watch. Tapping the Call Phone button (Figure 5.2, left) directly places a phone call on the iPhone (see Figure 5.2, middle), and tapping Send Message allows you to compose a message (see Figure 5.2, right) and send it through the iPhone’s Messages app.

Image

Figure 5.2 Making a phone call and sending messages directly from the Apple Watch

Recording Audio

The Apple Watch has a built-in microphone that allows you to make dictation and place phone calls. In watchOS 2, your apps have access to the microphone to perform audio recordings:

1. Using Xcode, create a new iOS App with WatchKit App project and name it AudioRecord. Uncheck the option Include Notification Scene so that we can keep the WatchKit project to a bare minimum.

2. Select the Interface.storyboard file to edit it in the Storyboard Editor.

3. Drag and drop a Button control onto the Interface Controller and set its title to Record Audio, as shown in Figure 5.3.

Image

Figure 5.3 Populating the Interface Controller

4. Create an action for the button in the InterfaceController.swift file:

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {

    @IBAction func btnRecordAudio() {
    }

5. Add the following statements in bold to the InterfaceController.swift file:

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {
    var filePath:NSURL!
    @IBAction func btnRecordAudio() {
        if let dir : NSString = NSSearchPathForDirectoriesInDomains(
            NSSearchPathDirectory.DocumentDirectory,
            NSSearchPathDomainMask.AllDomainsMask, true).first {
                //---format can be wav, mp4, or m4a---
                let path = dir.stringByAppendingPathComponent(
                    "myrecording.wav");
                filePath = NSURL(string: path)
                let audioOptions = [
                    WKAudioRecorderControllerOptionsActionTitleKey:
                        "Save",
          WKAudioRecorderControllerOptionsAlwaysShowActionTitleKey:
              true,
                     WKAudioRecorderControllerOptionsAutorecordKey:true,
                WKAudioRecorderControllerOptionsMaximumDurationKey:5.0
                ]
                presentAudioRecorderControllerWithOutputURL(filePath!,
                    preset: WKAudioRecorderPreset.HighQualityAudio,
                    options: audioOptions as [NSObject : AnyObject],
                    completion: {
                    (didSave, error) -> Void in
                    if didSave {
                        print("Audio saved!")
                        let options =
                            [WKMediaPlayerControllerOptionsAutoplayKey:
                                true]
                        self.presentMediaPlayerControllerWithURL(
                            self.filePath, options: options) {
                            (didPlayToEnd, endTime, error) -> Void in
                            if didPlayToEnd {
                                print("Movie finished playback")
                            }
                            if error != nil {
                                print(error!.description)
                            }
                        }
                    }
                    if error != nil {
                        print(error!.description)
                    }
                })
        }
    }

In the previous statements, you first created a path to save the audio recording. In particular, you saved it into the Documents directory on the Apple Watch. You then created a dictionary containing the various options to record the audio:

Image WKAudioRecorderControllerOptionsActionTitleKey specifies the title to display (in the top-right corner) when the Audio Recorder Controller is displayed.

Image WKAudioRecorderControllerOptionsAlwaysShowActionTitleKey specifies whether to show the title on the Audio Recorder Controller.

Image WKAudioRecorderControllerOptionsAutorecordKey specifies if audio recording should commence automatically when the Audio Recorder Controller is shown.

Image WKAudioRecorderControllerOptionsMaximumDurationKey specifies the maximum duration of the audio recording in seconds. To indicate no maximum duration, use NSTimeInterval.infinity.

To display the Audio Recorder Controller, call the presentAudioRecorderControllerWithOutputURL:preset:options:completion: method. This method takes in the following arguments:

Image The quality of the audio to record, which could be HighQualityAudio, NarrowBandSpeech, or WideBandSpeech

Image The options dictionary as just described

Image A completion handler indicating if the audio recording is saved successfully and any errors

Once the audio is recorded, you can play it back using the presentMediaPlayerControllerWithURL:options: method.

6. Select the WatchKit App scheme and run the project on a real Apple Watch. When you tap the Record Audio button, you are prompted to give permission to access the microphone on the Apple Watch (see Figure 5.4). You are also prompted for permission on your iPhone.

Image

Figure 5.4 Running the app for the first time requires granting permission to the app to use the microphone on the watch

7. Once permission is given, tap the Record Audio button again. This time, you should see the Audio Recorder (see Figure 5.5). As you have specified the recording to start automatically, the recording starts immediately and records for five seconds (also specified by you). Once the recording is done, you can tap the Save button to save the audio recording (the controller will close thereafter), or tap the Play button to review what you have just recorded.

Image

Figure 5.5 Audio recording in action

Digital Crown

In the current release of WatchKit for watchOS 2, Apple allows only the following uses of the Digital Crown:

Image Scrolling page content in third-party apps. This basically means that if your Interface Controller has more controls than the screen of the Apple Watch can display, turning the Digital Crown allows you to scroll the page up and down, revealing the controls.

Image The new Picker control in watchOS 2 allows users to select an item by turning the Digital Crown. The Picker control is discussed in Chapter 4, “Displaying and Gathering Information.”

At the moment, third-party developers are not allowed to register custom event handlers for the Digital Crown. This feature would interest a lot of developers and will likely be available in a future release of the WatchKit.

Accelerometer

The Apple Watch comes with a multitude of sensors. One of them, the accelerometer, is available to third-party developers in watchOS 2. Using the accelerometer, you can measure the acceleration experienced by the Apple Watch in three axes: x-axis, y-axis, and z-axis. With this data, you can build applications that measure the activity level of your users.

1. Using Xcode, create a new iOS App with WatchKit App project and name it UsingCoreMotion. Uncheck the option Include Notification Scene so that we can keep the WatchKit project to a bare minimum.

2. Select the Interface.storyboard file to edit it in the Storyboard Editor.

3. Drag and drop three Label controls onto the Interface Controller, as shown in Figure 5.6.

Image

Figure 5.6 Populating the Interface Controller

4. Create three outlets for the labels in the InterfaceController.swift file:

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {
    @IBOutlet var labelX: WKInterfaceLabel!
    @IBOutlet var labelY: WKInterfaceLabel!
    @IBOutlet var labelZ: WKInterfaceLabel!

5. Add the following statements in bold to the InterfaceController.swift file:

import WatchKit
import Foundation
import CoreMotion

class InterfaceController: WKInterfaceController {
    var motionManager: CMMotionManager!

    @IBOutlet var labelX: WKInterfaceLabel!
    @IBOutlet var labelY: WKInterfaceLabel!
    @IBOutlet var labelZ: WKInterfaceLabel!

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)

        // Configure interface objects here.
        motionManager = CMMotionManager()
        motionManager.accelerometerUpdateInterval = 0.1

        print(
            "Accelerometer: (motionManager.accelerometerAvailable)")
        print(
            "Gyroscope: (motionManager.gyroAvailable)")
        print(
            "Magnetometer: (motionManager.magnetometerAvailable)")
        print(
            "Device Motion: (motionManager.deviceMotionAvailable)")
    }

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

        let handler:CMAccelerometerHandler =
        {
            (data: CMAccelerometerData?, error: NSError?) -> Void in
            self.labelX.setText(
                String(format: "x - %.2f", data!.acceleration.x))
            self.labelY.setText(
                String(format: "y - %.2f", data!.acceleration.y))
            self.labelZ.setText(
                String(format: "z - %.2f", data!.acceleration.z))
        }
        motionManager.startAccelerometerUpdatesToQueue(
            NSOperationQueue.currentQueue()!,
            withHandler: handler)
        print("Start updating...")
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no
        // longer visible.
        super.didDeactivate()

        motionManager.stopAccelerometerUpdates()
        print("Stop updating...")
    }
}

With these statements,

Image You created an instance of the CMMotionManager class. The CMMotionManager class provides a range of motion services provided by iOS and watchOS. While the CMMotionManager class on iOS provides data from services, such as the accelerometer, gyroscope, magnetometer, and device motion, only the accelerometer data is exposed by the CMMotionManager class in watchOS 2. You can verify this by checking the various properties of the CMMotionManager object, such as accelerometerAvailable, gyroAvailable, and so on.

Image You created a handler block of type CMAccelerometerHandler, which takes in two parameters—accelerometer data of type CMAccelerometerData, and an optional error of type NSError. The accelerometer data consists of the acceleration experienced by the Apple Watch in the three axes: x, y, and z. To get data from the accelerometer, use the startAccelerometerUpdatesToQueue:withHandler: method of the CMMotionManager object, which takes in an NSOperationQueue object and a handler block to handle new accelerometer data. As the accelerometer data might come in at a high rate, you should not pass in the main operation queue. Instead, you should use the current operation queue.

To stop the accelerometer, call the stopAccelerometerUpdates method of the CMMotionManager object.

6. Select the WatchKit App scheme and run the project on a real Apple Watch. Observe the data displayed on the Apple Watch (see Figure 5.7). You should also see the following in the Output window:

Accelerometer: true

Gyroscope: false

Magnetometer: false

Device Motion: false

Image

Figure 5.7 Viewing the accelerometer data

Taptic Engine

The Apple Watch has a built-in vibrator, known as the Taptic Engine. This little device produces haptic feedback. Coupled with audio cues, the Taptic Engine provides an enhanced user experience. Some of the controls in the WatchKit already support the Taptic Engine. For example, both the Table and Picker controls produce haptic feedback when the user scrolls beyond the first or last item in the control.

In watchOS 2, developers can now access the Taptic Engine directly in their code. The following example shows how:

1. Using Xcode, create a new iOS App with WatchKit App project and name it TapticEngine. Uncheck the option Include Notification Scene so that we can keep the WatchKit project to a bare minimum.

2. Select the Interface.storyboard file to edit it in the Storyboard Editor.

3. Drag and drop a Picker and a Button control (set its title to Tap Me!) onto the Interface Controller, as shown in Figure 5.8.

Image

Figure 5.8 Populating the Interface Controller

4. Create an outlet and an action for the Picker control and an action for the Button control in the InterfaceController.swift file:

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {
    @IBOutlet var picker: WKInterfacePicker!

    @IBAction func pickerChanged(value: Int) {
    }

    @IBAction func btnTapMe() {
    }

5. Add the following statements in bold to the InterfaceController.swift file:

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {
    @IBOutlet var picker: WKInterfacePicker!

    var selectedHapticType = 0

    //---an array containing the haptic types---
    let hapticTypes = [
        "Notification",
        "DirectionUp",
        "DirectionDown",
        "Success",
        "Failure",
        "Retry",
        "Start",
        "Stop",
        "Click"
    ]
    @IBAction func btnTapMe() {
        WKInterfaceDevice.currentDevice().playHaptic(
            WKHapticType(rawValue: selectedHapticType)!)
    }

    @IBAction func pickerChanged(value: Int) {
        selectedHapticType = value
    }

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)

        //---an array of WKPickItems---
        var items = [WKPickerItem]()
        for hapticType in hapticTypes {
            let item = WKPickerItem()
            item.title = hapticType
            items.append(item)
        }
        //---populate the Picker with the list of haptic types---
        picker.setItems(items)
    }

In the previous code, you first created an array of haptic types supported by the Taptic Engine. You then used the Picker control to list all these haptic types so that the user can select one of them and try it out. When the user taps on the Tap Me! button, you use the playHaptic: method of the WKInterfaceDevice instance to play the selected haptic.

6. Select the WatchKit App scheme and run the project on a real Apple Watch. Select a haptic type on the Apple Watch (see Figure 5.9) and tap the Tap Me! button. You should be able to feel the watch vibrating and hear the accompanying audio cue.

Image

Figure 5.9 Trying out the Taptic Engine

Summary

In this chapter, you saw that watchOS 2 exposes several APIs for you to access the various hardware on the Apple Watch. Although not all the hardware features are exposed, this represents a good way for you to start integrating additional features into your Apple Watch apps.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.166.246