iOS : Use of HKObserverQuery's background update completionHandler

IosBackgroundHealthkitHkobserverquery

Ios Problem Overview


HKObserverQuery has the following method that supports receiving updates in the background:

- initWithSampleType:predicate:updateHandler:

The updateHandler has a completionHandler which has the following documentation:

> This block is passed to the update handler. You must call this block > as soon as you are done processing the incoming data. Calling this > block tells HealthKit that you have successfully received the > background data. If you do not call this block, HealthKit continues to > attempt to launch your app using a backoff algorithm. If your app > fails to respond three times, HealthKit assumes that your app cannot > receive data, and stops sending you background updates.

From looking at other posts it seems like there's a lot of confusion revolving around this handler. Below are some questions that I have about it:

  • When should the handler be called? If called too late, then HK might think that the app never received the query update causing you to hit the background update 3-strikes back-off algorithm. The documentation states that it should be called after handling other queries. Depending on how long it would take to run those queries, it sounds like you could get dangerously close to hitting the background update strikes.
  • Why is this needed? Shouldn't the system know that the app has been launched and has received the background update? When using CoreBluetooth in the background it just wakes your app up in the background for 10 seconds. No need to call any handler or deal with the background update 3-strikes.
  • If you hit the background update 3-strikes and HK stops sending updates is that permanent? Does HK ever start sending the background updates again? What if there's a bug that prevented the handler to be called and now you've fixed it. Is the app stuck never receiving the updates? Or will it reset when the app is re-launched or updated?
  • Does HK keep your app running in the background until the handler is called? Is that part of its purpose or just a side effect? If it's part of its purpose how long can we run before needing to stop (and hit the first background update strike)?

Ios Solutions


Solution 1 - Ios

> When should the handler be called?

Call it after you are done your job. Your code should not do complex operations. The app is in the background and the user does not see what's changed. You can just set a "flag" that data is updated and do complex operations after the user launched the app. If your decision about either notifies the user or not based on complex operations, then try to refactor code so that all necessary data is pre-calculated (e.g. in UserDefaults) and extra data is simply fetched with that data. So, 1-2 seconds is enough for your calculation.

> Why is this needed?

All such handlers have completion closures. They are needed for iOS to know if your app works fine. If your app will eat too much CPU time, then iOS could become slow. Hence, Apple wants to be sure that iOS works fine despite bad apps.

> If you hit the background update 3-strikes and HK stops sending updates is that permanent?

No.

> Does HK ever start sending the background updates again?

Yes. But it depends on many factors. It may try to call your app again in 1-2 days. If nothing changes it will call it rarely.

> Does HK keep your app running in the background until the handler is called?

This is unknown. It depends on many factors. Probably if iPhone is charging it will allow running your app longer just to estimate if the completion handle is called or not. If your iPhone is not charging and closed to 0% battery, then more likely iOS will kill your app. So, you should not do any job after you called the completion handler. And try to keep it simple.

Recommendations

You should process new data as quickly as possible. If you need to fetch a lot of data, then try to optimize this and pre-calculate it when the app is in foreground, then save somewhere (UserDefault), and use new data with cached data to make a decision (e.g. notify user about something; I believe you need background updates exactly for that).

1-2 seconds or less is a good time for background updates.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionosprView Question on Stackoverflow
Solution 1 - IosAlexander VolkovView Answer on Stackoverflow