WWDC2016 Session 209

Transcript

[ Music ]
[ Applause ]
>> Good morning, and welcome
to Getting the Most
Out of HealthKit.
I'm Matt, I'm a software
engineer on the HealthKit team,
and I'll be joined on stage
shortly by my colleague Jeff.
In this session, we'll be
going over some great new
and recent additions
to the HealthKit APIs
in iOS X and watchOS 3.
Just as importantly, we'll be
covering some key features,
core concepts, and important
workflows to make sure
that you're really able to
get the most out of HealthKit.
We expect you have some
familiarity with HealthKit
if you're here watching this
session, but if you don't,
if you're here watching this
session, but if you don't,
we'll list some past sessions
at the end of this talk
that you can refer to
later to get up to speed.
But for now, let's get started.
As all of you here
know, Apple's health
and fitness ecosystem has become
a huge hit with our users.
People are getting more
fit and more healthy
because of the integration of
HealthKit and now ResearchKit
and CareKit with
your apps and devices
for iPhone and Apple Watch.
We want to make sure
that you're able
to keep creating
these great health
and fitness user experiences
that our users have come
to expect and enjoy.
So today we're going to be
covering all the things you need
to do to get these
great experiences right.
First, we'll cover
authorization,
which underpins everything
else you do with HealthKit.
Next, we'll cover the Activity
Rings API introduced in iOS 9.3
and Health Records
introduced this year in iOS X,
both of which happen to have
important implications related
to authorization.
Finally, we'll spend the
rest of the session going
over a wide range of best
practices for handling data
when you're interacting
with HealthKit.
So let's dive in.
First up is authorization.
If you've been using HealthKit
for a while, some or even most
of this section might
feel like review,
but we really recommend
you pay important attention
to the details because
they'll be important
for the stuff we cover
later in this session.
We'll sprinkle in some
best practices as well,
so keep your ears peeled.
iOS gives users full control
over their health data
and which apps can access
which parts of that data.
Before interacting
with HealthKit,
your app should request access
to the appropriate types
via HK Health Store,
and then the Health Store
in turn will present the
appropriate authorization UI
to the user if necessary.
Be aware that the user can
change permissions for your app
at any time, so you should keep
that in mind while you're
developing your app.
And just as importantly,
read authorization
And just as importantly,
read authorization
and write authorization
are completely independent.
That last bit can actually be
a little tricky, so let's look
at it in a little more detail.
Here's how read and write
authorizations work.
If the user grants you both
read and write permissions
to a given HealthKit type, then
your app can query and save data
for that HealthKit type
just like you'd expect.
If the user grants you only read
permissions for a given type,
then your app can read but
not write HealthKit data
for that type.
So far, so good.
Now, if the user grants
you write permissions
for a given type, then your
app can write data to HealthKit
for that type but
not read it back
from HealthKit for that type.
Write permissions do not
imply read permissions.
However, there's an important
exception to that point.
If your app has write
permissions
for a HealthKit type, then
you can read back data
that your app has written, just
not data from other sources.
Finally, if the user denies you
both read and write permissions
for a given type, then you can
neither query nor save data
for a given type, then you can
neither query nor save data
for that type.
And there's an important
implication
of that last point as well.
If the user denies you a
previously granted write
permission for that app,
then that means your app
can no longer read any data
from HealthKit for that type,
even data that your
app previously wrote,
so keep that in mind.
So that was all technically
review,
but there is one important
change to authorizations
in general in iOS X,
and that has to do
with usage descriptions.
Apps linked on or after iOS
X must include a description
for the user of why they're
trying to access health data.
This reinforces our principle
of user control over data.
These usage descriptions
should be declared
on your app's info.plist
file as values
for the
NSHealthShareUsageDescription
key if you're reading data
or the
NSHealthUpdateUsageDescription
key if you're writing data.
As a refresher, this is how
you request authorization.
The first thing we
want to do is make sure
The first thing we
want to do is make sure
that HealthKit is even
available on the current device.
For instance, maybe
this instance
of our app is running
on an iPad.
After we've established
that, we list the types
that we're interested
in reading and writing.
And finally, we call
request authorization
on HK Health Store, pass in
the types we're interested in,
and then handle the
response and the callback.
What if you have a watchOS app?
Authorizations are shared
between your iOS app
and its companion watchOS app,
and you can request
authorization at any time
from your iOS code
or your watchOS code.
However, the system
authorization UI can only be
presented to the
user on the phone,
so this has some important
usability implications.
For instance, if the user
is about to start a workout,
they might already have their
phone wrapped up in an armband,
and if that's the case,
they can't really easily
approve an authorization request
from your app, so this
may not be the best time
to request initial
authorization.
But there's an even
more important case.
If the user's using a Watch app,
their phone may not be nearby
If the user's using a Watch app,
their phone may not be nearby
at all, and if that's the case,
the authorization sheet
can't even be shown.
So we really recommend you
consider these important cases
when you're developing
your Watch app.
Also remember that
the response time
for the request authorization
call is not guaranteed,
so definitely don't block
any UI while you're waiting
for a response.
So clearly it's important
to get the authorization
user experience right,
and on top of that, your app
may be requesting access to some
or even many HealthKit
data types,
so that all raises a
really important question.
When should I be
requesting access to some
or all of these types?
Here are our recommendations
on that front.
First, we recommend
that you request access
to sensible groupings
of types that correspond
to logical activities
in your application.
So for instance, say
your app allows users
to track both food
intake as well
as body measurements like BMI.
If that's the case, you might
consider requesting access
If that's the case, you might
consider requesting access
to nutrition types the first
time the user tries to log food,
but then requesting access
to body measurement types
whenever the user tries
to log one of those.
One exception to that rule is
if your app has an
on-boarding flow.
If this is the case, it
might actually make sense
to request access to all
the types your app wants
to use upfront because
you're already in a context
where you can clearly explain to
the user what your app is going
to be doing with those types.
Regardless of which you
choose, we definitely recommend
that you frequently
test authorization
during development.
You can easily reset the
initial authorization flow
by deleting your app
off of the device or out
of the simulator before
building and running again
so that HealthKit
presents the user
with the initial authorization
flow all over again.
When you're doing this,
be sure to test cases
where authorization
is either delayed
or completely denied
by the user.
How does your app
function in these cases?
What capabilities are left over?
Finally, if we could
summarize authorization
in one sentence, it's this.
Consider the user experience.
Don't present obstacles
at inopportune times,
and ensure that your
flows make sense.
So we've spent a lot of time
talking about authorization.
Now let's move onto some
new features since last year
in HealthKit, starting
with Activity Rings.
Apple's developed a great health
and fitness tracking
experience for the Apple Watch.
Users love how easy it is to
track key activity metrics
and improve their day, and
now in iOS X and watchOS 3,
users can even share
their Activity Rings
with each other and compete.
Now we're giving you a great way
to incorporate this Activity
Ring experience right
into your app with the
Activity Rings API in iOS 9.3.
To do this, we start with
an HKActivitySummary object.
HKActivitySummary represents
the sum of a user's activity
HKActivitySummary represents
the sum of a user's activity
over the course of a given day.
That includes their move
calories, exercise minutes,
and stand hours, and
their goals for each.
HKActivitySummary is a
distinct type for authorization.
It's not an HKObject, but
rather a special read-only type
that you request
authorization for distinctly
from its component types.
That last part's
really important.
HKActivitySummary covers some of
the same HealthKit information
as the HealthKit types; active
energy, exercise minutes,
and stand hours, but only
on a daily aggregated basis.
So for instance, if you want
to do something more specific
like contribute to a
user's Move ring by writing
to the active energy type or
shown finer grain statistics
for activity over the course
of a given day, in that case,
you'd want to request access
to the constituent
types separately.
Now, because an ActivitySummary
object represents activity
over the course of a given
calendar day, which may
or may not correspond to a
particular 24-hour period,
we specify the day corresponding
to an activity summary using
a DateComponents object.
Let's see how that works
in the following example.
So suppose we want to fetch
the activity summary for today.
To do that, we use an
HKActivitySummaryQuery.
First, we use our calendar
to create a DateComponents
object corresponding
to today using the
required components;
era, year, month, and day.
Next, we use those components
to create a predicate object
that restricts our query
to activity summaries whose
day corresponds to today.
And then finally, we create our
query, pass in the predicate,
and then handle the, in this
case, single activity summary
that should come
back in the response.
So that's how you retrieve
activity summary data,
So that's how you retrieve
activity summary data,
but the really fun part is
showing the rings themselves.
To do that, we use
HKActivityRingView on iOS
or the analogous
WKInterfaceActivityRing
on watchOS.
They look like this, and
just like you'd expect,
they perform this
great animation
when you call
setActivitySummary, animated.
Some tips for using
HKActivityRingView
and WKInterfaceActivityRing.
Firstly, just like in the
health and activity apps on iOS
and watchOS, the rings look
best on a black background,
so we recommend display
them similarly in your apps.
Secondly, if your
app has sharing
and communication features, you
can use the writable properties
of HKActivitySummary to
construct your own object,
supply it to HKActivityRingView
or WKInterfaceActivityRing,
and thereby display another
user's rings alongside the
current user's rings
in your own app.
Finally, when you're using
HKActivitySummaryQuery,
remember to use the required
DateComponents; era, year,
month, and day in your
HKActivitySummaryQuery.
Date map can be notoriously
tricky,
so if you have any
questions about using Calendar
or DateComponents, be sure
to check out this great talk
from a prior conference.
So we've been talking a lot
about authorization
and Activity Rings.
Let's put it into
action with a quick demo.
Here on the right, we
have an up and coming app
for a medical group
called LoopHealth.
This app has some
other features,
but its main page is a dashboard
with some helpful information,
so for instance, your doctor's
name, upcoming appointments,
and some healthy tips.
LoopHealth wants their patients
to live healthier daily lives
as well, so they saw this
as a great opportunity
to incorporate Apple's
Activity Rings right
onto their dashboard.
As you can see here,
we've already dropped
an HKActivityRingView
into the storyboard
for our application,
but we haven't actually
written the code
that hooks it up with data yet.
Let's see how easy
it is to do that.
So over here in Xcode, we
have DashboardViewController.
This is the view controller
we were just looking
at in the LoopHealth app.
It's pretty empty so far,
but we do have some
helpful things filled in.
You can see right here we have
an IBOutlet set up connected
to the activityRingView
that's already in our app.
Up here we import HealthKitUI.
This is the new framework
that you can find
HKActivityRingView in on iOS.
And finally down
here, LoopHealth sets
up its app-wide HKHealthStore
in its app delegate,
so we've just set up a simple
computed property to retrieve it
for convenience when we need it.
Okay, so if we want to show an
activity summary in our app,
the first thing we need to
do is request read access
to HKActivitySummary.
And since we're reading health
data, that means we need
to include a usage description,
so let's go to our info.plist
file and add a new key.
The key we're interested
in is called NSHealthShare
UsageDescription,
in is called NSHealthShare
UsageDescription,
which is written here in plain
English as Privacy Health Share.
Perfect. And I'll drop
in a quick usage
description, and that's it.
We're all set.
Now I can go back to
DashboardViewController
and then write the code that
actually requests authorization.
Since we want to show the
initial prompt to the user
and also update our rings
whenever the user navigates
to the dashboard tab, the
perfect place to do that is
in the viewDidAppear method.
So I'll drop that in here.
And after our requisite
call to super,
notice that we call
RequestAuthorization
on HKHealthStore, pass in
the activity summary type,
and then in the response, we
call updateActivitySummary,
which we'll write to actually
fetch and update the data.
Let's go implement that now.
So here's our skeleton
for updateActivitySummary,
and what we want to
do here is create an
and what we want to
do here is create an
HKActivitySummaryQuery, request
today's activity summary,
and then set that
activity summary
on our HKActivityRingView
once we get it back.
First, let's create a
DateComponents object
corresponding to today.
Since DateComponents only
makes sense in the context
of a particular calendar,
we set the calendar object
that we use back on
the components object.
Oops, perfect.
Next, we can create
our predicate using
that components object, and
once we have the predicate,
we can create our query,
pass in the predicate,
and then in the response,
we grab the single summary
that should come back for today.
Now, once we have that summary,
all we have to do is dispatch
back to the main queue
to update our UI and then
call setActivitySummary,
animated on our Activity
Ring view.
Now that we have our
query, all we have left
to do is execute
it, and that's it.
to do is execute
it, and that's it.
So let's build and run and
see how this all looks.
Excellent.
So first thing you see is now
that we're requesting access
to activity summary,
Health is asking the user
to approve authorization.
Let's approve read access
for our activity type,
and while we're down there,
notice that at the bottom
of the screen, that usage
description that we added
for reading health data is
included and shown to the user.
It's important to note
that in a real app,
we'd want to make sure this
description is localized,
so we'd include that in our
info.plist.strings file instead.
I'll approve authorization
here, and just like that,
we see the Activity Rings
animate beautifully into place.
[ Applause ]
So that's how easy it is
to incorporate Activity Rings
right into your own app.
Be sure to check out the API.
Next, I'll turn it over to
my colleague Jeff who's going
to tell you about an
awesome new feature in iOS X.
[ Applause ]
>> Thanks, Matt.
Good morning, everyone.
My name is Joefrey Kibuule.
I work alongside Matt as
an iOS software engineer
on the Health team.
Today I have the proud
privilege to introduce
to you a new feature of
iOS X, Health Records.
Health Records provides
an easy and portable way
to carry the information
most personal
to you right on your smartphone.
Today the current experience
when users visit a medical
professional and ask
for their health records
afterwards is this.
A stack of documents
which may be cumbersome
A stack of documents
which may be cumbersome
to find a particular
piece of information.
More recently,
health organizations have been
providing their patients this.
CDs of digitized information
which may be unintuitive to use.
But now with Health
Records in iOS,
we can help solve this problem.
Through the work that
we've done in this release,
your apps can start to
unlock new possibilities
in the exchange and
interaction of Health Records.
In fact, in the U.S., adoption
of these APIs can help
health organizations comply
with new regulations
that require them
to give their patients
more control
of their own health data.
So first, an overview.
Health Records in iOS is
an umbrella term we use
to represent a variety
of different patient
visits generated
by health institutions.
Today we're adding
support specifically
Today we're adding
support specifically
for health documents.
Standard machine-readable XML
that represents specific
patient visits.
These include patient
visit summaries,
continuity of care visits,
and operative notes,
just to name a few.
We support the international
HL-7 CDA standard
for interoperability with a
variety of different providers.
These documents are available
through patient healthcare
portals online
and can be imported via Safari,
Mail, and now all of your apps.
These documents are stored just
like all other HealthKit
data safely
and securely encrypted
on your iOS device.
Next, let's talk
about permissions.
Since so much information
is contained
within each health document,
we give the user
additional controls compared
to other data types
in HealthKit.
to other data types
in HealthKit.
Access is granted on a
per-document basis in addition
to the health document
data type.
As shown on the right, we
present the UI in order
to allow the user to both view
and select the document before
granting your app access.
This UI will present it whenever
you query for a document
and a new one is available.
If you query for documents and
none are, nothing has changed,
we will not show
this UI to the user
and your query will return
immediately with results.
If you query for documents
while your application is
in the background, we will
never prompt the user UI
to grant access to
new documents.
HealthKit ensures that
the user is always aware
when they're granting
access to documents
to your apps the
first time it occurs.
Next, let's talk about how to
create a document in HealthKit.
Next, let's talk about how to
create a document in HealthKit.
When saving a document
into HealthKit,
you can save the raw XML
into the new HKCDADocumentSample
type.
We validate on creation
to ensure compliance
with the standard and will
throw errors if this fails.
We automatically extract the
title, patient, custodian,
and author names whenever the
document is saved into HealthKit
in order to make querying
for these fields faster
without needing to read
the entire document.
Let's take a look at
this example in code.
We're going to take
the documentData
and transform it
into a data object.
The origin of this XML
will typically come
from a health organization
server.
We're then going to create a
new HKCDADocumentSample passing
in that data object, setting
the appropriate dates,
and any additional metadata,
just like any other HKSample.
And then we'll save the
document to the healthStore.
And then we'll save the
document to the healthStore.
That's it.
Now your health document is
saved into HealthKit ready
to be used in other
apps or viewed directly
by the user in the Health App.
Now, let's talk about querying
for documents in HealthKit.
Since HKCDADocumentSample
is a subclass of HKSample,
existing query objects you
may be already familiar
with continue to work
just as you'd expect.
However, you need to use
the new HKDocumentQuery
in order to fetch the raw XML.
Fetching the raw XML's
expensive, and we only do
so when explicitly specified.
We provide predicate
support in order to query
for the automatically extracted
fields, and then lastly,
to remember that since
HKDocumentSamples are immutable,
updated information
to previously samples are
considered new samples.
Now, let's take a look at
an example of how to query
Now, let's take a look at
an example of how to query
for documents in HealthKit.
In this example,
we're going to query
for all the documents
a user has stored.
So first, we need to
get the document type.
We're going to pass
the CDA identifier
into the document type
forIdentifier method
on HKObjectType.
We're then going to
create an HKDocumentQuery.
You have additional
fields in order to filter
and order the documents
received back
to you the order
that you'd like.
And then we execute
the query in order
to get the HKCDADocumentSamples
back from HealthKit.
One thing I want to note in
this particular example we set
includeDocumentData to false.
Only ever set it to true
if you need the full
raw XML document data.
Now, let's talk about some
best practices when dealing
with the health documents
in HealthKit.
First, check for validation
errors whenever creating
and HKCDADocumentSample.
The errors will tell
you why we weren't able
The errors will tell
you why we weren't able
to transform your raw
XML into a usable sample.
Next, you should
verify by the Health App
that you imported
were correctly saved
and automatically
extracted fields are present.
This way, you can tell
that queries based
on those automatically extracted
fields return the correct sample
that you'd expect.
And lastly, request the raw
XML data only when you need to.
Queries that don't request,
including document data,
will return the automatically
extracted fields,
and this may be all you
need for you and your users
to uniquely identify a
document in HealthKit.
For more information on
the HL-7 CDA Standard,
visit the link on the screen.
Now, I'd like to switch gears
and offer some general
guidance on handling data.
As you know, HealthKit serves
as a central repository
where your app and other
apps can help contribute
where your app and other
apps can help contribute
to a user's record
of health data.
Your app in cloud service may
also have a direct connection
with another app
in cloud service,
and this may require some
special considerations.
So there are three main topics
that I'd like to discuss
when talking about
handling data.
First, syncing data.
Second, tracking change data.
And third, migrating data.
So first, syncing data.
You should be using
HKAnchoredObjectQuery in order
to handle processing both new
and deleted samples in order
to keep up to date
with HealthKit.
Anchors act as a
bookmark to keep track
of the last query operation
you used to fetch data.
You could save this anchor
for the next time you need
to create a new
HKAnchoredObjectQuery.
You'll open one query
for each sample type
that you're interested in
and then pass an optional
update handler in order
to continuously process new and
deleted samples without needing
to continuously process new and
deleted samples without needing
to unnecessarily
requery HealthKit.
But say for a better
user experience,
in order to have fresh UI
when your application
is first launched,
or to keep your cloud data in
sync, your application needs
to handle processing new
and deleted samples even
when it's currently not running.
That's where HKObserverQuery
working
with HKAnchoredObjectQuery
comes into play.
Let's look at an
example with a diagram.
So there are four
main steps in order
to handle background
updates split
into two phases;
setup and execution.
In the first step,
we're going to register
for background updates.
You need to do this
for every sample type
that you're interested in.
In the second step, you're
going to open an ObserverQuery.
Once set up, the ObserverQuery
will monitor for both new
and deleted samples
in HealthKit.
When new samples are generated,
that's when you have
the third step.
You'll get a callback
from the observer query
and then execute an
HKAnchoredObjectQuery in order
to fetch new and
deleted samples.
And then in the fourth step,
you'll call the observer queries
completion handler in order
to let HealthKit know
that you've processed
and delivered the
background update.
You'll then continue to cycle
between steps three and four
in order to keep up to
date with HealthKit.
Now, let's take a look at this
example one by one in code.
So in the first step, we need to
register for background updates.
Your application needs to do
this every time it's launched,
so we recommend you do it
in application
didFinishLaunching WithOptions.
You'll then grab the step's
quantity type from HKObjectType
and then pass that to HK Health
Store's enableBackgroundDelivery
for, passing in the steps type
and the frequency
you'd like updates.
Do note that background delivery
times are not guaranteed.
Do note that background delivery
times are not guaranteed.
Your application needs to pick
the longest possible frequency
it can handle in order
to preserve a user's
device's battery life.
Also note that this
API is iOS specific.
Background updates are
not available on watchOS.
In the second step, we're going
to pass the step's quantity type
to create the HKAnchored,
the HKObserverQuery.
Here we'll have a
custom updateSteps method
that we can use in order
to know, to fetch new
and deleted samples when
HealthKit detects that.
And then we're going
to execute the query.
That's it.
That completes the setup
process in order for HealthKit
to monitor new and deleted
samples in HealthKit.
So as I'm walking across stage
generating health samples,
step samples, our,
we're going to dive
into the update steps method in
order to know what we need to do
in order to grab new
and deleted samples.
So first, we're going to create
an HKAnchoredObjectQuery,
So first, we're going to create
an HKAnchoredObjectQuery,
passing in the steps type.
You'll also have predicate,
additional fields in order
to filter the particular
samples you'd like.
Then we'll call the handleSteps
method in order to process new
and deleted samples and
then update our anchor
for the next time we need to
create an HKAnchoredObjectQuery.
We then call the
completionHandler in order
to know that we've done
processing fetching new data,
and then we execute the query.
Then lastly, in step four,
we're going to call the
completionHandler given to us
from the observer query in order
to let HealthKit know
we've both received
and processed the
background update.
And that's it.
Now your application will
have a fresh UI on launch
and keep your cloud data in sync
following all of these steps.
Next, let's talk about
tracking change data.
Next, let's talk about
tracking change data.
You should be using
UUIDs in order
to keep tracking of
unique HKObjects.
A unique identifier is set
each time an object is created
and persists for the
lifetime of the sample.
Record UUIDs in your own
data store or both locally
on the device and
remotely in the cloud
so that way you could tell a
particular sample is the same.
Whenever these samples
are deleted, say,
a workout from the Health
App, you should be monitoring
for these changes to
make sure that these,
those same samples are
also deleted again locally
on the device and
remotely in the cloud.
And ensure that future sync
operations don't re-add already
deleted samples.
Now, there are two
potential problems that I'd
like to discuss when
referring talking
about how to avoid duplication.
The first is pre-populating
data.
Pre-populating data is,
I'm sorry, onboarding.
Pre-populating data is,
I'm sorry, onboarding.
Pre-populating data is a
great way during on-boarding
to save the user time
by pulling information
that may already be
stored in HealthKit.
Users have the ability to verify
data that's already in HealthKit
and change it if necessary.
However, the problem is
saving unchanged values.
Be sure only to save data again
if this is the user's intent.
Another additional potential
problem may be ingesting data
both from another
app and HealthKit.
Remember to only pick one source
of information that's most
appropriate to your application.
HealthKit has a great
privacy story
that our users have
already bought into.
However, you know what's, what
source is best for your app.
Make sure not to save
another application's data
on their behalf.
Writing only your data once
avoids duplicating data
by simplifying which
app's responsibility it is
by simplifying which
app's responsibility it is
to write it.
There is one particular
exception for this rule.
Sometimes duplication
is intentional.
For example, if data's
coming from multiple sources.
If a data, step data is
generated both on a user's phone
and his or her Apple Watch,
you can use HKStatisticsQuery
and HKStatisticsCollectionQuery
in order
to automatically
de-duplicate data by the order
of the preferred data sources
that exist in the Health App.
This way, our users get
a consistent experience
of the view of their health
data throughout our ecosystem.
Now, I want to talk
about migrating data.
Let's say that you've launched
a new Bluetooth thermometer
and app that writes
data into HealthKit.
Your application has been in
the App Store for a few days,
but your users discover
a problem.
In certain locales, instead of
saving 98 degrees Fahrenheit,
you actually save
98 degrees Celsius.
you actually save
98 degrees Celsius.
That's a bit warm.
But in this case, we know
exactly how we can migrate this
data in order to fix it.
We first need to find old
samples, write new samples,
making sure to update
UUID stored elsewhere,
and then delete old samples.
Now, a few new things
regarding the flow of data
between iPhone and Apple Watch.
Starting in iOS 9.3,
data originating
on a user's phone will
now sync back to all
of their paired Apple Watches.
Apple Watch is now a reflection
of the most recent
health data stored
within the HealthKit ecosystem.
In order to accomplish this,
samples are now periodically
pruned based off their end date
on Apple Watch.
Make sure to save samples
after HKHealthStore's earliest
permitted sample date in order
to make sure your samples
are correctly saved
to make sure your samples
are correctly saved
and synced back to
a user's device.
Lastly, sync times
are not guaranteed.
You should be saving
data on either iPhone
or Apple Watch, not both.
Now, I'm going to hand it back
off to Matt, who's going to wrap
up the rest of our session.
Thank you, everyone,
and have a great WWDC.
[ Applause ]
>> Thank you, Jeff.
Before we wrap up, I'd like to
highlight one awesome additional
feature that's brand new
in iOS X and watchOS 3.
Wheelchair support.
Accessibility is extremely
important to use here at Apple.
All of our and your users
deserve to enjoy our products
and experiences as
much as possible,
and the great activity
tracking experience we brought
to Apple Watch is no exception.
iOS X and watchOS 3 include
great new motion-tracking
iOS X and watchOS 3 include
great new motion-tracking
features that automatically
record data important
to wheelchair users.
And now you can work with
and contribute to those types
when you're interacting
with HealthKit.
First, there's a new
characteristic data type,
HKWheelchairUse that
identifies whether the user uses
a wheelchair.
The value can be yes,
no, or indeterminate.
Next, we have some new
quantity types specific
to wheelchair users.
Those include wheelchair
distance and push count,
which you can think
of like step count.
Finally, we have some new
workout types important
to wheelchair users as well.
Those include wheelchair walk
pace and wheelchair run pace.
When a wheelchair user
is using Apple Watch,
the watch automatically
records wheelchair pushes
to the new push count data type.
In addition, the stand
ring corresponding
to the stand hours data type
instead becomes roll hours.
to the stand hours data type
instead becomes roll hours.
Be aware that wheelchair
distance is only automatically
recorded during a wheelchair
workout and also be aware
that a user's wheelchair
status can change over time.
This is really important
if you're querying
for historical data.
In this case, you want to
make sure that you query
for both wheelchair types
and non-wheelchair types
so that you're not potentially
leaving out a big chunk
of the user's historical
information.
To sum up, we work really
hard to make sure that all
of our products and experiences
are accessible to everyone.
You should too.
We strongly encourage you to
reach this important segment
of our users by supporting
and contributing
to wheelchair data
types in your apps.
So we've talked about
a lot today.
Let's recap.
Authorization is
extremely important
for protecting users' privacy,
but getting the user experience
right is absolutely key.
Keep authorization in mind when
you're developing your app,
Keep authorization in mind when
you're developing your app,
and be sure to test it often.
Next, fit in with Apple's
health and fitness ecosystem
by incorporating the Activity
Rings right into your app
with the Activity Rings API.
Whenever you're interacting
with HealthKit,
take care to handle all cases
where data is synchronized,
deleted, or duplicated
properly to ensure
that your users' data
is always precise
and always what you'd expect.
And finally, don't forget to
take advantage of the great,
new features we've
introduced this year in iOS X
and watchOS 3, especially
wheelchair support,
something we think is
extremely important.
If you'd like more
information about any
of the things we
talked about today
or if you have any questions,
please visit this site.
We have lots of additional
resources available.
And don't forget to check out
our related sessions as well.
We also have these great
sessions from previous years
if you want to get up
to speed on HealthKit.
Thank you for creating
your great apps
that help users live
healthier lives
and enjoy the rest of your WWDC.
[ Applause ]