In this tutorial, you’ll learn how to easily access heart rate data from HealthKit and use it in a ResearchKit study.

The “smart wearable” market, which includes the Apple Watch, is expected to reach worldwide sales of 53 billion US dollars in 2019. Meanwhile, studies using apps constructed with ResearchKit continue to access data from thousands of consented enrollees, turning consumers into participants and investigating some of our most important scientific mysteries.

One of these mysteries, at the intersection of wearable technology and research, is the heart. Many wearable devices can report heart rate data, providing a large dataset, and now you can tap into that dataset!

In this tutorial, you’ll learn how to easily access heart rate data from HealthKit and use it in a ResearchKit study. You’ll build an app which can:

Access heart rate data from HealthKit.

Create mock heart rate data for use while developing and testing the app.

Prompt the user to walk and rest for certain amounts of time and read heart rate during those periods.

Play a randomized song clip and read the user’s heart rate during the music.

Along the way, you’ll undoubtedly see some possibilities for customization, so building a similar app for another study will be straightforward.

Getting Started

Download and unzip the starter project for this tutorial and open Karenina.xcodeproj in Xcode. Build and run, and you will see a simple main menu that looks like the following:

The project will look familiar if you’ve completed ResearchKit Tutorial with Swift: Getting Started; it’s the finished sample project from that tutorial and includes ResearchKit and several basic tasks.

The project has been renamed Karenina, and you will expand this project to include two new Active Tasks. To refresh your memory, Active Tasks are HealthKit tasks that collect data while guiding the user through some type of activity.

To access heart rate data, your app needs the HealthKit capability. To add this, first navigate to the General tab for the Karenina target and update the Bundle Identifier to a unique value. Next, make sure that the Team field contains your iOS Developer account.

Note: In the following steps, you’ll be editing entitlements for an actual App ID tied to your account, so these identity settings are required. If you need to create an account or download provisioning profiles, do that now before going further.

With a valid team chosen and Bundle Identifier set, select the Capabilities tab, scroll down to HealthKit, and turn the associated switch on, as shown below:

Xcode has kindly added the HealthKit framework to your project and enabled the correct entitlement. If you run into any problems here, they are likely with the team you chose and the associated iOS Developer Account.

Creating Mock Heart Rate Data

Building your app is going to be difficult without a way to test it, and going for a walk every time you build and run would be tiring. You need a way to simulate heart rate data from HealthKit.

First, you need to gain permission to access HealthKit data. Create a new Swift file named HealthKitManager.swift and replace its contents with the following:

import Foundation import HealthKit class HealthKitManager: NSObject { static let healthKitStore = HKHealthStore() static func authorizeHealthKit() { let healthKitTypes: Set = [ HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!, HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)! ] healthKitStore.requestAuthorizationToShareTypes(healthKitTypes, readTypes: healthKitTypes) { _, _ in } } }

After importing HealthKit, you create a HealthKitManager class with a method authorizeHealthKit() for obtaining user permission to read and write certain HealthKit quantity types. Here, the quantity types you care about are the user’s heart rate ( HKQuantityTypeIdentifierHeartRate ) and distance walked ( HKQuantityTypeIdentifierDistanceWalkingRunning ). You create a Set with these quantity types and pass them to requestAuthorizationToShareTypes:readTypes:completion: which will present the user with a prompt.

Now you need a button to trigger the HealthKit authorization. Open ViewController.swift and add the following method to the ViewController class:

@IBAction func authorizeTapped(sender: AnyObject) { HealthKitManager.authorizeHealthKit() }

Then open Main.storyboard, add a UIButton with the title Authorize and connect it to your authorizeTapped(_:) action:

Optionally, add some Auto Layout constraints to align the button to the other buttons. If you don’t know how to do this, don’t worry as it’s not critical for this tutorial – but if you’re curious you can learn how to do so here.

Build and run your app; tap the Authorize button and you’ll see the Health Access screen, where your users can grant your app access to Health data:

Turn on all the options and tap Allow, and your ResearchKit tasks are now able to access data from HealthKit!

how the user responded – only that they did respond. You can query what Write access was granted, but for privacy reasons, you can’t do the same for Read access. Note: If you were to hit the Authorize button again, nothing would happen, because you’ve already authorized HealthKit. You might consider disabling the button after authorization – but be aware that HealthKit doesn’t tell youthe user responded – only that they did respond. You can query what Write access was granted, but for privacy reasons, you can’t do the same for Read access. For testing purposes, you can verify the settings at any given time by navigating to the Settings app, then to Privacy\Health\Karenina.

Now you’re able to create mock heart rate data and save it to HealthKit. To do that, open HealthKitManager.swift and add the following method to the class:

static func saveMockHeartData() { // 1. Create a heart rate BPM Sample let heartRateType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)! let heartRateQuantity = HKQuantity(unit: HKUnit(fromString: "count/min"), doubleValue: Double(arc4random_uniform(80) + 100)) let heartSample = HKQuantitySample(type: heartRateType, quantity: heartRateQuantity, startDate: NSDate(), endDate: NSDate()) // 2. Save the sample in the store healthKitStore.saveObject(heartSample, withCompletion: { (success, error) -> Void in if let error = error { print("Error saving heart sample: \(error.localizedDescription)") } }) }

Let’s review this section by section:

In the first section of saveMockHeartData() , you specify that your sample will be a heart rate sample. Then, you use a random measurement from 100-180 beats per minute (BPM) and set the measurement time to be the current NSDate() . Here you save the sample in HealthKit using saveObject(_:withCompletion:) , and print any error encountered.

Warning: Running this code on a real device will interfere with your personal HealthKit data. Remember to only use this on a simulator, or on a device where you don’t mind adding fake Health data.

Lastly, you use a timer to continuously trigger your mock data. Add the following property to the top of HealthKitManager :

static var timer: NSTimer?

Then add the following two methods to start and stop the timer:

static func startMockHeartData() { timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "saveMockHeartData", userInfo: nil, repeats: true) } static func stopMockHeartData() { self.timer?.invalidate() }

That wraps it up for HealthKitManager! Now that you’ve authorized HealthKit and set it up to provide mock heart rate data, you can start to define ResearchKit tasks that use this data.

Measuring Walking and Resting Heart Rate

ResearchKit includes a pre-made task to read health data while the user walks and rests for set periods of time. Active and resting heart rates hold key importance in heart studies, and now you can easily measure them.

Create a blank Swift file named WalkTask.swift and add the following:

import ResearchKit public var WalkTask: ORKOrderedTask { return ORKOrderedTask.fitnessCheckTaskWithIdentifier("WalkTask", intendedUseDescription: nil, walkDuration: 15 as NSTimeInterval, restDuration: 15 as NSTimeInterval, options: .None) }

Here, you create a new ORKOrderedTask , which you should find familiar after building several in the previous ResearchKit tutorial.

You create this particular task with fitnessCheckTaskWithIdentifier(_:intendedUseDescription:walkDuration:restDuration:options:) , which you supply with a descriptive string identifier ( WalkTask ) and the durations (in seconds) of the walking and resting segments. ResearchKit will take it from there and create your task for you.

Next, open ViewController.swift and add the following IBAction:

@IBAction func walkTapped(sender: AnyObject) { let taskViewController = ORKTaskViewController(task: WalkTask, taskRunUUID: nil) taskViewController.delegate = self taskViewController.outputDirectory = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0], isDirectory: true) presentViewController(taskViewController, animated: true, completion: nil) HealthKitManager.startMockHeartData() }

Here, you create an ORKTaskViewController for your new fitness task, set this view controller as the delegate, specify an output directory for any result files (of which there will be several), and present the view controller. This should be familiar, as it’s how you presented MicrophoneTask in the previous ResearchKit tutorial.

The only new aspect is that after doing all this, you start mocking the heart data. And since you are starting the mock data, you should stop it as well.

Find taskViewController(_:didFinishWithReason:error:) – this is a ORKTaskViewControllerDelegate protocol method that gets called when taskViewController is dismissed. Stop the mock heart data at that point by adding the following line to the top of the method:

HealthKitManager.stopMockHeartData()

As you may recall from earlier, stopMockHeartData() stops the repeating timer you started to generate mock data every second.

Lastly, you need a UI trigger for this IBAction. Open Main.storyboard, add a UIButton entitled “Walk,” and connect it to walkTapped(_:).

Again, optionally add some Auto Layout constraints to align the button to the other buttons.

Build and run your app; tap on Walk and you’ll be led through a short exercise task, during which you’ll see your (unrealistically-widely varying) mock heart rate data:

Note: If running in the simulator, you’ll see an error appear in the console around the time the Walk step begins, which looks similar to this:

WARNING: 997: Failure to setup sound, err = -50

This is because ResearchKit attempts to emit a vibration at the start and end of an active step, and fortunately for all of us, the simulator doesn’t vibrate! :]

You can complete the task now, but what happens to the results? Time to find them.

After completing the walking task, you’ll receive an ORKTaskResult that contains the results of every step. You’ll get to that in a moment, but first you need to create something to parse that data. Create a new file named ResultParser.swift, and replace its contents with the following:

import Foundation import ResearchKit struct ResultParser { static func findWalkHeartFiles(result: ORKTaskResult) -> [NSURL] { var urls = [NSURL]() if let results = result.results where results.count > 4, let walkResult = results[3] as? ORKStepResult, let restResult = results[4] as? ORKStepResult { // TODO: find ORKFileResults } return urls } }

findWalkHeartFiles(_:) accepts an ORKTaskResult that contains the results of every step in your walk task. Note as you are completing the walking test that the top of the walking step says Step 4 of 6; this is your sign that the fourth member – results[3] – holds the results for that step.

Likewise, the resting step is fifth and thus its results are at results[4] . At each of these positions is an ORKStepResult which itself may contain a number of ORKFileResult objects with the date for that step.

To parse out each ORKFileResult and find the file URL within, replace the following:

// TODO: find ORKFileResults

…with the code below:

for result in walkResult.results! { if let result = result as? ORKFileResult, let fileUrl = result.fileURL { urls.append(fileUrl) } } for result in restResult.results! { if let result = result as? ORKFileResult, let fileUrl = result.fileURL { urls.append(fileUrl) } }

You cycle through the results for the two steps of interest and add the fileUrl of each result to an array. The fileUrl points to a JSON file containing the results of the associated step reading. In this case, these results will contain measurements for heart rate in BPM during both the walk and rest phases.

This may seem like a lot of nesting to find the data you like, but the system will become familiar once you get used to digging into the task results. You will see this again when you get the results of your own custom task.

This function takes in an ORKTaskResult and returns an array of file URLs, but where does the ORKTaskResult come from?

To find it, open ViewController.swift and locate taskViewController(_:didFinishWithReason:error:) . Every ORKTaskViewController contains a result property – that’s what you want. Send it to your parser by adding the following code just below HealthKitManager.stopMockHeartData() at the top of the method:

if (taskViewController.task?.identifier == "WalkTask" && reason == .Completed) { let heartURLs = ResultParser.findWalkHeartFiles(taskViewController.result) for url in heartURLs { do { let string = try NSString.init(contentsOfURL: url, encoding: NSUTF8StringEncoding) print(string) } catch {} } }

Here, you check to see if the task is indeed the WalkTask , and that it completed successfully. Then, you use your ResultParser to get the series of file URLs for the step results. Finally, you print the contents of each file to the console.

Build an run your app; tap the Walk button, complete the activity again, then tap the Done button. Look at the console in Xcode, and you’ll notice the printed output in JSON format. If you want to send the results to a server, you could do so without any further serialization!

Below is a small piece of data in the format you will see in your console:

{"items":[{"unit":"count\/min","type":"HKQuantityTypeIdentifierHeartRate","endDate":"2015-10-07T22:22:04-0700","source":"Karenina","value":138,"startDate":"2015-10-07T22:22:04-0700"},{"unit":"count\/min","type":"HKQuantityTypeIdentifierHeartRate","endDate":"2015-10-07T22:22:05-0700","source":"Karenina","value":129,"startDate":"2015-10-07T22:22:05-0700"}]}

As you can see, you have the value, units, and date of every heart rate reading. You’ll notice one array that correlates to the walk step, and another for the rest step – although you haven’t done anything here to flag which is which.

That’s it for the walking task. Now it’s time to build your own task.

Measuring Music’s Effect on Heart Rate

Research into music and its effects on our minds and bodies is a fascinating field; you’ll build a sample task to gather data to test whether a random music clip affects a user’s heart rate.

Start by downloading this archive of a few short music clips, and drag them into your Xcode project. Make sure that Copy items if needed, Create groups, and the Karenina target are selected:

Next, you need a way for your app to easily choose and access a random song file.

Create a file named MusicClip.swift and replace its contents with the following enum:

import Foundation enum MusicClip: String { case Chill3 = "chill_preview_3" case Chill4 = "chill_preview_4" case Dark4 = "dark_preview_4" case Happy1 = "happy_preview_1" case Light2 = "light_preview_2" case Light3 = "light_preview_3" static func random() -> MusicClip { switch arc4random_uniform(6) { case 0: return .Chill3 case 1: return .Chill4 case 2: return .Dark4 case 3: return .Happy1 case 4: return .Light2 default: return .Light3 } } func fileURL() -> NSURL { return NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(self.rawValue, ofType: "mp3")!) } }

The MusicClip enum contains a case for each clip that provides its filename. random() returns a random clip, and fileURL() provides the exact mp3 file URL for a given clip.

Next, you need to think about the step that will eventually play the music clip. In the fitness check task you implemented earlier, the task defined the duration of the walking and resting steps and knew which types of data to collect during the steps. In this case, you’ll need to create a custom task that plays a specific clip for a set duration.

Luckily, there’s a base class in ResearchKit that lets you set a specific duration: ORKActiveStep. For the music step, the only customization you need to add to this class is a MusicClip property.

Create a new file named MusicStep.swift and subclass ORKActiveStep with a property for the music clip, like this:

import ResearchKit class MusicStep: ORKActiveStep { var clip: MusicClip! }

That handles the step, but how will the task know when to start and stop the music clip? That will be handled by the view controller that displays this step.

ResearchKit comes with a custom view controller that handles the display of a step: ORKActiveStepViewController . You have actually already been using this class behind the scenes for your MicrophoneTask and WalkTask. These predefined tasks come with predefined steps and view controllers – subclasses of ORKActiveStep and ORKActiveStepViewController .

Now that you’re delving into the realm of custom steps, you’ll need a custom subclass of ORKActiveStepViewController too. Create a new file named MusicStepViewController.swift and add the class below:

import AVFoundation import ResearchKit class MusicStepViewController: ORKActiveStepViewController { var audioPlayer: AVAudioPlayer? override func start() { super.start() if let step = step as? MusicStep { do { try audioPlayer = AVAudioPlayer(contentsOfURL: step.clip.fileURL(), fileTypeHint: AVFileTypeMPEGLayer3) audioPlayer?.play() } catch {} } } override func stepDidFinish() { super.stepDidFinish() audioPlayer?.stop() } }

In addition to the usual view controller life cycle methods like viewDidLoad() , an ORKActiveStepViewController keeps track of the life cycle of the step itself. You override start() and stepDidFinish() to perform additional actions at those points in the step’s life cycle.

Here, those additional actions are to play the mp3 clip contained in the step when it starts, and to stop playing when the step is over. You call the super functions as well to let the default implementation complete its work.

Next, it’s time to create a subclass of ORKOrderedTask to display instructions, play the music clip and thank the user for participating. In the previous ResearchKit tutorial, you created a ConsentTask and SurveyTask in this way, so the general process should be familiar.

Create a new file named MusicTask.swift, and add the following class:

import ResearchKit public var MusicTask: ORKOrderedTask { var steps = [ORKStep]() let instructionStep = ORKInstructionStep(identifier: "instruction") instructionStep.title = "Music + Heart Rate" instructionStep.text = "Please listen to a randomized music clip for 30 seconds, and we'll record your heart rate." steps += [instructionStep] // TODO: add recorder configuration // TODO: add Music Step let summaryStep = ORKCompletionStep(identifier: "SummaryStep") summaryStep.title = "Thank you!" summaryStep.text = "You have helped us research music and heart rate!" steps += [summaryStep] return ORKOrderedTask(identifier: "MusicTask", steps: steps) }

Here, you’ve created the task and added the introduction and summary steps, leaving a spot in the middle to add the step to play the music clip. But what is this TODO item to add the recorder configuration all about?

An ORKRecorder runs during the step to record data and save it to an output directory. The type of data it records is up to an ORKRecorderConfiguration , which specifies the desired quantity type and unit.

Replace the following line:

// TODO: add recorder configuration

…with the code below:

let configuration = ORKHealthQuantityTypeRecorderConfiguration(identifier: "heartRateConfig", healthQuantityType: HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!, unit: HKUnit(fromString: "count/min"))

The quantity type and unit for this configuration are the same as what you used in saveMockHeartData() , so the recorder will pick up all the mock data as it comes in.

Next, configure the music step by replacing the code below:

// TODO: add Music Step

with the following:

let musicStep = MusicStep(identifier: "music") musicStep.clip = MusicClip.random() musicStep.stepDuration = 30 musicStep.recorderConfigurations = [configuration] musicStep.shouldShowDefaultTimer = true musicStep.shouldStartTimerAutomatically = true musicStep.shouldContinueOnFinish = true musicStep.title = "Please listen for 30 seconds." steps += [musicStep]

You create the music step just as you do any other step: by supplying an identifier string. Then you assign a random music clip to the step, set the timer duration to 30 seconds and supply the heart rate recorder configuration you initialized in the previous code block. Note that the configuration is wrapped in an array; you can supply more than one configuration if you want to read several data types.

The remaining properties are common to all subclasses of ORKActiveStep and allow for some quick and easy customization behavior. I encourage you to experiment with these and other properties which you can find in the class reference.

Now that you have created your music task, it’s time to do the familiar work to trigger the task in your UI. Navigate back to ViewController.swift and add the following method:

@IBAction func musicTapped(sender: AnyObject) { let taskViewController = ORKTaskViewController(task: MusicTask, taskRunUUID: nil) taskViewController.delegate = self taskViewController.outputDirectory = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0], isDirectory: true) presentViewController(taskViewController, animated: true, completion: nil) HealthKitManager.startMockHeartData() }

Here you’ve created and presented a ORKTaskViewController , while immediately starting your mock heart rate data just as you did for the walk task.

Finally, add a UIButton to Main.storyboard with the title Music, and connect it to musicTapped(_:) .

Again, optionally add some Auto Layout constraints to align the button to the other buttons.

Build and run your app; tap Music to see your new task at work:

All your steps are there visually, but wait! There’s no music to listen to!

MusicStepViewController is in charge of playing the music clips, but you haven’t connected it yet. What you’re seeing is simply a generic ORKActiveStepViewController , which can handle the title and countdown, but not the music playback.

To associate your MusicStep and MusicStepViewController, you turn to the ORKTaskViewControllerDelegate protocol and its taskViewController(_:viewControllerForStep:) method. Your ViewController class already implements this protocol, and implementing this method lets you supply a custom view controller for a given step.

Copy the following method into ViewController.swift:

func taskViewController(taskViewController: ORKTaskViewController, viewControllerForStep step: ORKStep) -> ORKStepViewController? { if step.identifier == "music" { return MusicStepViewController(step: step) } else { return nil } }

If the step identifier is music, as you defined in MusicTask, then you create and return a new MusicStepViewController. In any other case, you return nil .

Note: Returning nil here doesn’t actually mean “don’t use a view controller.” It means “use the default view controller you would’ve used anyway.”

Build and run your app, and listen for a random music clip to play:

Great! You now have an app with a custom task, reading heart rate during a music clip. You’ve parsed out the data from a walking task, and now it’s time to do the same for your custom task. And while you’re at it, wouldn’t it be nice to associate that heart rate data with the music clip played?

Open ResultParser.swift and add the following method to find the heart rate data:

static func findMusicHeartFiles(result: ORKTaskResult) -> NSURL? { if let results = result.results where results.count > 1, let heartResult = results[1] as? ORKStepResult, let heartSubresults = heartResult.results where heartSubresults.count > 0, let fileResult = heartSubresults[0] as? ORKFileResult, let fileURL = fileResult.fileURL { return fileURL } return nil }

Underneath all this unwrapping, you retrieve the file URL associated with the music step. This file houses the heart rate data in JSON format.

Next, add the following method to find the music clip:

static func findClip(task: ORKTask?) -> MusicClip? { if let task = task as? ORKOrderedTask where task.steps.count > 1, let musicStep = task.steps[1] as? MusicStep { return musicStep.clip } else { return nil } }

This time, your input parameter is ORKTask? , not ORKTaskResult . You use ORKTask? as the music clip is a property of the MusicStep , which you will access via the MusicTask rather than the task results.

With those methods ready, go back to ViewController.swift and find taskViewController(_:didFinishWithReason:error:) . Remember that this method is called when an ORKTaskViewController finishes, at which point you can access results of the view controller.

Add the following to the top of the method, just below HealthKitManager.stopMockHeartData() :

if (taskViewController.task?.identifier == "MusicTask" && reason == .Completed) { let clip = ResultParser.findClip(taskViewController.task) print("clip name: \(clip!.rawValue)") let heartURL = ResultParser.findMusicHeartFiles(taskViewController.result) if let heartURL = heartURL { do { let string = try NSString.init(contentsOfURL: heartURL, encoding: NSUTF8StringEncoding) print(string) } catch {} } }

If the finishing view controller is for the MusicTask , you send that task to the ResultParser to find the clip used and print the clip’s name to the console.

Next, you use the ResultParser to find the generated file with heart rate data. As you did earlier, you print the JSON contents to the console so that you can easily review the results of your work.

Build and run your app; run the music task again and this time you’ll see results like the following printed to the console when you’re done:

clip name: chill_preview_4 {"items":[{"unit":"count\/min","type":"HKQuantityTypeIdentifierHeartRate","endDate":"2015-10-08T22:53:59-0700","source":"Karenina","value":150,"startDate":"2015-10-08T22:53:59-0700"},{"unit":"count\/min","type":"HKQuantityTypeIdentifierHeartRate","endDate":"2015-10-08T22:54:00-0700","source":"Karenina","value":129,"startDate":"2015-10-08T22:54:00-0700"}]}

With the clip name and associated heart results readily available, you’ll be able to upload this to your server and start analyzing the data! Who knows what relationships or correlations you might find?

Where to Go From Here?

You can download the completed project for this tutorial here.

I encourage you to experiment with other properties of ORKActiveStep in this project to see easy it can be to customize a Step within ResearchKit. Check out the full list in the RestKit documentation here.

If you need a refresher on working with JSON in Swift, see Working with JSON in Swift. You’ll likely be doing quite a bit more of this in your ResearchKit apps.

For more information on ResearchKit, check the official site, GitHub repository, and official ResearchKit forum. Also, Apple maintains a ResearchKit blog and presented about ResearchKit at WWDC 2015.

Beyond the framework, you can look into useful extensions to ResearchKit in the form of CardioHealth, an app developed with Stanford to study cardiovascular disease, and AppCore, which is shared code among all the launch apps. I recommend you take a look at how tasks are created in those projects, and use that behavior as a model.

Thanks for reading; please comment below, and I hope to see more ResearchKit success stories!