← Back to Blog

Introduction to HealthKit: Reading Steps, Weight, Height, and More

coding
mobile
tutorial

By Kevin Hou

4 minute read

Project Objectives

I was instructed to integrate HealthKit information — specifically pulling steps data — into Breathometer's upcoming app. I'm realitively new to Swift having only started a month ago, so this project was a way for me to get more familiar with the language and IDE. My task was to pull the data from HealhtKit then populate a table within a page of the app. This data could then be used for visualizations, analysis, etc. Here are my main learning goals for this project:

Authorizing and Integrating with HealthKit

Nested within the authorizeHealthKit function:

1func authorizeHealthKit(completion: ((success:Bool, error:NSError!) -> Void)!) { 2} 3

Get Healthkit information to read

1let healthKitTypesToRead = NSSet(objects: 2 HKObjectType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierDateOfBirth)!, HKObjectType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierBiologicalSex)!, 3 HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)!, 4 HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)! 5) 6

Healthkit information to write

1let healthKitTypesToWrite = NSSet(objects: 2 HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)! 3 ) 4

To actually get data from healthkit, create a function within the class. This one, for example, gets your birthdate from health kit:

1func getBirthdateFromHealthKit() -> AnyObject { 2 var birthdate: AnyObject! 3 do { 4 birthdate = try healthKitStore.dateOfBirth() 5 } catch { 6 print("No birthday listed, or permission denied") 7 birthdate = "Not Set" 8 } 9 10 return birthdate 11 } 12

More complex example

Pulls steps from Healthkit (x number of days) and show it in a table view by creating a new function within the HealthKitManager class.

Returning steps by per day for x number of days:

1func readStepsByDay(sinceDaysAgo: Int, completion: (([HKQuantitySample]!, NSError!) -> Void)!) { 2 let type: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)! 3 let currentDate = NSDate().dateWithoutTime() // Get current date 4 5 var stepData: [HKQuantitySample] = [] 6 7 for daysAgo in 1...sinceDaysAgo { 8 let startDate: NSDate = currentDate.daysAgo(daysAgo) // Set start date 9 let endDate: NSDate = currentDate.daysAgo(daysAgo - 1) // Next day 10 let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: .None) // Set parameters 11 // Getting all step counts within that day 12 let sampleQuery = HKStatisticsQuery(quantityType: type, quantitySamplePredicate: predicate, options: [.CumulativeSum], completionHandler: { (sampleQuery, result, error ) -> Void in 13 14 if let queryError = error { 15 completion(nil, queryError) // End the master function 16 print("Completion nil") 17 return 18 } 19 if completion != nil { 20 // Create KHQuantitySample for this day 21 let units = HKUnit.countUnit() 22 var quantity: HKQuantity = HKQuantity(unit: units, doubleValue: 0.0) 23 if let value = result?.sumQuantity()?.doubleValueForUnit(HKUnit.countUnit()) { 24 quantity = HKQuantity(unit: units, doubleValue: value) 25 } 26 let currentData = HKQuantitySample(type: HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)!, quantity: quantity, startDate: startDate, endDate: endDate) // Initiate HKQuantitySample 27 stepData.append(currentData) // Add data to array 28 29 if stepData.count == sinceDaysAgo { // If got all data 30 // If all days are properly fetched -> return [HKQuanitity] sample to master function 31 stepData.sortInPlace({ // Sort by time 32 $0.0.startDate.timeIntervalSinceNow > $0.1.startDate.timeIntervalSinceNow 33 }) 34 completion(stepData, nil) // Return error free 35 } 36 } 37 }) 38 39 self.healthKitStore.executeQuery(sampleQuery) // Fire the call 40 } 41 } 42

Extensions Used

1extension NSDate { 2 func daysAgo(daysAgo: Int) -> NSDate { 3 let result = -24 *60* 60 * Double(daysAgo) 4 return self.dateByAddingTimeInterval(result) 5 } 6 7 func dateWithoutTime() -> NSDate { 8 let dateFormatter = NSDateFormatter() 9 dateFormatter.dateStyle = .MediumStyle // Doesn't include time component 10 let dateToPrint: NSString = dateFormatter.stringFromDate(self) as NSString // Format into medium style string 11 let dateNoTime = dateFormatter.dateFromString(dateToPrint as String) // Get a date from midnight that day 12 return dateNoTime! 13 } 14} 15

Usage

1HealthKitManager().readStepsByDay(100, completion: { (mostRecentSteps, error) in 2 3 // Catch error 4 if( error != nil ) { 5 print("Error reading weight from HealthKit Store: \(error.localizedDescription)") // Feedback 6 return // End function 7 } 8 9 for dayCount in mostRecentSteps { 10 print(dayCount.quantity.doubleValueForUnit(HKUnit.countUnit())) 11 } 12 }) 13