HealthKit is a brand new framework that centralizes the data storage of personal health information. Learn from the framework authors how to save, query, and interpret health data to make your apps more engaging and personal for your users.
Hello everyone. Welcome to "Introducing HealthKit." My name is Justin, I'm an iOS engineer and I'll be joined up here in a little while by my colleague, Siji.
Siji and I got to work together on HealthKit and we're really excited to show it to you today.
So, there are a ton of health and fitness apps on the app store today. They do all sorts of awesome things that let our users get healthy and stay healthy.
The problem is not a lot of these apps can share data between each other.
This makes it really hard for our users to get a cohesive view of their current health.
The few apps that can share data have to write all sorts of custom code to do so, which means you spend your time and energy working on features that aren't core to the experience of your applications.
Now, we recognize that different applications have different needs.
The way we see it, they can be grouped into three main categories. First, there are applications that perform statistical analysis using graphs or trends.
Next there are applications that let users enter information.
Last, there are applications put out by health providers that let users sync data with their personal medical record.
These are three very different scenarios, but we built HealthKit so that it can handle all of them, and we're going to show you how it does that today. Throughout this talk we're going to refer to the health app.
This is talking about the new health application that we're introducing with iOS 8.
So here's our agenda for today.
We're going to start off by walking you through the HealthKit API so you can learn how to create data, how to save data and how to ask for data as well.
Then Siji is going to come up here and give you a demo so you can see how to incorporate HealthKit into your own applications.
We'll finish things off with some HealthKit best practices.
HealthKit is a framework that lets you store and retrieve health and fitness information. So data is really important. We're going to start off by talking about what data is in HealthKit.
Storing health information in a way that can scale to work all across the world has presented some challenging problems.
Every time you step on your scale, your weight may be pounds in the United States, stones in England or kilograms in many other areas.
We didn't want you to have to do unit conversion yourself so we handle unit conversion for you right in HealthKit. Units are handled by HKUnit, and HKUnit represents a particular unit in the metric or imperial unit system.
These can be simple, such as grams, or they can be complex, like milligrams per deciliter.
Base units are classified into types.
Types define which units are compatible with each other.
For example, a mass units value can be converted to any other mass unit.
Here you can see that milligrams per deciliter is an example of a mass per volume unit.
We give you a couple of different ways to create units.
First, you can specify them explicitly in code.
Here we're creating a gram unit, and then we're creating a deciliter unit.
and we're combining the two to make a grams per deciliter unit.
This works really well for simple units, but as you can see, it gets pretty unwieldy as we expand to more complex ones. To make things easier on you, we let you specify units using unit strings like so.
So this line will create an identical unit to the three lines above it. Once you have your unit, the next thing you're going to want to do is create an HKQuantity.
An HKQuantity is a double value relative to a particular unit.
What's really cool about quantities, though, is that they can be used to do unit conversion for you.
Let's take a look at how they do that.
Here we start off by making a quantity of 20 grams.
Next we can ask for its double value in kilograms. This will give us back .02.
Unfortunately, not all units play nicely together.
If you ask a quantity for its value in a unit it's not compatible with, we're going to throw an exception.
You can always guard yourself in code by asking a quantity if it's compatible with a particular unit.
So return a BOOL.
So now that you have your quantity, the question you should be asking yourself is what is this a quantity of? To answer that question we're going to take a look at object types. Object types represent all of the different kinds of data that we can store in HealthKit.
There are over 60 different types.
Major groups of types are organized into their own classes.
All of these classes inherit from HKObjectType.
Characteristic types are characteristics of the user or traits that don't change over time.
These are things such as their blood type or date of birth.
Sample types, on the other hand, are traits of the user that do change over time.
As such, they can be sampled at a particular point in time. One kind of sample type is HKQuantityType.
These are the kinds of data that can be represented by an HKQuantity.
They are by far the most common kinds of data in HealthKit and represent everything from blood pressure to potassium to the number of steps you've taken. Last we have HKCategoryType.
Category types describe the kind of data that can be categorized into an enumeration of values.
An example of category type is sleep analysis, which is how we store sleep in HealthKit.
Let's talk about how you would create an instance of an HKObjectType. Every type has its own type identifier.
You cannot create your own types or type identifiers, but it's important to understand how they're structured so that you can use auto complete to your advantage. Here we have our identifier for heart rate.
The first part of the identifier is which object type subclass it represents.
As you can see, heart rate is a quantity type.
The second part of the identifier is the type name or what you would call the type.
Once you have your type identifier, you can pass it to one of these three constructors on HKObjectType.
It's important to note that your identifier and your constructor need to match up. So if you were to pass a category type identifier to quantity type for identifier, you're going to get back nil. So, now we have a quantity, and we have an object type. It sounds like you're ready to create some data.
All data stored in HealthKit is a subclass of HKObject.
Here we have a diagram of the HKObject class hierarchy.
You might notice this is pretty similar to the hierarchy we just saw for HKObjectType.
This is by design as object types and objects are very closely tied together.
Let's take a look at some of these different classes.
We'll start with HKQuantitySample.
This is by far the most common kind of HKObject in HealthKit. They're how we store quantities in the database. Every quantity sample has a quantity type.
This is what kind of data the sample represents.
They also have a quantity, which is the value of the sample.
It's important to note that your quantity's unit and your quantity type need to match up.
Every quantity type expects a certain kind of unit, and if there's a mismatch here then we'll throw an exception. Next we have HKCategorySample.
Category samples are very similar to quantity samples.
They have a category type, which again describes what kind of data the sample represents, and they have a value.
Now, remember the category types are the kinds of data that can be categorized into an enumeration of values.
As such, every category type is paired with a corresponding enum.
This value property must be one of the members of that enum.
If an invalid value is provided, we throw an exception just like we do for quantity samples.
Both of these inherit from HKSample. Remember that samples are the kinds of data that can be sampled at a particular point in time.
To support this, every sample has both a start date and an end date.
Why both a state date and end date you might ask? Well, for some kinds of data, such as your weight, the reading is pretty instantaneous, so your start date and end date should probably be the same.
For other kinds of data, though, your reading might take place over a period of time.
You might want to say that your heart rate was an average of 80 beats per minute over the course of 30 seconds.
Every sample also has a sample type.
This is going to be the same as your category type or quantity type depending on which subclass you choose to implement. All of these inherit from HKObject.
Every object has a UUID, which is a unique identifier that has persisted for the lifetime of the object. So you can count on this always being the same. They also have a source.
Because health information is so sensitive, we wanted to make sure that every object could identify where it came from.
Each application represents its own source, but sources can also be pieces of hardware such as a Bluetooth heart rate monitor or the step tracker in your phone. Metadata is an important part of the extensibility of an object.
You can create an object with whatever metadata you like.
Note that metadata is a regular NSDictionary except it can only store strings as keys and strings, numbers and dates as values.
We give you a few predefined metadata keys, which we think might be useful, but we encourage you to create your own metadata keys as well.
Now you may have noticed that all of the properties you saw here are read only.
This is because all data in HealthKit is immutable.
As great as it would be to go back and change my height, it really doesn't make any sense.
So, you can create objects using constructors on HKQuantitySample and HKCategorySample.
This is an example of how you might create an object to represent someone's body temperature.
First we create our quantity type, which in this case is the quantity type for body temperature.
Next, we create our quantity.
Let's say this person is feeling pretty healthy today, so their temperature is 98.6 degrees Fahrenheit. Last we create some metadata.
This piece of metadata says that the person probably took their body temperature using an ear thermometer.
We can then pass all of this to HKQuantitySamples, quantitySampleWithType, and give it a startDate and endDate of right now. Now that you have your data, what do you actually do with it? Well, to really do anything with HealthKit, the first thing you need is an HKHealthStore.
You can think of your HealthStore as your link to the database.
It lets you save objects, and as we'll find out in a little bit, it lets you ask for data as well. Remember though that you really only need one HealthStore.
They should be long-lived, and you don't really get anything out of having multiple ones floating around. So create one, hold on to it and you're done. Here's an example of us saving some data to HealthKit.
First, we create our HealthStore. Next, we create a quantity sample.
We can then pass our sample to our HealthStore using save object with completion, and voila we have officially saved data in HealthKit.
So, saving data is great, but it's not really any fun unless we can ask for it back, right? HealthKit gives you lots of ways to ask for data. The easiest information to get are characteristics of the user.
Because these don't change over time, we really only care about the current value. So you can just ask your HealthStore directly.
Here's an example of us asking our HealthStore for the user's date of birth.
This doesn't work for everything though, so to ask for the bulk of our data, we're going to need something a little more heavy duty.
This is where queries come in. Queries provide a structured mechanism for you to look at health data in a variety of ways.
All queries inherit from HKQuery.
An HKQuery has a sampleType, which is what kind of data is being queried for.
They also have a predicate.
Predicate is an NSPredicate that filters which objects are to be returned by the query.
You can create predicates in a couple of different ways.
First, you can use regular NSPredicate constructors, which you may already be used to. We give you a constant for every key path that you can use with predicates. This is a really powerful tool, but we wanted to make it easy on you to create the predicates that are most commonly used.
So we provide some convenience constructors right on HKQuery.
Note that these two methods are going to create identical predicates, so you can use whichever method you feel more comfortable with.
Now, let's say that you're working on a brand new application.
This app is for a fancy new health tracker that can measure the user's blood sugar and sync it to their phone.
Your app already saves all its data in HealthKit. Now you want to create a screen that will show the user their most recent blood sugar reading.
You can do this with HKSampleQuery. Every sample query has a limit.
This defines how many objects are going to be returned by the query.
If you don't want to limit your results, you can specify HKObjectQueryNoLimit.
They also have a sort order.
This is an array of NSSortDescriptors that dictates the order for which you will receive your result.
Here's an example of us creating a sample query to get our most recent blood sugar reading.
First, we create our quantity type, which in this case is blood sugar.
Next we create our sort descriptor.
Because we want the most recent, we want to order our results in end date in descending order.
When we create our sample query, we admit it with a sample type of blood sugar, a nil predicate because we don't want to filter our results, a limit of one because we want the one most recent, and an array containing the sort descriptor we just created.
In our result handler, because we know there's only going to be at most one result, we can just ask our results for the last object. That worked pretty well, but you realize that every time a new reading comes over from your health tracker, nothing happens. It will be really great if every time you received a new reading the display would just update all by itself.
You could create some kind of pull mechanism to do this, where every 30 seconds or so you checked what the most recent is, but it would be a lot nicer if you could just be alerted when things actually change.
This is the job of HKObserverQuery.
Observer queries are very simple. All they do is watch for changes in the database.
They're a little bit different than sample queries in the sense that they're long running. So your update handler is going to be called every time a new object is saved or removed from the database.
You might notice that in your update handler there's a completion handler. This is for a feature that we won't have time to go into today called background delivery.
If you have any questions about background delivery, please come by one of our labs. Here's us creating an observer query.
All we do is tell it that we want all blood sugar readings, and our update handler will be called every time a new blood sugar reading is saved or removed from the database. Now, let's say that your health app, that your app, is partnering with a health provider. What it's supposed to do is take all the blood sugar readings that it's created and sync them to the cloud.
You could do this using a sample query, where every time you query for all the objects in the database and figure out which ones you haven't sent yet, probably using their UUID, but this is a lot of work and it would be a lot nicer if, and it would be a waste to pull all of the objects from the database just to find out that nothing has actually changed.
This is the perfect job for HKAnchoredObjectQuery.
An anchored object query has a limit, which again defines how many results are to be returned by the query.
It also has an anchor, but what's an anchor? Well, behind the scenes, every object stored in HealthKit has its own anchor in the database.
Your query anchor says that you want everything after a certain point.
So, if you're to provide a query anchor of 0, you would get back everything.
If you were to provide a query anchor of 3, you would only get back objects 4, 5 and 6.
So in creating an anchored object query, your anchor should represent the last piece of data that you've seen.
If you haven't seen any data yet, then you can specify 0, which means you don't have an anchor.
In your callback, you will receive a new anchor, which you can then use in subsequent queries.
Here's an example of us creating an anchored object query.
At some point in time, probably during our initializer, we set our last anchor to be 0.
When we create our query, we tell it that we want all blood sugar readings that have occurred since our last anchor and we don't want to limit our results.
In our completion handler, we will get our results as well as a new anchor, which we can then use in our next query.
Let's see how this would look with some actual data.
Let's say our database has three objects in it. Since I haven't seen anything yet, we'll say my current anchor is 0.
When I run my query, I'll get back objects 1, 2 and 3, and my current anchor will now be 3.
Next, two objects are added to the database. When I run another query, I'll get back objects 4 and 5, and my current anchor will now be 5. So, I've shown you a few different queries and some situations that they're useful in, but we haven't talked about how to actually run your queries.
This is done using two methods on HKHealthStore, executeQuery and stopQuery.
ExecuteQuery tells a query to begin running.
At any point in time you can call stopQuery, which will kill your query and prevent any callbacks that haven't happened yet.
You can call stopQuery as many times as you want. It doesn't matter. But you can only execute a query once. This is because once a query is stopped, its callbacks are invalidated to prevent retained cycles.
Remember, though, that you only need to stop long-running queries, such as the observer query.
Other queries know to stop themselves once they've received their initial data. Now, all of the queries that we've talked about so far let you get actual objects from the database, but oftentimes we don't care about the individual objects themselves. What we really care about are statistics on our data. You could use a sample query and iterate over all your results summing their quantities together, but this would be a lot of work and a lot of objects in memory, considering all we really care about is the sum.
To support operations like this, statistics are a first-class citizen in HealthKit.
Statistics are handled by HKStatistics.
An HKStatisticsObject is an aggregation of multiple kinds of statistics such as sum, min, max and average. You can ask for statistics across all data or only for statistics that came from a particular source. Because we're talking about numerical analysis, statistics are only valid for quantity types. Remember though that not all types are the same.
We care about different statistics depending on what kind of data we're looking at.
We classify types as either discrete or cumulative.
Discrete types are things like your height, weight or blood pressure.
They're the kinds of data where an individual sample has all of the context you need to make sense of its quantity.
The only statistics we care about for discrete types are min, max and average.
If I were to take all of my weight readings and add them together, I wouldn't get any useful information whatsoever.
Cumulative types are things like your step count or the number of calories that you've burned.
In contrast to discrete types, I really don't care about an individual sample.
What I care about is an aggregation of samples over a period of time.
For example, that I took 7,000 steps today.
So the only statistic we care about on cumulative types is sum. So every quantity type is classified as either discrete or cumulative. In our type identifier's header, every type identifier is listed with its aggregation style. If you want to check in code though, HKQuantityType has an aggregation style property that will return either cumulative or discrete. Now back to statistics.
As you may or may not know, generating statistics on large amounts of data can be rather expensive.
Because of this, we had you tell us what you want ahead of time using a bit mask of HKStatisticsOptions.
Average, min, max and sum each have their own statistics option.
These are marked as either discrete or cumulative.
If you ask a cumulative type for discrete statistic, we're going to throw an exception.
A little bit less straightforward is separate by source.
This lets you ask in HKStatisticsObject for the statistics that came from a particular source, but why is this important? Let's say that we have two sources, Source A and Source B.
Both of these sources are writing step data to HealthKit at the same time.
Now let's say that I want to sum up my steps. I could take all of the samples in the database and add them together, which would give me 41, which is also wrong.
Because these sources were saving data at the same time, in many cases I was actually double counting.
To handle this, we let the user specify in the health app which sources are most important to them for a particular quantity type.
We then use this information to try to figure out what actually happened.
If you don't like our merge strategy, then you can always perform your own by separating by source.
Now back to your application.
Let's say that your health tracker just got an awesome new feature. Now it can count the user steps.
To support this, you want to have a new screen that shows the user their total steps for the day.
This is a sum, so you know you want to use statistics, but how do you actually generate statistics? This is done through HKStatisticsQuery.
Statistics queries take a bit mask of statistics options and return a statistics object.
So here's an example of us creating a statistics query.
First we get our quantity type, which in this case is step count. Next we perform some date calculations to only return objects that happen today. We create our statistics options, which in this case is sum, and then when we create our query, we tell it we want all steps that happen today, and we want to take their sum, and in our completion handler we'll be given an HKStatisticsObject that we can then ask for its sum quantity.
Well, you feel like a rock star right now.
Using your UI code from your blood sugar screen, you're able to bust this out in like 5 minutes.
With all of that extra time you decide it would be really cool if you could show the user their daily step count throughout the week.
How do you do this? You could execute seven statistics queries, one for each day, and once they all return use their results to draw your chart. This sounds like a lot of effort though.
This is actually the perfect job for HKStatisticsCollection.
From a high level statistics collection is just a collection of statistics objects.
It splits time up into a series of time intervals and generates statistics on each of those time intervals.
Let's take a look at how this actually works.
In this diagram, each of our gray boxes represents its own HKStatisticsObject.
We call our Delta T our interval components, and this is an NSDateComponents object.
The reason why we chose to use NSDateComponents is because when we talk about health information in a historical way, we tend to talk about it in days, weeks, months and years.
To do this properly, you need to use date components.
If you're curious about date calculations, please see last year's video, "Solutions to Common Date and Time Challenges." So, now let's say that we have an interval component of one day.
The problem is, we don't know if you want your day to be midnight to midnight, noon to noon or something completely different.
To handle this, we have you give us an anchor date.
All the anchor date does is tell you what the edge of one of your time intervals is, and that's all we need to create a collection of statistics for you.
Let's see how this would look with some actual data.
Once we get your anchor date and your interval components, we split up all of time into a series of time intervals.
We can then group data into these different time intervals and collect statistics on it, such as ask for it sum. So, this is what a statistics collection is, but how do you actually interact with this object? Because we don't force you to give us a start date or an end date, there's potentially an infinite number of statistics.
The first thing you can do is ask for an array of all of the populated statistics.
Populated statistics are the ones where their time interval actually had data in it. You can ask for the statistics that occurred on a particular date.
What this will do is find out which time period your date falls into and give you back the statistics from that time period whether or not there was any data. Last you can enumerate across all of the statistics between two dates.
This will return both populated and nonpopulated statistics objects.
So this seems like it's going to work pretty well.
All you need to do is specify an anchor date of Sunday at midnight and an interval component of one day, and that's about it. So, how do you actually create a statistics collection? This is done with an HKStatisticsCollectionQuery.
These take a bit mask of statistics options, an anchor date and an interval components object and give you back an HKStatisticsCollection. It's that easy.
Now I'm going to hand things over to Siji, so that she can show you how to incorporate HealthKit into your own applications.
Thank you, Justin. Hey everybody, good morning. I am Siji Rachel Tom and I'm one of the engineers on HealthKit. I'm really excited to be here today to give you this quick demo. So there are three things that you will see in this demo.
First you'll see how you can leverage HealthKit to retrieve existing information about the user from HealthStore.
Now this information might have been inserted into HealthStore by some other app.
Second, you'll see how you can read and write your own data objects into HealthStore, and third, you'll see some examples of the queries that Justin spoke about. Now for the purpose of this demo I'm going to walk you through making a fitness tracking app.
The goal of this app would be to track your net energy burn for a given day, and we are going to define the net energy burn as a total energy burn by activity subtracted by the total energy consumed.
With that in mind let's go take a quick look at the demo.
So we know we are going to be using HealthKit for our data storage needs, but before we can do that we need the user's permission, and this is the code that you will write to get the user's permission. So first you check whether HealthKit is supported on the current iOS device, and this is because some devices such as the iPad does not support HealthKit.
Next you create an instance of HealthStore and then use HealthStore's authorization APIs to request read and shared access to these different sets of data types.
Now I have already set up my device to be authorized, but the first time you run this piece of code, you're going to get this dialogue sheet popup that requests permissions from you. So now let's look at the app.
Since we are dealing with user's specific energy burn calculations, let's assume that we need some user-specific statistics as well. For instance the user's age, height and weight.
Now I've set up the app such that the user can enter these details, but it will be so much cooler if we can look at HealthStore and see if these values already exist, and if so, just retrieve it and display it for the user's confirmation.
So let's go and write code to do just that.
A quick note before that - I'm not doing much edit handling code in this demo, but there is sample code for this app uploaded online, and that will be a much better guide.
Now, to get the user's age, we need birth date. Birth date is a characteristic data type in HealthKit, and HealthStore has this convenient synchronous method that directly accesses user's birthday. So let's go ahead and use that method here, and once we have the birth date, it's simple to get the user's age.
Notice here I am passing the age back in the completion block.
Let's run this code and see.
Tah-dah. The age does show up, and how this happened is because earlier today I used Apple's health app to insert my birth date into Health Store.
Let's look at user height and weight next.
So, height and weight are quantity data types in HealthKit, and to get quantity samples out of HealthStore, we need to write a sample query. So let's go ahead and write our first sample query in this convenient method which will give us like the most recently quantity sample of any given data type. So this is our first sample query. Now I want a single most recent quantity sample of a given data type, and so for that I'm first going to sort my existing samples in descending order and then I'm going to specify a limit of 1 to get just the first one out of it.
I don't want to filter the data, so my predicate is nil, and the data type that I'm interested in is passed into this method. Now when this query returns, I get an array back, and this is an array of quantity samples.
In our case if there is a valid quantity sample existing in HealthStore, then you're going to get just one quantity sample back. So what we're going to do is get the quantity object associated with that quantity sample back, and then pass that in this completion block.
So let's go and write code to that.
So this gets the first object and then passes it in the completion block.
Now very important once you've written a query is please don't forget to execute the query. Okay. Now let's use this convenient method to actually get the user's height. So let's first go can call that method we just wrote.
Now user height is a quantity type with identifier height, and so I pass that in. And when the query returns I get the most recent quantity object, and as Justin was talking about earlier, a quantity object is nothing but a double value associated with a particular unit. I want to show my height in inches and so I am going to specify HKUnit inchUnit. Once I have the height, we need to pass it back to the view controller who wants it, but note that queries from HealthStore always are done on anonymous background queues, so we need to make sure we switch back to the main queue, and it should give us the height.
Now, I have already set up code to do the exact same for getting the user's weight. The only difference is that the identifier here is that for body mass, and the unit I'm interested in is pound.
Now let's run this code.
There, it works, you guys.
Let's move on. So we are interested in getting the net energy burn, which we define as the total energy burn by activity subtracted by the total energy consumed.
So let's give the user a chance to enter details about the energy consumed. I've already set up this app to show a possible list of food items consumed, but really this app doesn't do much else right now.
What I want it to be able to do is when I select an item, I want to save that item details into HealthStore, and when I come back to this main screen, I want to retrieve those details and display it. So let's go and write code to do that now. Again a quick note - so food item is a lot more rich than just calories, but for the purpose of this demo we're going to focus on saving just the calorie information.
So, I'm going to treat each food item as a quantity sample, and I want to save the food item's name and calorie information.
I'll save the name as metadata and calorie information as the quantity object associated with that quantity sample.
So let's go create our first quantity sample.
Now the data type that I'm going to save this food sample as is that of dietary calories, and so let's specify that.
The quantity object as we just mentioned will be the calorie count.
So it will be kilocalorie unit, and the double value is passed into this method, and that's our quantity object.
Now I'm just going to save this food sample with the current date and time, and as I mentioned earlier, the metadata will have the food name associated with it. Notice here that HealthKit actually provides these convenient strings to be used as keys in metadata, and so we're just going to use the food type key, and that's it. We have officially created our first sample. Let's go and save this into the database, into HealthStore, and there, done.
Awesome. So now that we have saved these items let's write code to fetch these items out and display it. We already know what we are going to use to get quantity samples out of HealthStore. Let's write a sample query. The sample type I'm interested in is that of dietary calories because that's what I saved it in as.
Now, in this case, I want to filter samples out and get only those samples that were inserted in for today. So I'll have a predicate with a start date and an end date. And start date and end date will be start of today and end of today.
Now I don't really care about the number of samples as long as I get all of them back, and I don't want to sort them, so I'm going to specify nil here.
Again, when this query returns, I'm going to get all the quantity samples back, and what I want to do is retrieve relevant information from each quantity sample, which in our case will be the food item's name and calorie information, and I'm going to package that into an array.
So that's what this code does here. Notice here that I get back the calorie information and the calorie name. I put that into this array, and once I have the array I'm going to switch back to the main queue and send it back in the completion block.
As always, let's not forget to execute the query once we have written a query.
Let's see whether this works. So I had oatmeal. Yay, that worked, and bananas.
So, now that we have entered these details, we can actually go ahead and compute net energy burn.
So we're going to define net energy burn as total energy burn subtracted by the total energy consumed. So ideally the total here would be this total energy consumed, but what about the total energy burn? So let's assume now that I'm wearing this imaginary fitness tracker device here, and every time I sync my iPhone with this fitness tracker device, it inserts active energy burn samples into HealthStore.
So, let's write code to actually get the total of all of these quantity samples.
Now I could write a sample query, get all the quantity samples that I'm interested in, and then iteratively go over it and compute the values, but really what I want to do here is use a statistics query because that's what this is meant to do.
So as always, let's have a convenience method, and then in that let's write our first statistics query.
The quantity type that I'm interested in will be passed into this method. Again, the predicate will be filtering based on start date and end date because I'm interested only in samples that are relevant for today, and start date and end date are going to be start of today and end of today.
This is the interesting part here. I'm going to specify cumulative sum because that's the quantity that I'm interested in, and when this query returns, note that we are going to get an HKStatistics object back, and what I want to do is get the quantity object associated with this statistics object back and pass it along.
So I do that and let's not forget to execute the query. Now let's actually get the total energy consumed with this query. So let's call the convenience method that we just wrote.
And the energy type that I'm interested in is that of dietary calories because that's what I saved it in as. Finally when I get the quantity back, I know that I want the unit as kilocalorie unit.
As always, let's switch back to the main queue and return this. Now I've already set up code to do the exact same for active energy burn samples that were inserted by my fitness tracker device.
The only difference here is that of the data type, which will now be active energy burn. Now let's see whether this works. Okay. I should see 255 calories here, and that works, and now let's see whether syncing works, and so I actually get my net energy burn, and there, I'm on track with my net energy burned. And that was my quick demo. So we saw in less than 10 minutes how we manage to integrate HealthKit with our app. I hope you guys enjoyed it. So the sample code for this demo is already uploaded online. Please come to our labs if you have any more questions.
Over to Justin.
Thanks so much, Siji.
As you all can see, it's really easy to incorporate HealthKit into your own applications. Next we're going to talk through some HealthKit best practices.
So, before you can use HealthKit, the first thing you need to do is let us know that you intend to use it.
To support this, we've built HealthKit right in the capabilities pane of Xcode so that you can manage it in the same way you're used to managing things like Game Center or Passbook.
Once you've given your app the HealthKit capability, the last thing you need is permission from the user to access their health data, but remember health data is really sensitive to many of our users.
We want to encourage our users to only give apps access to the information that they feel comfortable sharing.
To support this, we let users give your app permission on a per object type basis.
That way, if the only thing your application needs is step data, they don't need to give it access to what may be more sensitive kinds of data.
We also let them give your apps separate read and write permissions per object type. A user might be totally fine with your application saving data to HealthKit but might not want it reading data that came from other sources.
To request access for a set of types, you can use HKHealthStore's requestAuthorization ToShareTypes, readTypes, completion.
They should be called before you start interacting with your HealthStore so that you can ensure that the user has been given a chance to grant your app access.
Once you ask for authorization to a new type, the user is going to be presented with this authorization sheet. This is a little bit different than the authorization alert you may be used to seeing from other frameworks. This is specially designed so that the user can manage multiple permissions for your application at the same time.
To give your user the best experience possible, you should request authorization for all types you intend to use at the same time. Once you've requested authorization, the next thing you're probably going to want to do is check if you've been granted access.
In HealthKit, we let you see whether you've been granted sharing or write access to a particular type, but you can't see if you've been granted read access.
This is because for some kinds of information, knowing that the user blocked your app can be just as private as knowing the data itself.
For example, if a user were to block your app from reading their blood sugar, it might indicate that they're diabetic, and we don't want to leak this information.
You can check your authorization status for a particular type using HKHealthStore's authorizationStatusForType.
Our users are spread all around the world.
To be able to reach all of these people, it's really important that your app supports localization.
Foundation already has a set of NSFormatters that let you localize things such as numbers, dates and even byte count.
You could use a number formatter to localize a quantity's value, but you'd have to localize the unit yourself.
To help you localize some kinds of the data that we keep in HealthKit, we've added three brand new formatters to foundation: NSMassFormatter, NSLengthFormatter and NSEnergyFormatter.
These let you display things such as weight, energy and distance in a way that's pertinent to the user's current locale.
Let's take a look at how you might use NSMassFormatter.
First, we create our formatter, and we tell it that it's to be used for person mass. This is pretty important because depending on your region, you might use a different unit to measure the weight of a person than you would to measure the weight of an object. Next we create our quantity and get its double value in kilograms.
We then pass this weight in kilograms to our formatter, and it gives us a localized string, including the unit string.
Note that our formatter explicitly takes its value in kilograms.
Behind the scenes it will convert this value to the proper unit.
This works great if all you're doing is putting a value in a label, but oftentimes you need to know which unit was actually used.
To support this, you can pass an NSMassFormatter unit pointer to your formatter, and it will be filled with whatever unit was used by the formatter. So, we've talked about a lot of stuff today.
What I really want you to take away from this is that HealthKit makes it easy for you to store and share health data, which means you can spend your time doing what you do best, keeping our users happy and healthy.
Before you go, there's one thing that I would love for all of you to do after this session.
Try out HealthKit for yourself; see what you can make with it.
Check out our sample code so you can see some examples of how to properly use HealthKit.
For more information, you can reach out to one of our awesome evangelists, Dave DeLong or David Harrington.
Our sample code is already available on developer.apple.com, and we encourage you to ask questions on our Apple Developer forums.
We have one related session, which unfortunately, has already passed, but you should totally check it out online, and it has some great information on how Bluetooth devices are integrated right into HealthKit.
Thank you, and everybody have a fantastic WWDC.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.