Healthkit is a powerful tool if you want to create an iOS mobile app based on health data. However, it’s not only for body measurements, fitness or nutrition; it’s also sleep analysis. In this Healthkit tutorial, I will show you how to read and write some sleep data and save them in Health app.

I’ve recently added an example written in Swift 2.0 and designed for Xcode 7.

Where to start

If you don’t know Healthkit framework, the better way to start is on Apple Developper. If you don’t have time to read all this stuff, here is a small resume.

HealthKit makes it easier to share data between apps. For developers, you no longer need to download APIs and write custom code to share with each app.

Apps can benefit by accessing a wider range of data, giving each app a more complete view of the user’s health and fitness needs.

Both HealthKit and the Health app are unavailable on iPad. The HealthKit framework cannot be used in an app extension.

You should allow your app to get access to Healthkit. In your app project, go to your current target > capabilities and switch on the HealthKit button. It will add Healthkit framework automatically to your project.

Healthkit Xcode

We are now ready to code.

Healthkit framework

“At the beginning, there was HKHealthStore.” You will use it to get access to the user’s health data. With this tool, we can share data in Health app or import them. Theses both features are based on an authorization request. That’s how it’s work in Swift :

Switf 2.0

override func viewDidLoad() {

 super.viewDidLoad()

 // create our store

 let healthStore = HKHealthStore()

 // create an object type to request an authorization for a specific category, here is SleepAnalysis

 if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) {
    
        let setType = Set<HKSampleType>(arrayLiteral: sleepType)
        healthStore.requestAuthorizationToShareTypes(setType, readTypes: setType, completion: { (success, error) -> Void in
                // here is your code
            })
        }

}

Swift 1.0

override func viewDidLoad() {

 super.viewDidLoad()

 // create our store

 let healthStore = HKHealthStore()

 // create an object type to request an authorization for a specific category, here is SleepAnalysis

 let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)

 healthStore.requestAuthorizationToShareTypes(NSSet(object: sleepType), readTypes: NSSet(object: sleepType), completion: {(success, error) -> Void in

 // here is your code

 })

}

This code will prompt a Health window to ask permission to the current user. With the completion block, you can handle success or error and get the final result.

Healthkit Introduction - Benoit Pasquier

Don’t add all objets params if you only need “share authorization” or “read authorization”. It’s really important to request only what you need because Apple can reject your app if they don’t understand your goal with these data. Choose wisely and don’t add all of them “for fun”.

Now we have permission to make some request. Let’s get some sleep data!

Read data in Health

To read some data, we need to prepare our query. My point of view is that’s very similar with CoreData framework: we define object and we can use predicates, sort descriptors or limits. Here is my code to get sleep data between two dates.

Swift 2.0

// startDate and endDate are NSDate objects

...

// first, we define the object type we want
guard let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) else {
    return
}
    
    // we create a predicate to filter our data
    let predicate = HKQuery.predicateForSamplesWithStartDate(startDate,endDate: endDate ,options: .None)
    
    // I had a sortDescriptor to get the recent data first
    
    let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
    
    // we create our query with a block completion to execute
    
    let query = HKSampleQuery(sampleType: sleepType, predicate: predicate, limit: 30, sortDescriptors: [sortDescriptor]) { (query, tmpResult, error) -> Void in
        
        if error != nil {
            
            // something happened
            return
            
        }
        
        if let result = tmpResult {
            
            // do something with my data
            for item in result {
                if let sample = item as? HKCategorySample {
                    
                    let value = (sample.value == HKCategoryValueSleepAnalysis.InBed.rawValue) ? "InBed" : "Asleep"
                    
                    print("Healthkit sleep: \(sample.startDate) \(sample.endDate) - source: \(sample.sourceRevision.source.name) - value: \(value)")
                }
            }
        }
    }
    
    
    // finally, we execute our query
    healthStore.executeQuery(query)

Swift 1.0

// startDate and endDate are NSDate objects

...

// first, we define the object type we want

let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)

// we create a predicate to filter our data

let predicate = HKQuery.predicateForSamplesWithStartDate(startDate,endDate: endDate ,options: .None)

// I had a sortDescriptor to get the recent data first

let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)

// we create our query with a block completion to execute

let query = HKSampleQuery(sampleType: sleepType, predicate: predicate, limit: 30, sortDescriptors: [sortDescriptor]) { (query, result, error) -> Void in

 if error != nil {

  // something happened

  return

 }

 if result.count > 0 {

  // do something with my data

  for sample in result as [HKCategorySample] {

   let value = (sample.value == HKCategoryValueSleepAnalysis.InBed.rawValue) ? "InBed" : "Asleep"

   println("Healthkit sleep: \(sample.startDate) \(sample.endDate) - source: \(sample.source.name) - value: \(value)")

  }

 }

}

// finally, we execute our query

healthStore.executeQuery(query)

At the end, we are able to read some sleep data from Health app. We know if it was a sleep time, or a bed time, and which app pushed it. It’s a really good thing to know because some apps are not accurate, we can filter them to ignore their data. For me, I import only connected app data from Jawbone, Withings, Fitbit or Beddit and the manual data added by the user.

Write data in Health

Swift 2.2

// startDate and endDate are NSDate objects
...

// again, we define the object type we want
guard let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) else {
   return
}
            
    // we create our new object we want to push in Health app
    
    let object = HKCategorySample(type:sleepType, value: HKCategoryValueSleepAnalysis.InBed.rawValue, startDate: startDate, endDate: endDate)
    
    // at the end, we save it
    
    healthStore.saveObject(object, withCompletion: { (success, error) -> Void in
        
        if error != nil {
            
            // something happened
            return
            
        }
        
        if success {
            print("My new data was saved in Healthkit")
            
        } else {
            // something happened again
            
        }
        
    })

Swift 1.0

// startDate and endDate are NSDate objects
...

// again, we define the object type we want

let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)

// we create our new object we want to push in Health app

let object = HKCategorySample(type:sleepType, value: HKCategoryValueSleepAnalysis.InBed.rawValue, startDate: startDate, endDate: endDate)

// at the end, we save it

healthStore.saveObject(object, withCompletion: { (success, error) -> Void in

 if error != nil {

  // something happened

  return

 }

 if success {

  println("My new data was saved in Healthkit")

 } else {

  // something happened again

 }

})

Finally, we added a new bed time in Health app. It’s really easy to read and to write some data. We just need to create a new sample object which can be saved with Healthkit.

Don’t be naive with data

Healthkit is an easy tool to get access to a lot of personal data. But don’t be naive with what you read: if an other app saved fake data in Health app, you can compromise your own when you read them.

You also must care about how you read and write: Healthkit doesn’t handle duplicated data, we can have multiple sleep data at the same time with the same start date or end date, from multiple sources.

Hope this Healthkit tutorial will help you, comment it if you have any questions.

Update – June 2016

Since I published this post last year, I received more and more emails asking about details on the implementation. I’m happy to let you know that I’ve published a HealthKitDemo app on Github. Enjoy!

healthkit demo app by Benoit Pasquier