Getting started with HealthKit is not difficult as long as you are not intimidated by the slew of classes, methods, and constants the framework defines. Without a proper foundation, you may miss the forest for the trees.

In this series, I aim to give you that foundation. This tutorial focuses on the basics. This includes setting up a project for HealthKit and requesting authorization. This includes setting up a project for HealthKit, requesting authorization, and a brief overview of several key classes defined by the HealthKit framework.

Project Setup

Regular readers know that I am an advocate of learning by doing. Fire up Xcode, create a new project based on the Single View Application template, and set Product Name to Meditations. Set Language to Swift and Devices to Universal.

Choosing the Single View Application Template

Configuring the Project

In this project, we create the foundation for an application to track the user's meditations. We target iPhone and iPad to find out how easy, or complex, it is to add support for HealthKit to a universal iOS application. Remember that HealthKit is not available on iPad.

Project Configuration

With Xcode properly configured, enabling HealthKit is as easy as flipping a switch in the Capabilities section of a target. Open the project in the Project Navigator, select the Meditations target from the list of targets, open the Capabilities tab at the top, and locate the HealthKit capability. Enable HealthKit for the Meditations target by toggling the switch on the right.

Enabling HealthKit for the Meditations Target

If you have correctly set up and configured Xcode, it connects to the developer portal on your behalf and creates an explicit App ID for your application.

Enabling HealthKit for the Meditations Target

You can verify this in the developer portal.

Xcode creates an explicit App ID for the application in the developer portal.

HealthKit is now enabled. Xcode has also linked the Meditations target against the HealthKit framework and created a file, Meditations.entitlements. The contents of Meditations.entitlements confirms that HealthKit is enabled for the Meditations target.

Xcode configures the project for HealthKit.

Health Store

With the project set up, we can start interacting with the HealthKit framework. Before we can read and write health data, we need to ask the user's permission for accessing their health data. As I mentioned in the first article of HealthKit Fundamentals, every type of health data is considered sensitive and the user needs to grant read and/or write access for every type of health data your application needs access to.

Creating the User Interface

Before we start writing the code for requesting authorization, we need to create a basic user interface. Open ViewController.swift and declare an outlet of type UIButton! and an action, enableHealthKit(_:).

import UIKit

class ViewController: UIViewController {

    @IBOutlet var enableHealthKitButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func enableHealthKit(sender: AnyObject) {
        ...
    }

}

Open Main.storyboard and add a button to the View Controller Scene. Set its title to Enable HealthKit and wire it up to the outlet and action we created in the ViewController class.

Create the User Interface

The class we use to interact with HealthKit is HKHealthStore. Instances of the class are long living, which means that you create one instance and use that same instance whenever you need to interact with HealthKit.

Open ViewController.swift and add an import statement for the HealthKit framework and a lazy property of type HKHealthStore.

import UIKit
import HealthKit

class ViewController: UIViewController {

    @IBOutlet var enableHealthKitButton: UIButton!

    lazy var healthStore = HKHealthStore()

    ...

}

Because some devices don't support HealthKit, we need to hide the enableHealthKitButton button if no health data is available on the device. This is easy enough. In viewDidLoad(), we ask the framework whether health data is available on the device by invoking, isHealthDataAvailable(), a class method of HKHealthStore. We show or hide the enableHealthKitButton button based on the answer we receive from the framework.

override func viewDidLoad() {
    super.viewDidLoad()

    // Show/Hide Button
    enableHealthKitButton.hidden = !HKHealthStore.isHealthDataAvailable()
}

Depending on the type of application you are creating, you can show the user a message if HealthKit is not available. This is particularly useful to avoid confusion if you are creating a universal application. Most people do not know that HealthKit not available on iPad and, therefore, they may wonder why they cannot access HealthKit on their iPad.

Requesting the User's Permission

To request authorization, we invoke requestAuthorizationToShareTypes(_:readTypes:completion:) on the HKHealthStore instance. This method accepts three parameters:

  • an optional set of HKSampleType objects
  • an optional set of HKObjectType objects
  • a completion handler with two parameters, a boolean indicating the result of the authorization request (successful or unsuccessful) and an optional error

It is important to understand that the boolean of the completion handler does not indicate whether the user granted or denied access to the requested health data types. It only informs the application whether the user responded to the application's authorization request. If the user dismissed the form by cancelling the authorization request, the boolean of the completion handler is set to false.

@IBAction func enableHealthKit(sender: AnyObject) {
    var shareTypes = Set<HKSampleType>()
    shareTypes.insert(HKSampleType.workoutType())

    var readTypes = Set<HKObjectType>()
    readTypes.insert(HKObjectType.workoutType())

    healthStore.requestAuthorizationToShareTypes(shareTypes, readTypes: readTypes) { (success, error) -> Void in
        if success {
            print("success")
        } else {
            print("failure")
        }

        if let error = error { print(error) }
    }
}

You should invoke requestAuthorizationToShareTypes(_:readTypes:completion:) before interacting with HealthKit. If the user has not granted your application read and/or write access before, she is presented with a form that lists the types of health data your application requests access to.

Requesting Authorization for HealthKit

Requesting Authorization for HealthKit

This form is not presented if the user previously granted or denied access to your application for the specified data types. Every time you request access to a data type the user has not previously granted or denied access to, the user is presented with the same form. For example, if you push an update to the App Store in which you need access to one or more additional data types, the user is presented with the same form, listing the updated set of data types your application would like to have access to.

The flow is similar to requesting authorization for showing notifications or for using the device's location services. The difference is that the user has absolute control over the type of health data your application has access to.

The user can deny your application access altogether by tapping Don't Allow. But she can also decide to give you partial read and/or write access. It is important to test that your application isn't crippled by how much access the user decides to give your application.

Users can update your application's permissions in the Settings application of the operating system. The permissions can be found under Privacy > HealthKit. If HealthKit is enabled for an application, it is listed in this section.

Permissions in the Settings Application

The first two parameters of requestAuthorizationToShareTypes(_:readTypes:completion:) are sets, instances of Swift's Set class. The first set is of type Set<HKSampleType> and the second set is of type Set<HKObjectType>. To understand what we are requesting permission for, we need to talk about the class hierarchy of a few key classes of the HealthKit framework.

Data Types

HKObjectType

The types of health data managed by HealthKit are categorized in a wide range of types. The HKObjectType class represents a type of health data. Two classes inherit directly from HKObjectType:

  • HKCharacteristicType
  • HKSampleType

An HKCharacteristicType instance represents a type of health data that does not tend to change. A person's birth date, for example, is represented by an instance of the HKCharacteristicType class.

Health data that changes over time is represented by the HKSampleType class. A common example is the weight of a person. Several classes inherit from HKSampleType. The ones that are of interest to us are:

  • HKWorkoutType
  • HKQuantityType
  • HKCategoryType

Since these classes inherit from HKSampleType, they represent a type of health data that changes over time. Instances of HKWorkoutType are used to query the HealthKit database for workouts. For example, we can use this class for asking HealthKit for the meditations the application has registered in the past week or month.

As the name of the class implies, HKQuantityType represents a type of health data that can be quantified, such as a person's height, weight, or heart rate. The type of data represented by an instance of HKCategoryType is impossible or difficult to quantify, such as sleep analysis. Instead of quantifying, this type of health data is categorized, using a predefined list of possible values.

With this information in mind, it should be clear what type of information we ask the user's permission for in the enableHealthKit(_:) action. Each set we pass to requestAuthorizationToShareTypes(_:readTypes:completion:) contains the shared HKWorkoutType instance. Put differently, we ask the user to grant the application access, read and write, to the workouts stored in the HealthKit database.

Build & Run

It is time to build and run the application. I recommend running the application on an iPhone as this gives you the best idea of how the user experiences the authorization flow.

Run the application and grant the application access to the requested data type. Stop the application in Xcode and run it again. Even though the form is shown only once, the completion handler of requestAuthorizationToShareTypes(_:readTypes:completion:) is invoked every time you run the application and tap the button.

Even if you change the application's permissions in the Settings application, the boolean that is passed to the completion handler of requestAuthorizationToShareTypes(_:readTypes:completion:) is set to true. It does not reflect the permissions the user has given the application.

What's Next?

Even though this tutorial only focused on requesting the user's permission for accessing their health data, we have learned quite a bit about the HealthKit framework. It is important to understand that health data is sensitive data and the HealthKit framework is very strict with respect to the user's privacy.

Questions? Leave them in the comments below or reach out to me on Twitter. You can download the source files of the tutorial from GitHub.