HealthKit iOS8 by Santiapps.com
HealthKit iOS8

Intro: What it’s for?  

HealthKit is a framework that allows you to store health data to a persistent store on the users device.  We will begin with an app from Part 1 but we will take some detours that are important to understand so bare with me.

The first steps are:

– Create a tab bar application in Swift for iPhone Only

– Rename First and Second view controllers to Profile and Journal and make them UITableViewControllers

– In Capabilities turn on HealthKit

HealthKit, (HK), requires permissions to access the health store since most of this data is considered confidential.  So to do this, move over to the AppDelegate.swift.  Add this to appDidFinishLaunching method in AppDelegate:

if (HKHealthStore.isHealthDataAvailable() == true) {

self.healthStore = HKHealthStore() //needs to be var for it to work?

var writeDataTypes = self.dataTypesToWrite()

var readDataTypes = self.dataTypesToRead()

self.healthStore!.requestAuthorizationToShareTypes(writeDataTypes, readTypes: readDataTypes, completion: { (success, error) -> Void in

NSLog(“success \(error)”)

if (!success) {

NSLog(“You didn’t allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: %@. If you’re using a simulator, try it on a device.”, error)

//Present VC

return

} else {

NSLog(“success authorizing the healthstore!”)

NSLog(“writeDataTypes is%@”,writeDataTypes)

NSLog(“readDataTypes is%@”,readDataTypes)

}

// Handle success in your app here.

self.setupHealthStoreForTabBarControllers()

})

}

This requests permission from the user’s health store (on their device) in order to read and write personal data.  The user will be prompted to authorize whatever data he or she feels comfortable with.

Those NSSets containing the user data to read and write are created like so:

func dataTypesToWrite () -> (NSSet) {

var dietaryCalorieEnergyType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)

var activeEnergyBurnType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)

var heightType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)

var weightType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)

var aSet: NSSet = NSSet(objects: dietaryCalorieEnergyType, activeEnergyBurnType, heightType, weightType)

return aSet

}

We do something a little different in the read types:

func dataTypesToRead () -> NSSet {

let values = [HKQuantityTypeIdentifierDietaryEnergyConsumed,

HKQuantityTypeIdentifierActiveEnergyBurned,

HKQuantityTypeIdentifierHeight,

HKQuantityTypeIdentifierBodyMass,

HKCharacteristicTypeIdentifierDateOfBirth,

HKCharacteristicTypeIdentifierBiologicalSex]

return values.reduce(NSMutableSet()) { (var theSet, let identifier) in

if identifier != nil {

if let something = HKCharacteristicType.characteristicTypeForIdentifier(identifier) {

theSet.addObject(something)

} else if let quantity = HKQuantityType.quantityTypeForIdentifier(identifier) {

theSet.addObject(quantity)

}

}

return theSet

}

}

And finally, since we are going to be using the health store to read and write from many view controllers so we need to propagate our central health store throughout those view controllers.  So we need to use this method:

func setupHealthStoreForTabBarControllers () -> () {

var tabBarController = self.window!.rootViewController as UITabBarController

for navigationController: UINavigationController in tabBarController.viewControllers as Array {

var viewController = navigationController.topViewController

if viewController.isKindOfClass(ProfileViewController) {

var profileViewController: ProfileViewController = viewController as ProfileViewController

profileViewController.healthStore = self.healthStore!

} else if viewController.isKindOfClass(JournalViewController) {

var journalViewController: JournalViewController = viewController as JournalViewController

journalViewController.healthStore = self.healthStore!

} else if viewController.isKindOfClass(EnergyViewController) {

var energyViewController: EnergyViewController = viewController as EnergyViewController

energyViewController.healthStore = self.healthStore!

}

}

}

Now our app has access to our health store.  So recapping what we’ve done in this intro part, we basically requested permission from the health store, specified the data types to read and write and finally propagated our fully authorized health store to our child view controllers.

This is what our storyboard will look like:

Storyboard for HealtKit App Santiapps.com
Storyboard for HealthKit App

 

Here we start out with a tab bar controller with 3 UITableViewControllers as children.  The best way to do this is to drag UITableViewControllers from the Object Library in case you removed the original First and Second placeholder view controllers supplied by the template.  But you could also just drag a tableview and a cell into each of those 2 supplied view controllers and drag an additional one into the storyboard, its up to you.  Then select each of the 3, one by one, and in Editor -> Embed in Navigation Controller.

Here is the ProfileViewController:

HealthKit iOS8 App by Santiapps.com
HealthKit iOS8 App – Profile

As you can see, these are not prototype-dynamic cells but rather custom static cells.  In this case we have given the UINavBar a title and we have divided up the tableview into 3 sections: one for the users age, another for the users height and the last one for the users weight.  You can do this by setting the Sections property of the tableview in the Attributes Inspector, setting the style to Grouped and giving each section a name.

The Journal view controller is the only one that has prototype cells actually.  It looks like this:

HealthKit App iOS8 by Santiapps.com
HealthKit App iOS8 – Journal

 

Here we will simply create a tableview with dynamically populated data from a hardcoded array.  The type of cell is Detail Style and we add a button on the top right.  The idea here is that the user can select items from a list that provide a certain number of calories or joules as input.  Remember, this is the Energy Consumption tab where the user can specify his daily intake.  So of course the “Add” button calls a view controller where the user can select from a list of items:

HealthKit app iOS8 by Santiapps.com
HealthKit app iOS8 – FoodPicker

 

Ok so this one also has dynamic cells, this is the tableview that will actually be filled with the hardcoded items.  Once the user selects an item, it will be passed back to the Journal view controller.  This is the FoodPicker view controller.

Finally here is the EnergyViewController which will basically unify all data:

HealthKit app iOS8 by Santiapps.com
HealthKit app iOS8

Wait!  What do you mean all the data, so far we only have the profile data read from the health store and consumed data, what about the workout?  Well that comes in the next view controller but for now, suffice it to say that this is a static table view cell with data fed in by:
Active Energy Burned = what you burn exercising

Resting Basal Burn = what you burn just breathing

Consumed Energy = what you ate

Net Energy = your final tally for the day

 

You input the Active Energy from the Workout view controller called when you tap the “Add” button in the Energy view controller which looks like this:

HealthKit app iOS8 by Santiapps.com
HealthKit app iOS8

 

Notice something important here, we are capturing workout specific data such as laps, time, meters and pace.  This is not health data per se.  And that is precisely what HealthStore was NOT made for.  Its important to make this distinction because if you open your Health app you will not find laps, meters, km biked, tennis sets played.  That is workout-specific data and the only specific data Health app records, is Steps, because its something the iPhone can record by itself.  The Health app and the health store was conceived to record health data and it can’t very well cover all sport-specific needs.  However all that workout-specific data, laps swam, km biked or sets played, translates, somehow, into calories burned.  Now THAT is a point of convergence for all workouts and that is the kind of thing stored by the health store.  Take a look at your Health app and you will see a Health Data icon which lets you see the kinds of data the app stores.

So why is this important, well, as you will see, we will be storing energy in and energy out.  But we are still capturing laps and meters and time from the user and of course that IS important to the user.  He or she will still want to see their progress in terms of laps and time.  So we will need to incorporate CoreData in the end, in order to store that kind of data.

Ok in the next part (Part 2) we will look at the core of health data in iOS, HKObjects and how to use them!

 

Leave a Reply