building great workout apps

163
© 2016 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple. HealthKit APIs and best practices App Frameworks #WWDC16 Session 235 Building Great Workout Apps Dash Brittain iOS Software Engineer Jorge Moriñigo iOS Software Engineer

Upload: duongkhuong

Post on 14-Feb-2017

304 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Building Great Workout Apps

© 2016 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.

HealthKit APIs and best practices

App Frameworks #WWDC16

Session 235

Building Great Workout Apps

Dash Brittain iOS Software EngineerJorge Moriñigo iOS Software Engineer

Page 2: Building Great Workout Apps
Page 3: Building Great Workout Apps
Page 4: Building Great Workout Apps
Page 5: Building Great Workout Apps
Page 6: Building Great Workout Apps

Background Running

Page 7: Building Great Workout Apps

Background Running

Workout Lifecycle

Page 8: Building Great Workout Apps

Background Running

Workout Lifecycle

Activity Rings

Page 9: Building Great Workout Apps

Background Running

Workout Lifecycle

Activity Rings

Workouts in iOS 10

Page 10: Building Great Workout Apps

Background Running

Workout Lifecycle

Activity Rings

Workouts in iOS 10

Best Practices

Page 11: Building Great Workout Apps

Getting Started

Page 12: Building Great Workout Apps

HKWorkoutSession

Page 13: Building Great Workout Apps

HKWorkoutSession

Motion and calorimetry for activity type

Page 14: Building Great Workout Apps

HKWorkoutSession

Motion and calorimetry for activity typeActivity rings

Page 15: Building Great Workout Apps

HKWorkoutSession

Motion and calorimetry for activity typeActivity ringsShow app on wake

Page 16: Building Great Workout Apps

HKWorkoutSession

Motion and calorimetry for activity typeActivity ringsShow app on wakeBackground running

Page 17: Building Great Workout Apps

Background Running NEW

Page 18: Building Great Workout Apps

Background Running

Process sensor data

NEW

Page 19: Building Great Workout Apps

Background Running

Process sensor dataLive feedback

NEW

Page 20: Building Great Workout Apps

Background Running

Process sensor dataLive feedbackQuickly update UI

NEW

Page 21: Building Great Workout Apps

// Background Running

// WatchKit Extension Info.plist

<key>WKBackgroundModes</key>

<array>

<string>workout-processing</string>

</array>

NEW

Page 22: Building Great Workout Apps

Conserve powerBackground Running NEW

Page 23: Building Great Workout Apps

Conserve powerBackground Running

Limit background work

NEW

Page 24: Building Great Workout Apps

Conserve powerBackground Running

Limit background workApp may be suspended

NEW

Page 25: Building Great Workout Apps

Conserve powerBackground Running

Limit background workApp may be suspendedMeasure background work with tools

NEW

Page 26: Building Great Workout Apps

Conserve powerBackground Running

Limit background workApp may be suspendedMeasure background work with tools• CPU Report in Xcode

NEW

Page 27: Building Great Workout Apps

Conserve powerBackground Running

Limit background workApp may be suspendedMeasure background work with tools• CPU Report in Xcode• Time Profiler in Instruments

NEW

Page 28: Building Great Workout Apps

Conserve powerBackground Running

Limit background workApp may be suspendedMeasure background work with tools• CPU Report in Xcode• Time Profiler in Instruments• Backtrace log

NEW

Page 29: Building Great Workout Apps

Starting a Workout

Page 30: Building Great Workout Apps

Authorization

Starting a Workout

Page 31: Building Great Workout Apps

Authorization Workout Configuration

Starting a Workout

Page 32: Building Great Workout Apps

Authorization Workout Configuration

Start Workout Session

Starting a Workout

Page 33: Building Great Workout Apps

Authorization

Page 34: Building Great Workout Apps

Authorization to write• Workouts

Authorization

Page 35: Building Great Workout Apps

Authorization to write• Workouts

Authorization to read• Energy burned• Distance• Heart rate

Authorization

Page 36: Building Great Workout Apps

Authorization to write• Workouts

Authorization to read• Energy burned• Distance• Heart rate

Authorization

Getting the Most Out of HealthKit Wednesday

Page 37: Building Great Workout Apps

// Workout Configuration

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

Page 38: Building Great Workout Apps

// Workout Configuration

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

Page 39: Building Great Workout Apps

// Workout Configuration

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

Page 40: Building Great Workout Apps

// Start Workout Session

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

healthStore.start(workoutSession)

Page 41: Building Great Workout Apps

// Start Workout Session

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

healthStore.start(workoutSession)

Page 42: Building Great Workout Apps

// Start Workout Session

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

healthStore.start(workoutSession)

Page 43: Building Great Workout Apps

DemoSpeedySloth: Starting a Workout

Dash BrittainiOS Software Engineer

Page 44: Building Great Workout Apps

Data Collection and Control

Jorge MoriñigoiOS Software Engineer

Page 45: Building Great Workout Apps

Ending and Saving Workout

Data Collection and Control

StartingWorkout

Page 46: Building Great Workout Apps

Ending and Saving Workout

Data Collection and Control

StartingWorkout

Start Observing Samples

Page 47: Building Great Workout Apps

Start Observing Events

Ending and Saving Workout

Data Collection and Control

StartingWorkout

Start Observing Samples

Page 48: Building Great Workout Apps

Start Observing Events

Ending and Saving Workout

Data Collection and Control

StartingWorkout

Start Observing Samples

Running

Page 49: Building Great Workout Apps

Start Observing Events

Ending and Saving Workout

Data Collection and Control

StartingWorkout

Start Observing Samples

Paused

Running

Page 50: Building Great Workout Apps

Start Observing Events

Ending and Saving Workout

Data Collection and Control

StartingWorkout

Start Observing Samples

Paused

Running

Page 51: Building Great Workout Apps

Observing Samples

Page 52: Building Great Workout Apps

Observing Samples

Open query for each data type

Page 53: Building Great Workout Apps

Observing Samples

Open query for each data typeUpdate your running totals

Page 54: Building Great Workout Apps

Observing Samples

Open query for each data typeUpdate your running totalsDisplay live data

Page 55: Building Great Workout Apps

Observing Samples

Open query for each data typeUpdate your running totalsDisplay live dataNotify user of reached goals

Page 56: Building Great Workout Apps

// Observing Samples

Page 57: Building Great Workout Apps

// Observing Samples

let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil,

options: .strictStartDate)

Page 58: Building Great Workout Apps

// Observing Samples

let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil,

options: .strictStartDate)

let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])

Page 59: Building Great Workout Apps

// Observing Samples

let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil,

options: .strictStartDate)

let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])

let queryPredicate = CompoundPredicate(andPredicateWithSubpredicates:[datePredicate,

devicePredicate])

Page 60: Building Great Workout Apps

// Observing Samples

let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil,

options: .strictStartDate)

let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])

let queryPredicate = CompoundPredicate(andPredicateWithSubpredicates:[datePredicate,

devicePredicate])

let updateHandler: (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?,

NSError?) -> Void = { query, samples, deletedObjects, queryAnchor, error in

// Process samples

}

Page 61: Building Great Workout Apps

// Observing Samples

let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil,

options: .strictStartDate)

let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])

let queryPredicate = CompoundPredicate(andPredicateWithSubpredicates:[datePredicate,

devicePredicate])

let updateHandler: (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?,

NSError?) -> Void = { query, samples, deletedObjects, queryAnchor, error in

// Process samples

}

let query = HKAnchoredObjectQuery(type: quantityType,

predicate: queryPredicate,

anchor: nil,

limit: HKObjectQueryNoLimit,

resultsHandler: updateHandler)

Page 62: Building Great Workout Apps

// Observing Samples

let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil,

options: .strictStartDate)

let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])

let queryPredicate = CompoundPredicate(andPredicateWithSubpredicates:[datePredicate,

devicePredicate])

let updateHandler: (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?,

NSError?) -> Void = { query, samples, deletedObjects, queryAnchor, error in

// Process samples

}

let query = HKAnchoredObjectQuery(type: quantityType,

predicate: queryPredicate,

anchor: nil,

limit: HKObjectQueryNoLimit,

resultsHandler: updateHandler)

query.updateHandler = updateHandler

Page 63: Building Great Workout Apps

// Observing Samples

let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil,

options: .strictStartDate)

let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])

let queryPredicate = CompoundPredicate(andPredicateWithSubpredicates:[datePredicate,

devicePredicate])

let updateHandler: (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?,

NSError?) -> Void = { query, samples, deletedObjects, queryAnchor, error in

// Process samples

}

let query = HKAnchoredObjectQuery(type: quantityType,

predicate: queryPredicate,

anchor: nil,

limit: HKObjectQueryNoLimit,

resultsHandler: updateHandler)

query.updateHandler = updateHandler

healthStore.execute(query)

Page 64: Building Great Workout Apps

Notify user of reached goalObserving Samples

Page 65: Building Great Workout Apps

Notify user of reached goalObserving Samples

Play haptic to alert user

Page 66: Building Great Workout Apps

Notify user of reached goalObserving Samples

Play haptic to alert userUpdate UI to reflect reached goal

Page 67: Building Great Workout Apps

Notify user of reached goalObserving Samples

Play haptic to alert userUpdate UI to reflect reached goal

WKInterfaceDevice.current().play(.notification)

Page 68: Building Great Workout Apps

Observing Events

Page 69: Building Great Workout Apps

Observing Events

Timestamps to highlight point in session

Page 70: Building Great Workout Apps

Observing Events

Timestamps to highlight point in sessionSome events created by your app

Page 71: Building Great Workout Apps

Observing Events

Timestamps to highlight point in sessionSome events created by your appSome events created by HealthKit

Page 72: Building Great Workout Apps

Observing Events

Timestamps to highlight point in sessionSome events created by your appSome events created by HealthKit

protocol HKWorkoutSessionDelegate

func workoutSession(_ workoutSession: HKWorkoutSession, didGenerate event: HKWorkoutEvent)

Page 73: Building Great Workout Apps

Laps and Markers NEW

Page 74: Building Great Workout Apps

Laps and Markers NEW

HKWorkoutEventType.lap

HKWorkoutEventType.marker

Page 75: Building Great Workout Apps

Create to store in a workout

Laps and Markers NEW

HKWorkoutEventType.lap

HKWorkoutEventType.marker

Page 76: Building Great Workout Apps

Create to store in a workoutTimestamps for graphs and statistics

Laps and Markers NEW

HKWorkoutEventType.lap

HKWorkoutEventType.marker

Page 77: Building Great Workout Apps

Create to store in a workoutTimestamps for graphs and statisticsLaps for equal distance partitions

Laps and Markers NEW

HKWorkoutEventType.lap

HKWorkoutEventType.marker

Page 78: Building Great Workout Apps

Create to store in a workoutTimestamps for graphs and statisticsLaps for equal distance partitionsMarkers for arbitrary points

Laps and Markers NEW

HKWorkoutEventType.lap

HKWorkoutEventType.marker

Page 79: Building Great Workout Apps

Create to store in a workoutTimestamps for graphs and statisticsLaps for equal distance partitionsMarkers for arbitrary points

Laps and Markers NEW

HKWorkoutEventType.lap

HKWorkoutEventType.marker

Page 80: Building Great Workout Apps

Pausing and Resuming

Page 81: Building Great Workout Apps

Pausing and Resuming

Users stop their activity

Page 82: Building Great Workout Apps

Pausing and Resuming

Users stop their activityPause workouts to save power and space

Page 83: Building Great Workout Apps

Pausing and Resuming

Users stop their activityPause workouts to save power and spaceIgnore data while paused

Page 84: Building Great Workout Apps

Pausing and Resuming

Users stop their activityPause workouts to save power and spaceIgnore data while pausedHealthKit responds with pause/resume events

Page 85: Building Great Workout Apps

Pausing and Resuming

Users stop their activityPause workouts to save power and spaceIgnore data while pausedHealthKit responds with pause/resume eventsAfter pause event, you will stop receiving new events

Page 86: Building Great Workout Apps

Pausing and Resuming NEW

class HKHealthStore {

func pause(_ workoutSession: HKWorkoutSession)

func resume(_ workoutSession: HKWorkoutSession)

...

}

Page 87: Building Great Workout Apps

Pausing and Resuming NEW

class HKHealthStore {

func pause(_ workoutSession: HKWorkoutSession)

func resume(_ workoutSession: HKWorkoutSession)

...

}

HKWorkoutEventType.pause

HKWorkoutEventType.resume

Page 88: Building Great Workout Apps

Motion Events for Running Workouts NEW

Page 89: Building Great Workout Apps

Motion Events for Running Workouts NEW

HKWorkoutEventType.motionPaused

HKWorkoutEventType.motionResumed

Page 90: Building Great Workout Apps

Motion Events for Running Workouts

Watch detects when motion pauses or resumes

NEW

HKWorkoutEventType.motionPaused

HKWorkoutEventType.motionResumed

Page 91: Building Great Workout Apps

Motion Events for Running Workouts

Watch detects when motion pauses or resumesStop collecting data

NEW

HKWorkoutEventType.motionPaused

HKWorkoutEventType.motionResumed

Page 92: Building Great Workout Apps

Motion Events for Running Workouts

Watch detects when motion pauses or resumesStop collecting dataDon’t need to manual pause

NEW

HKWorkoutEventType.motionPaused

HKWorkoutEventType.motionResumed

Page 93: Building Great Workout Apps

Motion Events for Running Workouts

Watch detects when motion pauses or resumesStop collecting dataDon’t need to manual pause Only for HKWorkoutActivityTypeRunning

NEW

HKWorkoutEventType.motionPaused

HKWorkoutEventType.motionResumed

Page 94: Building Great Workout Apps

DemoSpeedySloth: Data Collection and Control

Jorge MoriñigoiOS Software Engineer

Page 95: Building Great Workout Apps

Ending and Saving

Dash BrittainiOS Software Engineer

Page 96: Building Great Workout Apps

Workouts in Activity NEW

Page 97: Building Great Workout Apps

Workouts in Activity

Activity workout list

NEW

Page 98: Building Great Workout Apps

Workouts in Activity

Activity workout listActivity Move ring

NEW

Page 99: Building Great Workout Apps

Data Collection and Control

Ending and Saving

Page 100: Building Great Workout Apps

Data Collection and Control

EndWorkout Session

Ending and Saving

Page 101: Building Great Workout Apps

Data Collection and Control

EndWorkout Session

SaveWorkout

Ending and Saving

Page 102: Building Great Workout Apps

Data Collection and Control

EndWorkout Session

SaveWorkout

Add Samplesto Workout

Ending and Saving

Page 103: Building Great Workout Apps

Ending an HKWorkoutSession

Page 104: Building Great Workout Apps

Ending an HKWorkoutSession

healthStore.end(workoutSession)

Page 105: Building Great Workout Apps

Ending an HKWorkoutSession

healthStore.end(workoutSession)

func workoutSession(_ workoutSession: HKWorkoutSession,

didChangeTo toState: HKWorkoutSessionState,

from fromState: HKWorkoutSessionState,

date: Date) {

if toState == .ended {

// Workout ended, time to save

}

}

Page 106: Building Great Workout Apps

// Save Workout

let workout = HKWorkout(

Page 107: Building Great Workout Apps

// Save Workout

let workout = HKWorkout( activityType: config.activityType,

Page 108: Building Great Workout Apps

// Save Workout

let workout = HKWorkout(

start: startDate,

activityType: config.activityType,

Page 109: Building Great Workout Apps

// Save Workout

let workout = HKWorkout(

start: startDate,

end: endDate,

activityType: config.activityType,

Page 110: Building Great Workout Apps

// Save Workout

let workout = HKWorkout(

start: startDate,

end: endDate,

workoutEvents: events,

activityType: config.activityType,

Page 111: Building Great Workout Apps

// Save Workout

let workout = HKWorkout(

start: startDate,

end: endDate,

workoutEvents: events,

totalEnergyBurned: totalEnergyBurned,

activityType: config.activityType,

Page 112: Building Great Workout Apps

// Save Workout

let workout = HKWorkout(

start: startDate,

end: endDate,

workoutEvents: events,

totalEnergyBurned: totalEnergyBurned,

totalDistance: totalDistance,

activityType: config.activityType,

Page 113: Building Great Workout Apps

// Save Workout

let workout = HKWorkout(

start: startDate,

end: endDate,

workoutEvents: events,

totalEnergyBurned: totalEnergyBurned,

totalDistance: totalDistance,

metadata: [HKMetadataKeyIndoorWorkout: isIndoor])

activityType: config.activityType,

Page 114: Building Great Workout Apps

// Save Workout

let workout = HKWorkout(

start: startDate,

end: endDate,

workoutEvents: events,

totalEnergyBurned: totalEnergyBurned,

totalDistance: totalDistance,

metadata: [HKMetadataKeyIndoorWorkout: isIndoor])

healthStore.save(workout) { (success, error) in

// Workout saved

}

activityType: config.activityType,

Page 115: Building Great Workout Apps

Add Samples to Workout

Page 116: Building Great Workout Apps

Add Samples to Workout

Creates an association

Page 117: Building Great Workout Apps

Add Samples to Workout

Creates an associationQuery later for graphs

Page 118: Building Great Workout Apps

Add Samples to Workout

Creates an associationQuery later for graphsActivity Move ring credit

Page 119: Building Great Workout Apps

Add Samples to Workout

Creates an associationQuery later for graphsActivity Move ring creditMatch totals on HKWorkout

Page 120: Building Great Workout Apps

// Add Samples to Workout

healthStore.add(samples, to: workout) { (success, error) in

// Samples added

}

Page 121: Building Great Workout Apps

DemoSpeedySloth: Ending and Saving

Dash BrittainiOS Software Engineer

Page 122: Building Great Workout Apps

Workouts in iOS 10

Jorge MoriñigoiOS Software Engineer

Page 123: Building Great Workout Apps

Workouts in iOS 10

Page 124: Building Great Workout Apps

Workouts in iOS 10

Workout apps have parent iPhone application

Page 125: Building Great Workout Apps

Workouts in iOS 10

Workout apps have parent iPhone applicationWatchConnectivity for messaging when Apple Watch app is running

Page 126: Building Great Workout Apps

Workouts in iOS 10

Workout apps have parent iPhone applicationWatchConnectivity for messaging when Apple Watch app is runningBackground running

Page 127: Building Great Workout Apps

Workouts in iOS 10

Workout apps have parent iPhone applicationWatchConnectivity for messaging when Apple Watch app is runningBackground runningStart a workout from iPhone

Page 128: Building Great Workout Apps

Workouts in iOS 10

Workout apps have parent iPhone applicationWatchConnectivity for messaging when Apple Watch app is runningBackground runningStart a workout from iPhoneNo user intervention on Apple Watch

Page 129: Building Great Workout Apps

Workouts in iOS 10

HKWorkoutConfiguration

iPhone App

Page 130: Building Great Workout Apps

Workouts in iOS 10

HKWorkoutConfiguration

iPhone App Apple Watch App

Page 131: Building Great Workout Apps

Workouts in iOS 10

HKWorkoutConfigurationStart

HKWorkoutSession

iPhone App Apple Watch App

Page 132: Building Great Workout Apps

Workouts in iOS 10

HKWorkoutConfigurationStart

HKWorkoutSession

iPhone App Apple Watch App

<key>UIBackgroundModes</key>

<array>

<string>workout-processing</string>

</array>

Page 133: Building Great Workout Apps

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

workoutSession.delegate = self

healthStore.start(workoutSession)

// Starting Workout from iPhone

Page 134: Building Great Workout Apps

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

workoutSession.delegate = self

healthStore.start(workoutSession)

// Starting Workout from iPhone

Page 135: Building Great Workout Apps

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

workoutSession.delegate = self

healthStore.start(workoutSession)

// Starting Workout from iPhone

Page 136: Building Great Workout Apps

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

workoutSession.delegate = self

healthStore.start(workoutSession)

// Starting Workout from iPhone

Page 137: Building Great Workout Apps

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

workoutSession.delegate = self

healthStore.start(workoutSession)

// Apple Watch App

// Starting Workout from iPhone

// iPhone App

Page 138: Building Great Workout Apps

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

// Starting Workout from iPhone

// iPhone App

Page 139: Building Great Workout Apps

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

// Starting Workout from iPhone

}

if wcSession.activationState == .activated && wcSession.isWatchAppInstalled {

// iPhone App

Page 140: Building Great Workout Apps

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

// Starting Workout from iPhone

}

if wcSession.activationState == .activated && wcSession.isWatchAppInstalled {

// iPhone App

Page 141: Building Great Workout Apps

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

// Starting Workout from iPhone

}

if wcSession.activationState == .activated && wcSession.isWatchAppInstalled {

// iPhone App

Page 142: Building Great Workout Apps

healthStore.startWatchApp(with: workoutConfiguration) { (success, error) in

...

}

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

// Starting Workout from iPhone

// iPhone App

if wcSession.activationState == .activated && wcSession.isWatchAppInstalled {

}

Page 143: Building Great Workout Apps

healthStore.startWatchApp(with: workoutConfiguration) { (success, error) in

...

}

var workoutConfiguration = HKWorkoutConfiguration()

workoutConfiguration.activityType = .running

workoutConfiguration.locationType = .outdoor

// Starting Workout from iPhone

// iPhone App

if wcSession.activationState == .activated && wcSession.isWatchAppInstalled {

}

Page 144: Building Great Workout Apps

// Starting Workout from iPhone

Page 145: Building Great Workout Apps

// Starting Workout from iPhone

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

workoutSession.delegate = self

healthStore.start(workoutSession)

// Apple Watch App

Page 146: Building Great Workout Apps

// Starting Workout from iPhone

// Apple Watch App

func handle(_ workoutConfiguration: HKWorkoutConfiguration) {

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

workoutSession.delegate = self

healthStore.start(workoutSession)

}

Page 147: Building Great Workout Apps

// Starting Workout from iPhone

class ExtensionDelegate: WKExtensionDelegate {

}

func handle(_ workoutConfiguration: HKWorkoutConfiguration) {

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

workoutSession.delegate = self

healthStore.start(workoutSession)

}

// Apple Watch App

Page 148: Building Great Workout Apps

// Starting Workout from iPhone

class ExtensionDelegate: WKExtensionDelegate {

}

func handle(_ workoutConfiguration: HKWorkoutConfiguration) {

let workoutSession = HKWorkoutSession(configuration: workoutConfiguration)

workoutSession.delegate = self

healthStore.start(workoutSession)

}

// Apple Watch App

Page 149: Building Great Workout Apps

DemoSpeedySloth: iPhone App

Jorge MoriñigoiOS Software Engineer

Page 150: Building Great Workout Apps

Best Practices

Page 151: Building Great Workout Apps

Best Practices

Ensure Apple Watch app is functional when iPhone is unreachable

Page 152: Building Great Workout Apps

Best Practices

Ensure Apple Watch app is functional when iPhone is unreachable• Keep session running when losing connectivity

Page 153: Building Great Workout Apps

Best Practices

Ensure Apple Watch app is functional when iPhone is unreachable• Keep session running when losing connectivity• Use HealthKit distance when GPS is unavailable

Page 154: Building Great Workout Apps

Best Practices

Ensure Apple Watch app is functional when iPhone is unreachable• Keep session running when losing connectivity• Use HealthKit distance when GPS is unavailable

User should be able to begin workout on Apple Watch or iPhone

Page 155: Building Great Workout Apps

Best Practices

Ensure Apple Watch app is functional when iPhone is unreachable• Keep session running when losing connectivity• Use HealthKit distance when GPS is unavailable

User should be able to begin workout on Apple Watch or iPhoneDisplay workouts from other sources

Page 156: Building Great Workout Apps

Best Practices

Ensure Apple Watch app is functional when iPhone is unreachable• Keep session running when losing connectivity• Use HealthKit distance when GPS is unavailable

User should be able to begin workout on Apple Watch or iPhoneDisplay workouts from other sourcesDon’t display deleted workouts

Page 157: Building Great Workout Apps

Summary

Page 158: Building Great Workout Apps

Summary

Background running

Page 159: Building Great Workout Apps

Summary

Background runningContribute to Activity rings

Page 160: Building Great Workout Apps

Summary

Background runningContribute to Activity ringsStart workout from Apple Watch or iPhone

Page 161: Building Great Workout Apps

More Information

https://developer.apple.com/wwdc16/235

Page 162: Building Great Workout Apps

Related Sessions

Getting the Most out of HealthKit Wednesday

Health and Fitness with Core Motion Thursday

Introducing HealthKit WWDC 2014

Designing Accessories for iOS and OS X WWDC 2014

What’s New in HealthKit WWDC 2015

Page 163: Building Great Workout Apps