1

I'm trying to program a heart rate monitor using the HealthKit API.

I have a Polar H7 and it is writing the data to the Health store. I achieved my goal using HKObserverQuery (no missing call to completionHandler()), HKSampleQuery and enabling background updates calling HKHealthStore.enableBackgroundDeliveryForType for the type I'm querying.

private func queryForHeartRate() {

    guard let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate) else {
        executeCompletionHandler(value: nil, error: nil)
        return
    }

    let observerQuery = HKObserverQuery(sampleType: sampleType, predicate: nil) { [unowned self] query, completionHandler, error in

        guard error == nil else {
            self.executeCompletionHandler(value: nil, error: error)
            return
        }

        self.queryHeartRateSample(sampleType)
        completionHandler()
    }

    healthStore.executeQuery(observerQuery)
}

private func queryHeartRateSample(sampleType: HKSampleType) {

    let timeSortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
    let sampleQuery = HKSampleQuery(sampleType: sampleType, predicate: nil, limit: 1, sortDescriptors: [timeSortDescriptor], resultsHandler: { [unowned self] (sampleQuery, results, error) in

        guard error == nil else {
            self.executeCompletionHandler(value: nil, error: error)
            return
        }

        guard let samples = results as? [HKQuantitySample] where !samples.isEmpty else {
            self.executeCompletionHandler(value: nil, error: error)
            return
        }

        guard let lastSample = samples.last else {
            self.executeCompletionHandler(value: nil, error: error)
            return
        }

        let heartBeat = lastSample.quantity.doubleValueForUnit(self.heartBeatsPerMinuteUnit)
        self.executeCompletionHandler(value: heartBeat, error: nil)
    })

    healthStore.executeQuery(sampleQuery)
}

But when the app goes to background or I lock the phone (immediate passcode) the app stops to receive the updates.

Reading the docs I see:

The HealthKit data is only kept locally on the user’s device. For security, the HealthKit store is encrypted when the device is locked. The HealthKit store can only be accessed by an authorized app. As a result, you may not be able to read data from the store when your app is launched in the background; however, apps can still write data to the store, even when the phone is locked. HealthKit temporarily caches the data and saves it to the encrypted store as soon as the phone is unlocked

However, when I use Runstastic, I receive sound advises when I change the heart zone; Nike+Running tracks all the heart rate the same way. How is that possible with that privacy policy?

I'm a bit lost, and the documentation is kind of confusing about what is needed to receive updates on background/locked (if possible). I read all the related answers here in SO but no one is conclusive, and the one with more information, this, speaks about background fetches, thing that is not mentioned in the docs.

Is there any resource or tutorial on how to achieve this? Is even possible? Have Runtastic or similar apps workarounds for this?

Thank you so much.

Community
  • 1
  • 1
emenegro
  • 6,901
  • 10
  • 45
  • 68

1 Answers1

1

Your app cannot receive HealthKit data while the device is locked because the data is encrypted and inaccessible at that time. Other apps that respond to changes in heart rate while the device is locked are most likely reading data directly from the BT heart rate monitor, not HealthKit.

Allan
  • 7,039
  • 1
  • 16
  • 26
  • That was what I was supposing, so I'll implement a way to get the beats from the sensor using BTLE. Thank you! – emenegro Apr 19 '16 at 06:42
  • My experience with BLE is that the connection to the device gets lost after a certain amount of background execution time. After approx. 4 hours in background iOS will terminate the app with your BLE connection, resulting in no more monitor updates. Do you have more reliable experiences with BLE connections? – Chris Mar 30 '17 at 19:48