Managing background tasks with the new Task Scheduler in iOS 13
In this post I’m going to discuss the BackgroundTasks framework, introduced at WWDC this year.
Apple released another great framework this year, and this time it is the BackgroundTasks framework. We can use it to schedule and control the execution conditions of our background jobs. BackgroundTasks framework allows us to plan and run background work according to required criteria like when the battery is charging, connection availability, etc. BackgroundTasks framework has various task types. Let’s take a look at them.
App refresh task
BGAppRefreshTask is a special type of Background Task which we can use for app data update. One thing that makes this task type very special is the user behavior. iOS learns how often and at what time the user is running your app and tries to run BGAppRefreshTask at a time when the user is not likely to be using the app.
Let’s implement a background app refresh for the sample app. First of all, we have to add background modes capability in the project settings. Next, we need to enable “Background fetch” checkbox, which is required for background app refresh. Lastly, we need to add “Permitted background task scheduler identifiers” key to Info.plist. This key will store the array of unique identifiers for every background task in the app. Finally, we can start working on the background refresh logic.
We start by registering the task identifier and associated closure. This closure will run on every job execution. In handleAppRefresh function, we run the background operation.
There are two key points here:
1. Make sure you call the setTaskCompleted method as soon as your job is finished.
2. Set expiration handler on task object because the system gives you a limited time to complete your job, and if you exceed it, you have to clean up resources.
Remember that you can only schedule a job once, you have to schedule it every time if you want to run it periodically.
Background processing task
Another type of background tasks is a Processing task. You can use it to train a ML model on-device or make a clean up in the database. Before you start, enable “Background processing” checkbox in Background Modes capability. Let’s add another identifier for a new job type to Info.plist.
Scheduling a processing task is very similar to the app refresh task. Please take a look at scheduleMLTrain function. We set requiresExternalPower and requiresNetworkConnectivity properties to true. By doing this, we indicate that our job needs a network connection and battery charging. I highly encourage you to do your heavy calculations while the device is charging to prevent battery drain and a bad user experience.
The only way of debugging background tasks is to keep your phone connected to Xcode debugger, but we don’t know when iOS will decide to run our jobs because it uses some hidden logic for that. Luckily, Apple provides two private functions, which we can use in the debugger to start and expire background tasks. Please remember that you can use it only during development, don’t include them in release.
For starting background tasks, pause your app and run in the debugger this code:
e -l objc — (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@”TASK_IDENTIFIER”]
To force early termination use:
e -l objc — (void)[[BGTaskScheduler sharedScheduler] _simulateExpirationForTaskWithIdentifier:@”TASK_IDENTIFIER”]
Remember to replace TASK_IDENTIFIER with the real identifier.
The BackgroundTasks framework is a great way of scheduling your heavy work with the best user experience by using environment conditions. This year WWDC was so rich, Apple released a bunch of new frameworks, and I will try to cover more new topics in the next posts. Thanks for reading!