I'm trying out iOS Background Task for the first time. Following the sample WWDC'19 code, I set up a simple app that sets a UserDefaults
key's value to 1 in the ViewController.viewDidLoad()
and set it to 2 in the background task. I have the value printed before entering background and upon returning to foreground. The value consistently prints as 1, even after letting the app sit in the background overnight. Is my background task not run? Or could it be that my UserDefaults
value is not synchronized between the foreground and background tasks, as discussed in several stackoverflow questions? Or am I doing something else wrong? Any pointer appreciated.
I have checked the "Background fetch" item in "Background Modes" under "Signing & Capabilities" and I have also added "com.example.BGTask.refresh" as "item 0" under "Permitted background task scheduler" in my Info.plist
. I'm running the app on device, tethered to Xcode.
iOS 13.5.1, Xcode 11.5
AppDelegate.swift:
import UIKit
import BackgroundTasks
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.example.BGTask.refresh", using: nil) { task in
self.handleAppRefresh(task: task as! BGAppRefreshTask)
}
return true
}
func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: "com.example.BGTask.refresh")
request.earliestBeginDate = Date(timeIntervalSinceNow: 15*60)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh: \(error)")
}
}
func handleAppRefresh(task: BGAppRefreshTask) {
scheduleAppRefresh()
task.expirationHandler = {
task.setTaskCompleted(success: false)
}
UserDefaults.standard.set(2, forKey: "bgtask")
task.setTaskCompleted(success: true)
}
// MARK: UISceneSession Lifecycle
// rest of templated AppDelegate.swift
SceneDelegate.swift:
Following this tutorial, I call scheduleAppRefresh()
in SceneDelegate
instead of AppDelegate
and have modified these two functions:
func sceneDidBecomeActive(_ scene: UIScene) {
print("didBecomeActive: ", UserDefaults.standard.integer(forKey: "bgtask"))
}
func sceneDidEnterBackground(_ scene: UIScene) {
print("didEnterBackground: ", UserDefaults.standard.integer(forKey: "bgtask"))
(UIApplication.shared.delegate as! AppDelegate).scheduleAppRefresh()
}
Finally, in ViewController.swift:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
UserDefaults.standard.set(1, forKey: "bgtask")
print("viewDidLoad: ", UserDefaults.standard.integer(forKey: "bgtask"))
}
}
This is what I get printed out on the Xcode console:
viewDidLoad: 1
didBecomeActive: 1
// tap the Home button
didEnterBackground: 1
// after a suitably long time, tap the app icon
didBecomeActive: 1
Why doesn't UserDefaults.shared.integer(forKey: "bgtask")
get incremented by the second didBecomeActive
?
after I watch wwdc2019
https://developer.apple.com/videos/play/wwdc2019/707/
The task will be executed only when the system decides to do so
You can check to this forum discussion link too :
https://forums.developer.apple.com/thread/124320
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With