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.