I register the background fetch task in didFinishLaunchingWithOptions of the appDelegate:
BGTaskScheduler.shared.register(forTaskWithIdentifier: BackgroundScheduler.shared.backgroundTaskId, using: DispatchQueue.main) { task in
BackgroundScheduler.shared.handleAppRefresh(task: task as! BGAppRefreshTask)
}
The handleAppRefersh function schedules for another refresh task and calls the fetch method of the operation and also passes a completion handler to be run after finishing the fetch operation.
func handleAppRefresh(task: BGAppRefreshTask) {
os_log("handleAppRefresh exetued.")
scheduleAppRefresh()
task.expirationHandler = {
os_log("backgroundFetch expiration called")
}
operation.fetch() {
os_log("backgroundFetch fetch called")
task.setTaskCompleted(success: true)
}
}
The scheduleAppRefresh submits BGAppRefreshTAskRequest for repeating the background fetch executions.
func scheduleAppRefresh() {
os_log("scheduleAppRefresh exetued.")
let request = BGAppRefreshTaskRequest(identifier: backgroundFetchId)
request.earliestBeginDate = Date(timeIntervalSinceNow: AppSettings.refreshInterval)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
os_log("Could not schedule app refresh:", error.localizedDescription)
}
}
The refreshInterval is 10 * 60 which means 10 minutes.
The operation.fetch method checks the current location of the device and sends a request to a remote server. Finally it sends local notifications, updates UI and calls the following code:
task.setTaskCompleted(success: true)
Both the "Location update" and "Background fetch" capabilities checked in the Xcode and required settings added to the info.plist.
When I test the background fetch feature using the following debug command everything works perfectly and there is not any warning messages in debugger.
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"TASK_IDENTIFIER"]
But when I leave the app in the background even for long hours, the iOS never calls the handleAppRefresh function.
Xcode: 12.2, iOS: 14.2
Project public repo:
https://github.com/amirrezaeghtedari/CoronaVirousRegulations.git
I’m confused completely.
2
Answers
I had set the background fetch interval for 10 minutes and and after waiting around 4 hours or more the iOS ran my app in the background. After that my app is called in the background irregularly with intervals from less than one to some hours. It is obvious that there is no problem with my implementation and these execution intervals depend on iOS policies.
WWDC 2020
Background execution demystified
Allegedly, there are many factors in play that determine when you app actually runs background refresh. The OS’s neural engine learns when the user launches app so that the updates can be performed just before. They first mention this in the 2019 session.