Building Great Workout Apps

Session 235 WWDC 2016

HealthKit provides robust tools for building great workout apps for Apple Watch. Learn how your workout app can collect data from Watch sensors, run and analyze data in real-time in the background, and contribute to Activity rings. Gain insights into creating a great standalone Watch experience and see how to display your workouts within the Health app and the Activity app on iOS.

[ Music ]

[ Applause ]

Hello, everyone.

Welcome to Building Great Workout Apps.

You are here because you care about building the best experiences for users of your fitness apps.

Some of them are fanatical.

They're spending hours per week on their fitness, and they expect responsive, easy to use apps that provide accurate data and integrate seamlessly with Apple Health.

My name is Dash.

I'm an engineer on Apple's Health and Fitness team, and I'll be joined up here in a little while by my colleague Jorge.

Today, we're going to show you how to build great workout apps that your users will love.

Working out is an important aspect of overall health.

It can help you sleep, make good eating decisions, and clear your mind.

Many of you have worked hard to create workout apps on iOS that inspire users to track their fitness activities and reach for new health and fitness goals.

With Apple Watch, workout apps come to life within the moment heart rate, calorie burn, and activity detection, in an experience delivered exclusively from the wrist.

Today, we're going to primarily focus on how to build great workout apps for Apple Watch.

We'll start by introducing background running, a new game changing capability for workout apps on watchOS 3.

Then, we'll walk through the lifecycle of a workout from start to finish.

Along the way, we'll show you how your workout app can contribute to the user's activity ranks.

Next, we'll discuss some new APIs that we've added for workouts in iOS 10.

And finally, we'll review some best practices.

So let's get started.

At the core of every workout app is a workout session that the user can start and stop.

So we start with HKWorkoutSession.

This API is simple to use and provides automatic benefits to your workout app.

When a workout session is active, the sensors on Apple Watch will use the activity type of the session to accurately compute motion and calorimetry.

This will also enable your app to contribute to the user's activity rings.

For example, during a workout, activity will use the workout type to award exercise minutes to the user's exercise ring.

During a workout session, your app will be displayed whenever the user wakes their device.

Users will love having instant access to your app while they're using it to workout.

Finally, we're really excited to announce that workout apps in watchOS 3 can now be set up to run in the background.

Let's talk more about background running.

[ Applause ]

Background running will elevate the experience of your workout app.

Your app will be able to process data from the sensors in the background.

For example, you'll be able to receive continuous heart rate values even when your app isn't displayed on screen.

You'll also be able to provide live feedback to the user at any time during the workout session.

You can send the user haptic alerts to let them know their current progress.

This will also allow you to quickly show up to date data whenever the user just glances at their wrist.

Enabling background running is simple, just add workout-processing to the BackgroundModes in your extensions Info.plist.

Of course, to maintain high performance on Apple Watch, it's critical that you limit your background work to only do what's necessary.

If your app uses excessive CPU while in the background, watchOS may decide to suspend it.

We recommend that you use our tools to measure your app's background CPU usage.

You can use the CPU report tool in Xcode, or the time profiler in instruments.

watchOS 3 will also generate a log with a backtrace whenever your app crosses the CPU threshold.

Now that you're set up for background running, let's walk through the steps for starting a workout.

There are three steps for starting a workout.

First, you need to request authorization to access data in HealthKit.

Second, you'll create a workout configuration object representing the type of workout that you'd like to start.

And third, you'll create and start a workout session using your workout configuration.

Let's go through these one-by-one.

All workout apps will want to request authorization to write workouts to HealthKit.

This will enable workouts from your app to show up in the user's health and activity apps.

Depending on the specifics of your workout app, you may want to request authorization to read energy burned, distance, and a heart rate.

If you'd like more information on how to set up authorization, we recommend you take a look at our previous talk, Getting the Most out of HealthKit.

Workout sessions are created with a workoutConfiguration object.

The workoutConfiguration includes the workouts activity type, such as running or bicycling, and the location type, such as indoor or outdoor.

You will use the configuration object to create a workoutSession, then to start the session, simply pass it to the start method on an HK healthStore.

Let's try this out with a demo.

For just today, let's pretend we all work for the same company.

Our latest project is to build a workout app for watchOS 3 that's designed specifically for sloth lovers.

It's called SpeedySloth.

I've an Xcode project here that already has the UI built for this workout app.

Let's take a look together.

So this is the first view that the user sees when they open our app.

It has two pickers, one for activity type, which can be walking, running, or hiking.

And another for location type, which can be outdoor, indoor, or unknown.

When I press the Start button, nothing happens.

Let's fix that together.

The view that you just saw is controlled by a class called configuration interface controller.

I've a method right here called didTap StartButton, that's called whenever the user taps the Start button.

I'll fill it in now.

I'm creating a workoutConfiguration object, and I'm setting the activity type to be the currently selected activity type from that first picker.

Then I'm setting the location type to be the currently selected location type from that second picker.

I'm passing the workoutConfiguration object to a new interface controller called WorkoutInterface Controller.

WorkoutInterface Controller is responsible for managing the UI during our workout session.

It will also be responsible for Starting and stopping the workout session.

Let's take a look at WorkoutInterface Controller.

So, I'm in the awake method of WorkoutInterface Controller, and I know that we'll receive our workoutConfiguration object as a context object in this method.

Let's use it to start a workout session.

First, I'm unwrapping the context object to make sure that it's a valid workout configuration.

Then I'm using it to create a workout session by passing it to the initializer for HKWorkoutSession.

I'm setting the delegate of my workout session to be self, so we'll receive callbacks for things like state changes and errors.

Then I'm saving the current date to be our workout start date.

We'll use this later on, when we save our workout sample to HealthKit.

Next, I'm passing the workoutSession to the start method on HK healthStore.

Let's try it out.

So here we are at configuration interface controller.

I'm going to leave it at outdoor walk and I'm going to press the Start button again.

So this just opened WorkoutInterface Controller.

So I've a feeling, that our workout session did start correctly, but to be sure, let's take a look at the clock face on the device.

You'll see at the top, that there's a green running man icon.

This indicates that one of the apps on this watch has an active workout session.

The user can tap this at any time to get back to the app with the active session.

So it looks like our session did indeed start correctly.

Let's review what we just did.

We used information from the user to create a workoutConfiguration object.

Then we used that configuration to create a workout session.

And we started the session by passing it to the start method on our healthStore.

Now that we have an active workout session, we want to start collecting some data to display to the user during the workout.

To talk to you more about data collection and control, I'd like to invite up my colleague Jorge.

Thank you.

[ Applause ]

Thank you Dash.

Good morning.

My name is Jorge.

I'm a software engineer in the HealthKit Team.

So, my colleague Dash just showed you how to configure and start a workout session.

Now, we are going to continue by discussing how you can collect data and control the state of your session during a workout.

We are going to be calling data collection and control those different tasks that you need to perform from the moment you start a workout session and until you decide to end it.

Let's take a look at all these different steps.

First, we are going to be observing samples, that is, retrieving sample information from HealthKit in order to incorporate those into your workout.

Next, we are going to be observing events.

Events can be generated by HealthKit or you can detect them from your user interface.

We're going to be discussing events a little more in detail later.

Once you started those two tasks, you're in a running state.

At any point, you could choose to pause, and then resume the workout maybe several times.

And later, you will decide that you want to end your workout session.

So let's take a look at all these steps a little more in detail.

First, we said we wanted to observe samples.

The way you do this is by opening an anchor object query for each of the data tabs you're interested in.

That could be, maybe, wheelchair distance, or it could be active energy burn.

When you do this, you also will setup an updateHandler in order to receive new event, new samples arriving to HealthKit.

That will allow you to keep running totals for your workout such as maybe the total accumulate distance or total accumulated number of calories.

With that, you will be able to update your UI live.

You will also be able to display, for example, the most recent heart rate measured.

You could also notify users of certain goals, for example, whenever they reach the first mile in their run, or whenever they burn the first 100 calories in their rowing workout.

So let's now take a look at some code.

Since we are going to be using anchor object queries, the first thing that you need to do is to create a predicate for your query.

We are going to start by using the start date of your workout.

You do not want samples that the work generated before that date to count against your totals.

Next, you're going to be asking for samples from the local device.

That means the current watch.

You want to avoid, for example, getting samples that are being saved on your watch as a result of a sync operation with your iPhone.

Finally, you're going to compose those two predicates into the final predicate you're going to be using in your query.

Next, you have to set up a handler in order to process samples arriving in from HealthKit.

You will normally accumulate those samples into your totals and maybe display some updated user interface.

Now, we are ready to create the anchor object query.

You're going to be using the quantityType you're interested in, the predicate we just built, and set up your initial results handler as the handle we defined before.

You will also set up the updateHandler so you get new samples arriving to HealthKit during your workout.

Finally, you're going to execute your anchor object query.

We also mention that you would like to notify your users of certain reached goals.

For example, whenever they reach the first mile, or the first 100 calories in their workout.

The way you will normally do this, is like playing a haptic to alert the user of this situation.

When you do that, we recommend that you update your user interface so you reflect what this reached goal is.

It is very likely when a user feels the haptic, they will raise their wrist and try to see on the screen, what this haptic was about.

The way to play a haptic is by using the play method in WatchKit interface device.

Now let's talk about events.

Events are timestamps you would use to highlight certain points during your workout.

For example, you can use pause and resume events to highlight the point where your workout state changed.

Some events are going to be created by your application and saved later into your workout.

Others are going to be created by HealthKit and sent to you.

New in watchOS 3, we have the didGenerate event in workout session delegate that HealthKit will use to send events to your application.

So let's now take a look at the different types of events that we have in watchOS 3.

Laps and markers are two new events that we just introduced.

These are events that you want to create yourself to store in your workout.

This will represent timestamps you can use later for displaying your workouts in graphs or statistics.

There is a difference between laps and markers.

Laps represent events that partition your workout in equal distance portion.

For example, if you're in a running or cycling workout in a track, you would create a lap event each time the user completes a round.

Markers, on the other side, can be arbitrary points in your workout.

They don't have to be tied to distance or to any other metric.

They could represent, for example, the moment your user reached the top of a hill, or maybe that time where you saw a sloth in your way.

Now let's talk about pausing and resuming workouts.

During a workout session, your user might decide to momentarily stop the activity.

For example, they are on a run, and they might decide to stop to buy a bottle of water.

In this case, you will have some way in your user interface for your user to let you know of this situation.

When this happens, you can now call into HealthKit to pause your workout.

This will allow HealthKit to save power on your watch and space in the database.

Of course, when this happens, you want to ignore any new data that arrives to your application.

You don't want to accumulate samples to your totals while your session is paused.

HealthKit will respond to pause and resume calls by generating pause and your resume events that you will get using the workout session delegate.

It's important to know that after you receive a pause event, no new events will be generated by HealthKit, until you resume your session.

New in watchOS 3, the function you will use to pause and resume your workout are part of HKHealthStore, pause workoutSession and resume workoutSession.

Events that you will receive are paused and resumed, which you may already know from previous iOS releases.

Now let's talk about motion events.

This is new in watchOS 3.

The motion pause and motion resume events.

Your watch, during a running workout, is able to detect that the user stopped moving.

That means they are not running anymore.

And we will be able to detect whenever they start running again.

When you receive these events, you will stop collecting data into your workout, the same way as you did when the user manually paused.

However, you do not need to pause your workout session.

Note that this is implemented only for the running activity type.

So let's go back into our SpeedySloth demo application and see how we can incorporate some of the concepts we just learned about.

So I'm going to be switching to our demo.

So to recap what we saw before, we have our workout application, which already started our workout session, but we can see on the screen that calories and meters reported as zero.

We are not accumulating data yet.

So let's go into our workout and see how we can fix that.

So going back to our workout interface controller class, I'm going to be looking for the delegated callback when decision changes it state.

This is workoutSession didChangeTo toState fromState.

Here I have switch statement which is empty for all cases.

What I'm interested in right now is the running case.

Whenever we came from a notStarted state that means that the application just started the workout.

So if you are in the running case and coming from notStarted, I'm going to be calling a function called startAccumulating Data.

So let's take a look at this function.

What we want to do is to update those two labels that we saw on the screen, one for your distance, and another one for your energy burn.

So basically we are going to be starting two queries for each of those two data types.

The way you start the query is exactly what we saw during the presentation.

We first are going to be building a predicate to use in your query.

Next, we are going to be defining a handler.

In this case, I already have implemented process function that will grab those samples, accumulate those, and update my user interface.

Now, I'm ready to create my query, set up the updateHandler and execute it.

And finally, what I want to do is to save that query for later.

Because a query executed with an updateHandler, we want to stop it at some point.

So let's now go and run our application again.

Switch to the simulator.

Okay. Here we are.

So we are going to be choosing, let's say, a running outdoor workout.

There it is.

When we start, we can see that we see some numbers increasing on the screen.

This is because the watch's simulator is generating some fake samples for you whenever you start a workout session.

Great. So if you take a look at the screen, we see there are several buttons, but they are currently not doing anything.

We already discussed how you can pause and generate marker events for your app, so let's go into the code and see how we can do that.

So here I have the didTapPause ResumeButton function, but it's hooked up to the Pause button on the screen, so I'm going to be inserting some code here.

First I'm going to be checking that I have a workout session, and I'm going to be checking the state of it.

If it's running, I'm going to be pausing the workout session.

If it's paused, I'm going to be resuming it.

Good. As a result of this, your workout session will change state, so if we go back up to the delegate callback, whenever your workout session changes to some certain states, you're going to see here that the paused state is empty, so we're going to be inserting some code.

In this case I already have implemented pauseAccumulatingData, which is a function that will basically stop considering new samples as they arrive into the totals of my workout.

Similarly, we need to resume the workout at some point, so whenever our session goes back to running state, we're going to receive resumeAccumulatingData.

The other button that we have on the screen was the Marker button.

In this case, what we are wanting to do is create a markerEvent.

We just create the workout event with a marker type and the current date.

We're going to be saving that event into a local array for later saving into our workout.

And finally, I have a step here that will notify the user on the user interface.

This event just happened.

Also note that we already have implemented the didGenerate event that is a callback from our workout session delegate.

In this case, we also want to save the event generated by HealthKit into the workout events array.

So let's now run our application again.

Give it a second for it to launch.

Okay. Here it is.

I'm going to choose Walking Outdoor now.

And give it a few seconds so we can have some numbers on the screen.

You can see at the top of the screen that it says that there is an active workout.

Whenever I hit the Pause button, it goes into pause state and you can see that the numbers are not incremented for calories and meters.

I can probably resume it right now.

It goes into active state, and the numbers increase again.

You can also tap on the Marker button, which it basically displays something the user interface.

It is very likely that an actual watch you can also play a haptic for your user.

Great. So let's now switch back to our presentation.

So let's recap what we saw.

We just saw how you can use anchor object queries to get information from HealthKit and update your workout totals.

Then we implemented pause and resume events in your workout application, and finally, we show you how to create an event and save it for later.

Next step will be ending your workout session.

To talk about that, I'm going to invite my colleague Dash again on stage.

[ Applause ]

Hello again.

Ending and saving a workout is simple.

With a few steps, workouts saved from your app will integrate seamlessly with the activity and health apps.

Let's take a look at the activity app now.

Workouts saved to HealthKit will automatically show up in the activity apps workout list.

Starting in iOS 10, this includes workouts saved on the phone.

This means that a user can do a workout in an app on their phone when their watch isn't even nearby, and they'll still get credit in the activity app.

[ Applause ]

Workouts saved with energy samples will be able to contribute to the users move ring.

Users will love getting credit from working out in your app in their activity day.

Let's walk through the steps to end and save a workout so that it shows up in the user's activity app.

There are three steps to completing a workout.

First, you end the workout session.

Second, you save the workout to HealthKit.

And third, you add related samples to the saved workout, such as energy burned and distance.

Let's go through these one at a time.

To end the workout session, you simply call end on your healthStore, and pass along the workout session.

This will reset the devices sensors to their normal mode.

When HealthKit finishes ending your workout, your workout session delegate will receive a callback in its state change method.

When you see that the state has changed to ended, it's time to save the workout.

You'll create an HKWorkout sample to save to HealthKit.

The information that you create your workout with will be displayed in the user's health and activity apps.

Make sure to use the same activity type that you used on your workout configuration.

Set a startDate and an endDate for the workout, and include an array of workout events.

This array can include events like pausing and resuming, and markers or laps as Jorge discussed earlier on.

The totalEnergyBurned value is an HK quantity that represents the sum of all energy burned during the workout session.

Likewise, the totalDistance value is an HK quantity that represents all distance traveled during the workout session.

Finally, don't forget to add metadata.

Set a value for the IndoorWorkout key to indicate the location type of your workout.

You can save this workout sample to HealthKit simply by passing it to the save method on your healthStore.

When you see that it's been successfully saved, it's time to add samples to the workout.

Let's talk more about adding samples.

When you add samples to a workout, HealthKit creates an association between these samples and the workout itself.

Apps will be able to query later on for all samples that are associated with a given workout.

This will be useful if you want to graph detailed data across your workout timeline.

Adding energy samples to the workout is necessary if you want the user to get credit in their activity move ring.

Activity will use these associated energy samples to compute credit for that ring.

Finally, make sure that the totals stored previously on your workout sample match the sum of all these associated samples.

To add samples to your workout, simply pass an array of HK samples to the add samples to workout method on your healthStore.

Let's update SpeedySloth now to include ending and saving the workout.

So when we were last in the app, Jorge showed us how to collect data to display to the user.

And also how to control the event by pausing and resuming.

You may have noticed at the bottom of the Workout Interface Controller, that there's this button called End Workout.

When I tap it, it doesn't do anything yet.

So we'll fix that now.

I'm back in Workout Interface Controller, and I have a method called didTapEndButton.

Let's fill it in.

First, I'm saving the current date to be our workoutEndDate.

We'll use this in just a second when we create that workout sample.

Next, I'm calling the end method on my healthStore and passing along the workout session.

When HealthKit finishes ending the session, we can expect a callback in our state change method.

I'll go back to this state change method now.

So Jorge showed us earlier, how to handle the running and pause states.

Now we want to handle this ended state.

We want to do two things when the workout session is ended.

First, we want to stop all the queries.

This method is already implemented and it just iterates over the array of open queries and calls stop for each one.

Next, we want to save the workout.

Let's implement that now.

I'm creating a workout sample and I'm using the activity type straight from our workout configuration.

Then I'm setting the start date and the end date that we saved earlier on.

I'm including the array of workoutEvents that Jorge showed us how to build during the workout session.

I'm using the quantities for totalEnergyBurned and totalDistance that we accumulated from our data queries during the session.

And finally, I'm including a dictionary for metadata.

I'm setting the indoor workout key to have a value based on the location type of our workout configuration.

I'm passing this workout sample to the save method on my healthStore, which will save it to HealthKit.

When I see that it's successfully saved, I'm going to call addSamples toWorkout, which is a function right down here that we'll implement now.

I want to add two samples to this workout, one for totalEnergyBurned, and one for totalDistance.

For totalEnergyBurned, I'm creating a quantitySample and I'm using the quantityType active energy burned.

Then I'm passing the same totalEnergyBurned quantity that I used on my workout sample.

This means that there will be one big energy burned sample that spans the entire duration of the workout.

If you'd like to, you can create multiple smaller energy burned samples, just make sure that they sum to the same total that you set on the HKWorkout sample.

I'm doing the same thing for the totalDistanceSample.

I'm using the quantity type distanceWalkingRunning.

HealthKit has three distance types.

I'm using WalkingRunning because our workout app only handles walking and running distance.

If you're building a cycling workout app, you'd want to use cycling distance, and we've also just added a new distance type, wheelchair distance, that you would use for wheelchair based workouts.

I'm using the same total distance quantity that I used on the workout sample, and I'm setting the same workout start and end date.

So again, this is one big distance sample that spans the duration of the workout.

I'm adding these two samples to the workout by passing them in an array to the add samples to workout method on my healthStore.

When I see that they've been successfully added, I know that all my data for this workout is stored in HealthKit.

Now I want to display that workout to the user.

I'm doing this by passing the HKWorkout object to a new interface controller called SummaryInterface Controller.

SummaryInterface Controller is already built and knows how to display an HKWorkout to the user in a summary view.

I'm going to run the app again, and we'll see how to end our workout.

Let's do outdoor run again.

I'll press Start.

And we'll wait a few moments for some data to collect.

Okay I'm going to press the End Workout button now because we have some data.

Our workout session was ended and our sample was stored in HealthKit.

Here's the summary view displaying that workout sample to us now.

To make sure that it did indeed store properly in HealthKit, let's take a look at the Health app on the iPhone simulator.

Here I am in the Workouts view of the Health app.

I'm going to tap Show All Data to see a list of all of our workouts.

At the top you can see a workout that was just completed at 11:36.

That's our workout.

I'm going to tap it to see more information about it.

So you can see that this is the running workout.

It had an almost 13 second duration, and there's our start and end date.

This is all the information from our workout sample.

You can even see the metadata down here that says it's not an indoor workout.

At the bottom, you can see those two samples that we associated with the workout.

We have almost two calories for a total energy burn.

Good job everyone.

And we have a 100th of a mile.

So looks like everything did save to HealthKit correctly.

Let's review what we just did.

We ended our workout session by calling end on our healthStore.

And then we waited for our callback in our state change delegate method.

When we saw that the state changed to ended, we created a workout sample and saved it to HealthKit.

Then, we created two samples to add to the workout, one for totalEnergyBurned, and one for totalDistance.

Remember associating that energy burned sample is necessary so that the user will get credit in their activity ring.

So we've just built an entire workout app for watchOS 3.

It's that simple.

[ Applause ]

Now every app on WatchOS comes with a parent application on iOS.

So we've added some new API's in iOS 10 specifically for workout apps.

To talk to you more about these new API's I'd like to invite Jorge back up.

Thank you.

[ Applause ]

Thank you, Dash.

So you've been developing great applications for your iPhone.

So workout apps are not only about your watch.

Starting on iOS 10, we are providing some new API's you can use to implement new functionality in your iPhone applications.

We mentioned that every watch application comes with a parent iPhone app.

You can use that to your advantage to build great experiences for your users.

You might already be using WatchConnectivity for messaging between the two applications.

This is an effective way of implementing features while your watch is in a workout, and the application is running.

Now we have background running, so your application can be running all the time.

That allows you to implement great new functionalities.

However, in order for this to happen, you need to have your watch in the workout state.

So, starting with iOS 10, we're providing functionality where you can start a workout from iPhone.

That is, your watch will be in a workout state, without the user having to intervene in its user interface.

So, let's take a look at how this works.

On your iPhone application, you will select an activity type and a location, and you will create a workoutConfiguration object.

Once you have that, you send that workoutConfiguration object to the watch application.

If the watch application is not already running, it will be launched for you.

Now, the workout application can grab that configuration and start a workout session.

In order for this to work, you need to have the workout processing background mode we mentioned earlier in this presentation.

So let's now take a look at some code.

You may be familiar with this code because we saw it earlier in this presentation.

This is what you do whenever you want to start a workout on your watch.

You first create a workoutConfiguration object, and then use that to create a workoutSession and start date.

In this case, we want to separate this code in two parts.

The first part, creating the workoutConfiguration, will be executed on your iPhone application.

Creating a workoutSession and start date will be executed on the watch app.

For this to work, you need some sort of communicate between the two applications, so let's first take a look at the iPhone application code.

First, you need to check with WatchConnectivity if you have an activated session, and if you have a watch application installed.

Once you do that, you're ready to create your workoutConfiguration.

Next, in order to pass this workoutConfiguration to your watch application, you're going to be calling in the new in iOS 10 startWatchApp with workoutConfiguration, which is a new method of HK healthStore.

This will grab your workoutConfiguration and send it over to your watch app.

So let's now look at the watch application code.

What you want to do is grab that workoutConfiguration to create a session and start it.

For that, you will implement handle workoutConfiguration, which is a new function, which is part of WatchKit ExtensionDelegate.

By implementing this function, you will grab your workouConfiguration and are ready to start it.

So, let's now go back into our SpeedySloth demo app, and see how we can actually start our workout from your iPhone.

So, let's take a look at our iPhone simulator.

I'm going to create the health app.

And here I have the iPhone version of our SpeedySloth application.

So I'm going to launch it, and you see that the user interface looks very similar to what we did on the watch.

We have a user interface that allows you to select an Activity Type, and a Location Type.

And then we have a Start button that is currently not doing anything.

So let's take a look at our code and see how we can actually implement that functionality.

So I'm going to be switching to the code for the iPhone application and I have configuration view controller which is the class that handles that screen that we just saw.

In the didTapStart button, we're going to be implementing our functionality.

First, we're going to be creating our workoutConfiguration object with the selected activity types and location.

This is the exact same code that we have on the watch app.

Next, we are going to be grabbing our workoutViewController for our storyboard.

This is the UI that we're going to show while the workout is running.

We are going to set the property of workoutViewController in order to pass the workoutConfiguration we created.

And finally, we are going to be presenting that user interface.

So let's take a look at workoutViewController code, and see what it is doing.

On the viewDidLoad method, we see that the first thing that we do is to initializewatch Connectivity.

This is basically grabbing our WatchConnectivity session and make sure it's initialized.

Then, we are going to be calling into startWatchApp function.

The startWatchApp function is going to first check that we have a valid workoutConfiguration that we have a valid WatchConnectivity session, and then this is the same code that we saw in our slides.

We first check that the connectivity session is activated and that we have our watch app installed.

Finally, we are going to be calling in to startWatchApp with workoutConfiguration.

Great. So now we have to go into our WatchKit extension to make sure that we grab that workoutConfiguration object.

So, we are going to be moving into the workout into the ExtensionDelegate for the watch app, and using the same code to handle the workoutConfiguration.

When we do that, we want to wrap that workoutConfiguration in a context object and pass to the Workout InterfaceController.

This is the same user interface that we were showing whenever you started a workout on the watch.

One other thing that we want to note here, if we're going to Workout InterfaceController, whenever an application let me see whenever I said an active workout session changes state.

We're going to be calling this updateState function.

This is something that we already have implemented in our code, which is basically going to grab the current state of the session, and send in through WatchConnectivity to the iPhone application.

So, let's now run our code switching to the iPhone app, and take a look.

There it is.

So we are going to be selecting outdoor walking workout.

When I press the Start button, you see the workout session is starting.

If you go back to the watch simulator, you see that the app launch, and it's now workout state.

Going back to the iPhone app, you can see that now it is in running state, if you missed that, I can probably pause the workout session, and you see that we updated state on the other side.

And we can probably end it, and now the state of the workout also changed on the other side.

[ Applause ]

So to recap, we just saw how you can put some code in your iPhone application, in order to put your watch in a workout state, and at no point there was any user intervention needed on the watch.

So, let's now talk about some basic practices we will like you to follow whenever you are developing workout applications.

The first is that we want you to make sure that your watch application is still functional whenever you reach sorry, whenever you miss reach-ability from your iPhone.

This is, for example, a user might expect to start a running workout session, leave their house, and go for a run, leave their phone behind.

In that situation, we do not want you to stop the workout.

So, the first thing that you need to do is to keep your workout session active, even when you lose connectivity with your iPhone.

Another interesting point in this scenario, is that you can use HealthKit distance because HealthKit is able to generate distance samples even when you don't have a GPS available.

Also, we said that your user can start a workout from either their iPhone or the Apple Watch.

I would advise if you give your user the choice, on which device they want to start the workout from.

Other advice involves application display historic workouts.

If you do this, display workouts from all sources, not only your own app.

We want you to show workouts generating by other applications too.

If you're doing so, don't forget to observe deleted objects.

You do not want to keep displaying workouts that were removed from HealthKit's database.

So, to finalize today, there are three things that we want you to take from this presentation.

First, we learned about background running, which is a great way of keeping your application updated constantly, and having your user interface be responsive.

Second, you learned that you can contribute to your activity rings by adding samples to your workout, either on your watch, or your iPhone application.

And finally, third, we learned how you can start a workout from either your watch or your iPhone.

So we would like you to go home or to your office, take a look at your code, and apply what you learned today to implement some great new features in your app.

For more information, you can go to this website where you can see videos from this presentation.

We have some related sessions.

One from HealthKit and another one from Core Motion this year.

If you missed them, you can go online and watch them.

And here are also a few presentations from previous years related to this topic.

This is all for today.

Thank you very much.

Enjoy the rest of your day.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US