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.
- Cheshire Half Marathon 2020 September 27, 2020With most of 2020 being a complete right off, it meant I could knuckle down and get plenty of good training in. Races should have been on the cards with Manchester marathon, Holkham triathlon and Valencia marathon being the main goals. However, like most events...
- Helvellyn September 13, 2020Hannah and I were due to get married on the 29th August and were supposed to be spending two weeks hiking around Canada. Then the coronavirus happened and all our plans went out the window. Instead of sitting home doing nothing, we decided to take...
- Uploading content, React, GraphQL, Rails and Active Storage April 26, 2020There are some great blog posts out there on all these topics but I found a lot to be out of date. The versions I’m using are below. Rails 6.0 React 16.3.1 Apollo 3.0.0 Rails To start off with we will set up our backend...
- Full-stack introduction using Rails, React, Docker and Heroku February 9, 2020Coming from mainly a mobile background, I’ve always been interested in learning new technologies that I wouldn’t use in my day to day field. I find it fascinating that especially with today’s technology it is easier for an individual to write an entire end to...
- Malaga Marathon 2019 December 21, 2019All the training these last few months had been leading up to one goal – to run a sub-3-hour marathon in the Malaga marathon. The training had been going great, and with a 1:22 in the Tatton Half, I felt like I had a great...
- Run Tatton Half Marathon 2019 November 9, 2019It’s been a while since my last run event, with the Chester half being back in May. With my marathon training now in full swing for Malaga, I was going to treat this as a fast training run. I had no real goal time in...
- Property Wrappers October 31, 2019First introduced in Swift 5.1, property wrappers allow us devs to add our own implementation details to a property before they are initialized. Currently, by delaying initialization we can declare a property as lazy, and then return our property when it’s first requested. Property wrappers...
- Shropshire Triathlon 2019 September 15, 2019A step up was on the cards for this race, as this would be my first shot at an Olympic distance triathlon after my sprint distance race that I did back in April. I did not have the best prep going into the race, as...
- Running Xcode Tests from CI August 3, 2019The ability to run a suite of tests is a great way to cut down on manual testing time, whilst still having the knowledge that any new changes have not broken the codebase. There are a number of different options when it comes to writing...
- Method Swizzling June 29, 2019When anyone mentions swizzling I automatically get worried. Method swizzling is an Objective C runtime feature which allows for the switching of method implementations. This means any function can theoretically be switch out for another one at run time. The Objective C runtime as a...