Reputation: 19469
I am programming an inactivity alert into my HealthKit-enabled iOS app. When a user has taken less than 100 steps in the last 60 minutes, based on data in Health, it sends a notification. This works perfectly when the app is open, but I am having some trouble making it work in the background. I have tried fetching steps data along with the background location-checking program described in this tutorial (https://www.raywenderlich.com/92428/background-modes-ios-swift-tutorial), but for some reason location data stops being collected in the background when the tutorial's program is run on a real iPhone.
So, my question is: How can my app reliably check Health data every minute in the background, even if the app has been closed for days?
Upvotes: 4
Views: 5305
Reputation: 769
You can use the HKObserverQuery: A long-running query that monitors the HealthKit store and updates your app whenever a matching sample is saved to or deleted from the HealthKit store.
1.First Set your observer queries
let sampleType =
HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)
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()
}
// Take whatever steps are necessary to update your app's data and UI
// This may involve executing other queries
self.updateDailyStepCount()
// If you have subscribed for background updates you must call the completion handler here.
// completionHandler()
}
healthStore.executeQuery(query)`
2.Then register to receive background deliveries
Register to receive updates while in the background by calling the HealthKit store’s enableBackgroundDelivery(for:frequency:withCompletion:)
method. You can set the appropriate frequency of updates upon requirements.
HealthKit wakes your app whenever new samples of the specified type are saved to the store. If you plan on supporting background delivery, set up all your observer queries in your app delegate’s application(_:didFinishLaunchingWithOptions:)
method. By setting up the queries in application(_:didFinishLaunchingWithOptions:)
, you ensure that the queries are instantiated and ready to use before HealthKit delivers the updates.
For more info, please check the source: https://developer.apple.com/documentation/healthkit/hkobserverquery
Upvotes: 8
Reputation: 20237
The HealthKit database is encrypted when the device is locked. This means you are not able to read any data from it at all when the device requires you to enter your passcode/fingerprint (which the majority of devices have enabled). So unfortunately, even if you are able to get something to run in the background every minute you would not be able to read the data (your query will just return an error instead of any results).
However, step data can still be accessed from the pedometer (this data is not encrypted). I recommend you look at using that instead of HealthKit for any background processing.
Now it sounds like you really only need to check if the user has taken steps in the last hour. It would be much more efficient if you would only check that often instead of every minute. If your app has access to a server with push notifications setup, you could schedule a silent push notification to wake up your app in the background and do the step check from the pedometer once an hour.
Upvotes: 8