This post carries on from Importing File Data, where we looked at how to import a GPX file, and parse it into useable objects. If you’ve not read the first part I would recommend doing so before continuing.
For a quick recap, we ended the last post with an array of Workout objects. The Workout objects consist of a name, start date and an array of track point data. Again, all this information comes from the GPX file we imported in the previous post.
Before we can read, or in our case, write to HealthKit, we need to request authorisation to do so. This requires us to call requestAuthorization, and pass in the values which we want permissions for. Below is the overlay iOS presents when you request for permissions.
In this example, we have asked to write data for four different pieces of data.
Heart Rate – This is pretty self explanatory, we want to write the heart rate data to a workout so we have to request permission for that.
Walking + Running Distance – Again this very straightforward. This permission allows us to write the total distance for a running or walking activity.
Workout Route – To store location data, we need to enable this permission. It allows us to store the longitude and latitude of a workout, which is what apps use to draw a map of the route.
Workouts – Finally the workouts permissions allows us to save the type of workout, whether it be running, cycling, swimming etc.
It is very simple to request access, all we need to do it call requestAuthorization on an instance of HKHealthStore for example.
One thing to note. The completion block is returned on the background queue, so you will need to dispatch to the main thread once ready to update the UI.
We now have all the permissions in place to start writing to Health Kit. All that is left to do is to convert our model objects to HealthKit readable objects, and add them to the health store.
To save workouts to HealthKit we first need to convert our Workout objects into a HealthKit object called HKWorkout. HKWorkout contains lots of information about the workout, however this is were it gets a bit confusing. Certain types of data, such as heart rate are stored as sample data (HKSample) in the HealthKit store, and then linked to a workout after. The workout route also needs to created separately, and then linked to a workout using HKWorkoutRouteBuilder, which I will pick up later; but for now lets first create our HKWorkout and add it to the store.
First, to create the HKWorkout instance we need to use the initialiser which best suits our example. Annoyingly Apple have not added any default parameters to the HKWorkout initialisers so instead of only passing in the data we want, we just have to pass nil into the values we don’t need.
Once we have the startDate, endDate and totalDistance, we can construct an instance of HKWorkout using the above initialiser. Notice we have to provide an activity type. This data is not part of a GPX file so some form of user input is required here. For my example I bring up an action sheet to ask the user what activity they were doing e.g run, bike, swim etc, and this is how I would populate the activityType within the initialiser. For this example I have just set it to running.
Once the workout is initialised, we can then add it to HealthKit. Like with the authorisation, all we have to do is call a function on HKHealthStore. In this case it’s just save(:), whilst passing in the workout we created before.
Its that simple. Once your workout is saved it will appear within HealthKit as well as the Activity app.
Adding Sample Data
We mentioned before, that not all data is stored in HKWorkout, and some data is linked separately. In our case we need to create samples and location data for both the heart rate and route information. It is in this logic where will also calculate the total distance.
To calculate the total distance, as well as create heart rate and location data for all our track points, we will need to loop through all the track points and create individual sample data for each one. I will show you how I achieved this in the code below.
This will collect heart rate samples for all the track point data. Before we link them to our workout, we first need to create the location and distance data. To do this we still need to be in the forEach loop above. So just below the code that creates the heart rate samples we need to add some extra code.
We now have all the location data ready to be linked to the workout, we just need to create the samples for the total distance. So again inside the forEach loop we need to add some more code.
I know that’s a lot of code, but now we have all our samples, location data and total distance ready to link to our workout. Incase you missed it, the totalDistance variable we set up above was the same one we used to initialise the HKWorkout object before.
The final phase is to add the samples to the workout and then finish the route builder. Both of these steps can only be done once a workout as been stored within HealthKit.
This is perfect as we already stored our workout in HealthKit earlier on.
Once the samples have been added, and finishRoute: has been called on the route builder, your workout in HealthKit will now be populated with all that extra information.
I hope that gives you a good insight into how to add data into HealthKit.