How does BGTaskScheduler work, and why does your task not run when you ask?
Predict first
You set earliestBeginDate to 15 minutes from now. When is the task guaranteed to run?
// A: after exactly 15 minutes
// B: never guaranteed, the system chooses, at the earliest then
// C: immediately
- A
- B
- C
Mental model. You leave a note saying “call me after 3 pm”. The system calls when it is convenient for the battery, and only if it thinks you will be wanted.
You register a handler for each task identifier at launch (in didFinishLaunching, before it returns), list the identifiers in BGTaskSchedulerPermittedIdentifiers in Info.plist, enable the matching background mode, and then submit a request: BGAppRefreshTaskRequest for a short refresh, BGProcessingTaskRequest for long work (with options such as requiring external power or network). Each request carries an earliestBeginDate, which is only a lower bound.
The system then decides when to launch the app in the background, using usage patterns (it learns when the user opens the app), battery level, thermal state, network and Low Power Mode. It may delay a task for hours or not run it at all. When it runs, your handler gets a BGTask with an expiration handler you must set to stop work cleanly, and you must call setTaskCompleted(success:) when finished, then usually schedule the next request. Test by pausing in the debugger and running the private simulate-launch command for the identifier, because waiting for the system is not practical.
The date is only a lower bound. The system schedules the launch according to battery, usage and thermal conditions.
Common traps
- Registering the handler after launch has finished. The registration must happen before
didFinishLaunchingreturns. - Not scheduling the next request in the handler. A refresh runs once and does not recur by itself.
They might follow up with
- How do you debug it? Use the debugger command that simulates launching a task for an identifier, and the “Background Fetch” simulation in Xcode.
- Does
earliestBeginDateguarantee a time? No. It is the earliest the task may run, not when it will.
Related questions
- 6.5.1 An app goes to the background. What can it still do, and how do you choose a mechanism?
- 6.7.1 What is Info.plist for, and which keys matter most?
- 6.5.4 How does a background URLSession keep working when the app is not running?
← What do the audio, location, VoIP and remote-notification background… How does a background URLSession keep working when the app is not… →