Reputation: 6824
I have followed Apple Docs and Several threads on stackoverflow on how to achieve background fetching of data from Health Store. So far I have:
This is my code (swift): If your answer is in Obj-C and works, please state it as well, I will have to translate it, but that's no problem.
AppDelegate.swift
var healthStore: HKHealthStore?
var bpmSamples: [HKQuantitySample]?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let dataTypesToWrite = [ ]
let dataTypesToRead = [
HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate),
HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMassIndex),
HKCharacteristicType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierDateOfBirth)
]
if self.healthStore == nil {
self.healthStore = HKHealthStore()
}
self.healthStore?.requestAuthorizationToShareTypes(NSSet(array: dataTypesToWrite as [AnyObject]) as Set<NSObject>,
readTypes: NSSet(array: dataTypesToRead) as Set<NSObject>, completion: {
(success, error) in
if success {
self.addQueryObserver()
println("User completed authorisation request.")
} else {
println("The user cancelled the authorisation request. \(error)")
}
})
return true
}
func addQueryObserver(){
let sampleType =
HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)
let query = HKObserverQuery(sampleType: sampleType, predicate: nil) {
query, completionHandler, error in
if error != nil {
// Perform Proper Error Handling Here...
println("*** An error occured while setting up the stepCount observer. \(error.localizedDescription) ***")
abort()
}
println("query is running")
self.performQueryForHeartBeatSamples()
completionHandler()
}
healthStore?.executeQuery(query)
healthStore?.enableBackgroundDeliveryForType(sampleType, frequency:.Immediate, withCompletion:{
(success:Bool, error:NSError!) -> Void in
let authorized = self.healthStore!.authorizationStatusForType(sampleType)
println("HEALTH callback success", success)
println("HEALTH callback authorized", sampleType)
})
if HKHealthStore.isHealthDataAvailable() == false {
println("HEALTH data not available")
return
} else {
println("HEALTH OK")
self.performQueryForHeartBeatSamples()
}
}
// MARK: - HealthStore utility methods
func performQueryForHeartBeatSamples() {
let endDate = NSDate()
let startDate = NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitMonth, value: -2, toDate: endDate, options: nil)
var heartRate : HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)
let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: .None)
let query = HKSampleQuery(sampleType: heartRate, predicate: predicate, limit: 0, sortDescriptors: nil, resultsHandler: {
(query, results, error) in
if results == nil {
println("There was an error running the query: \(error)")
}
dispatch_async(dispatch_get_main_queue()) {
self.bpmSamples = results as? [HKQuantitySample]
let heartRateUnit: HKUnit = HKUnit.countUnit().unitDividedByUnit(HKUnit.minuteUnit())
if self.bpmSamples?.count > 0 {
if let sample = self.bpmSamples?[self.bpmSamples!.count - 1] {
println(sample.quantity!.description)
let quantity = sample.quantity
var value = quantity.doubleValueForUnit(heartRateUnit)
println("bpm: \(value)")
}
}
else {
println("No Data")
}
}
})
self.healthStore?.executeQuery(query)
}
So, the problem is that I only receive updates when I resume my app from background to active state manually.. HKObserverQuery
doesn't seems to be working for me while on background mode.
Any suggestions?
Upvotes: 0
Views: 2223
Reputation: 878
In my experiences, frequency ".Immediate" doesn't work well. The handler of queries are inserted into background queue. If the matching samples are frequently added or iOS is busy, the immediate frequency doesn't work well.
In addition, you cannot use HKSampleQuery
in HKObserverQuery
. updateHandler
of HKObserverQuery
may work, but resultHandler
of HKSampleQuery
will not. The handler of an observer query can be executed in the background mode but the one of a sample query cannot be executed in the background mode.
You should know that ONLY HKObserverQuery
can be used in the background
Upvotes: 1