HealthKit

The Validic Mobile library provides a simple way to read and upload data from HealthKit to Validic. VLDHealthKitManager can subscribe to specific HealthKit sample types and automatically upload them to Validic in the background as new data is recorded.

Before you can use the HealthKit features of the library, be sure to import the HealthKit framework into your project and enable the HealthKit entitlements for your app.

Setup

  • The HealthKit framework requires filling in the Privacy - Health Share Usage Description and Privacy - Health Update Usage Description keys and values if edited in Xcode.

HealthKit Usage Description

If viewing the raw source add the NSHealthShareUsageDescription and NSHealthUpdateUsageDescription keys as displayed below.

<key>NSHealthShareUsageDescription</key>
<string>Get Health data</string>
<key>NSHealthUpdateUsageDescription</key>
<string>Write Health data</string>

To use HealthKit in your project you must enable it from the Capabilities tab. Select your project target and then select the Capabilities tab, scroll down until you find HealthKit and select the switch to turn HealthKit on. Your project should look like the screenshot below.

HealthKit-Enabled

In new Xcode projects the HealthKit framework will be linked automatically when the framework is imported by a project file. To confirm this navigate to the Build Settings tab of the project target and search for Link Frameworks. Under Under Clang - Lanuage - Modules you’ll see Link Frameworks Automatically set to Yes.

Linked Frameworks

Subscription Sets

Useful sets of sample types are defined in an VLDHealthKitSubscriptionSet enum. Sample types for a subscription set can be retrieved using the sampleTypesForSubscriptionSet: static method of the VLDHealthKitSubscription class. The following subscription sets are available:

  • VLDHealthKitSubscriptionSetRoutine: Includes Flights Climbed, Active Energy Burned, Distance Walking/Running, Step Count, and Basal Energy Burned. In iOS 9 and later this also includes Apple Stand Hours, Apple Exercise Minutes, and Mindful Minutes (from the Apple Watch). In iOS 10 and later this will also include Wheelchair Distance and Wheelchair Push Count.
  • VLDHealthKitSubscriptionSetDiabetes: Blood Glucose sample type.
  • VLDHealthKitSubscriptionSetWeight: Includes Body Mass (weight), Height, Body Fat Percentage, Lean Body Mass, and Body Mass Index.
  • VLDHealthKitSubscriptionSetFitness: Includes Workout, Nike Fuel, and Cycling Distance.
  • VLDHealthKitSubscriptionSetSleep: Sleep Analysis sample type, this set tracks time in bed, time awake, and time asleep.
  • VLDHealthKitSubscriptionSetBasicNutrition: Includes Calcium, Carbohydrates, Cholesterol, Fiber, Iron, Potassium, Protein, Saturated Fat, Sodium, Sugar, Total Fat, and Energy Consumed. in iOS 9 and later this will also include Dietary Water.
  • VLDHealthKitSubscriptionSetReproductiveHealth: Includes Sexual Activity, Cervical Mucus Quality, Intermenstrual Bleeding, Menstrual Flow, Ovulation Test Result, and BasalBodyTemperature. These sample types are only available in iOS 9 and later.
  • VLDHealthKitSubscriptionSetBiometrics: Includes Systolic Blood Pressure, Diastolic Blood Pressure, Heart Rate, Body Temperature, and SpO2 (oxygen saturation).

Subscribing to changes

Subscribing to HealthKit updates only needs to be done once for a user. The subscriptions will be persisted across app launches in the VLDSession object. A typical use of the HealthKit framework would be to create a UISwitch that adds the required subscriptions when turned on and removes them when turned off. Example:

func toggleHealthKit(_ sender: UISwitch) {
    if sender.isOn {
        var sampleTypes = VLDHealthKitSubscription.sampleTypes(for: VLDHealthKitSubscriptionSet.routine)
        sampleTypes?.append(contentsOf: VLDHealthKitSubscription.sampleTypes(for: VLDHealthKitSubscriptionSet.biometrics))
        sampleTypes?.append(contentsOf: VLDHealthKitSubscription.sampleTypes(for: VLDHealthKitSubscriptionSet.diabetes))
        sampleTypes?.append(contentsOf: VLDHealthKitSubscription.sampleTypes(for: VLDHealthKitSubscriptionSet.sleep))
        sampleTypes?.append(contentsOf: VLDHealthKitSubscription.sampleTypes(for: VLDHealthKitSubscriptionSet.basicNutrition))
        sampleTypes?.append(contentsOf: VLDHealthKitSubscription.sampleTypes(for: VLDHealthKitSubscriptionSet.fitness))

        VLDHealthKitManager.sharedInstance().setSubscriptions(sampleTypes, completion: nil)
    } else {
        VLDHealthKitManager.sharedInstance().setSubscriptions([], completion: nil)
    }
}

To properly process the delivery of data in the background, the subscription observers need to be recreated immediately when the app is launched. To do this, you need to call [VLDHealthKitManager observeCurrentSubscriptions] inside your application delegate’s application:didFinishLaunchingWithOptions: fuction. Example:

func application(_ application: UIApplication didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
    VLDHealthKitManager.sharedInstance().observeCurrentSubscriptions()
    return true
}

Note: Calling [[VLDSession] sharedInstance] endSession] in Objective-C or VLDSession.sharedInstance().end() in Swift will remove all HealthKit subscriptions and stop listening for new data.

Subscribing to Intrday Steps

The Validic Mobile library supports retreiving more fine step data through VLDIntray. If enabled via your SDK this will automatically be gathered when subscripting to VLDHealthKitSubscriptionSetRoutine. This is a premium feature and is not enabled by default.

Historical Fetch

The Validic Mobile library provides the ability to query 6 months of data for a subset of data types provided by HealthKit by specifying one of more values of the VLDHealthKitHistoricalSet enum.

Two historical sets are available

  • VLDHealthKitHistoricalSetRoutine - Step data
  • VLDHealthKitHistoricalSetFitness - Workout data
  • VLDHealthKitHistoricalSetIntraday - Intraday step data (Premium feature, with only 7 days of historical data)

To fetch 6 months of historical HealthKit data, call the fetchHistoricalSets: method on VLDHealthKitManager and pass in the datasets you want to fetch. Example:

VLDHealthKitManager.sharedInstance().fetchHistoricalSets([NSNumber(value:VLDHealthKitHistoricalSet.fitness.rawValue),
                                                          NSNumber(value:VLDHealthKitHistoricalSet.routine.rawValue)]) {
                                                          (results:[AnyHashable : Any]?, error:Error?) in
    // historical fetch complete
}

Doing this may display a permission dialogue from HealthKit so it’s important to call this at an appropriate time in your app. It is recommended to explain to the user why you want this data before attempting to fetch it. This operation may take several seconds to complete so it would be advisable to display an activity indicator to the user until the completion block is called. There should be no need to call this method more than once for a user. When the fetch completes all the data will have been fetched locally and queued up for submission to the server. The amount of time needed to upload the records may vary based on the user’s internet speed. The queued records are uploaded automatically by the library based on connectivity, but it is possible for the user to suspend the app before all the records have been uploaded, the remaining records will be uploaded when the user resumes the app. This should be kept in mind when receiving records from the Validic server.