Background tasks scheduled using BGTaskScheduler not getting triggered

Hi, I'm trying to schedule a background task to fetch a system parameter value at regular intervals. I've created a dummy iOS app using Xcode for the same and am making use of the new Background tasks framework to accomplish this.


I've selected the 'Background fetch' and 'Background processing' checkboxes at the Capabilities sections, and defined two new tasks in the 'Permitted background task scheduler identifiers' entry in the Info.plist file. I've added the following code into AppDelegate class to schedule the background tasks and get it triggered when my app is in the background:


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

BGTaskScheduler.shared.register(

forTaskWithIdentifier: "com.mokhosla.fetchBrightness", using: nil) { task in

self.handleAppRefreshTask(task: task as! BGAppRefreshTask)

}

return true

}

func handleAppRefreshTask(task: BGAppRefreshTask) {

scheduleBackgroundBrightnessFetch()

let brightnessOperation = BrightnessOperation(brightness: UIScreen.main.brightness.description)

task.expirationHandler = {

brightnessOperation.cancel()

}

brightnessOperation.completionBlock = {

task.setTaskCompleted(success: !brightnessOperation.isCancelled)

}

let operationQueue = OperationQueue()

operationQueue.addOperation(brightnessOperation)

}

func scheduleBackgroundBrightnessFetch() {

let taskRequest = BGAppRefreshTaskRequest(identifier: "com.mokhosla.fetchBrightness")

taskRequest.earliestBeginDate = Date(timeIntervalSinceNow: 10)

do {

try BGTaskScheduler.shared.submit(taskRequest)

} catch {

print("error: \(error.localizedDescription)")

}

}


Upon building the app and then moving it in the background, I find that the OS never trigggers the background task. I've gone through a few other threads on this forum and find other developers facing the same issue. Is there something wrong I'm doing there? Is this not the expected way to use BGTasksScheduler? Kindly help me understand what I'm doing wrong here. Thanks in advance!

I'm trying to schedule a background task to fetch a system parameter value at regular intervals.

It’s unlikely that an app refresh task will meet your needs here. App refresh tasks are not a way to get regular execution time. Rather, the intended use case centres around user activity. The system observes the user’s behaviour and recognises that they interact with the app regularly. It then starts running the app’s app refresh tasks so that the app can update its UI proactively, meaning:

  • The user is more likely to see up-to-date info in the multitasking UI.

  • The user doesn’t have to wait for the app to refresh the next time they bring it to the the front.

So, unless you have an app that the user is checking regularly, an app refresh task won’t help you. It’s unlikely that the system will ever decide to run your task and, even if it does, that commitment will fade away over time.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank you for the explanation eskimo,

What about the "previous" iOS 12 approach ? I have created in Xcode 11 sample, trivial project which read/write from/to UserDefaults number of times performFetch is called.

My point of using background fetch is for checking status of user's activation.

When I debug the app it works smoothly. (i.e. Simulate Background Fetch in Xcode, or Options -> Launch Due to a background Fetch event).

But It is not called on the real devices: iPhone 6, iOS 12.4, iPhone XS iOS 13.3.1

here is the link:

https://www.dropbox.com/s/gk63h6qmnxgeqg1/FetchTest.zip?dl=0


The code is trivial, i've added "Required background modes in Info.plist, no luck 🙂.

I tried running Debug & Release version it didn't work.

Below is an excerpt from AppDelegate:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        print("!!! Did finish launching count \(getCount())")
        application.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
        return true
    }
   
    func getCount() -> Int {
        let def = UserDefaults.standard
        let count = def.value(forKey: "count") as? Int ?? 0
        return count
    }
   
    func increaseCount() -> Int {
        let def = UserDefaults.standard
        let count = getCount()
        def.set(count + 1, forKey: "count")
        def.synchronize()
        return count + 1
    }
   
    func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print("!!! New count \(increaseCount())")
        completionHandler(.newData)
    }

Moreover, I took WWDC Background task sample code: and added there the same trivial logic count increment ( increaseCount ) logic. The code is here:


https://www.dropbox.com/s/2lu7rz1lett2pzz/RefreshingAndMaintainingYourAppUsingBackgroundTasks.zip?dl=0


But it doesn't work, I was opening the page with count, for a couple of times, so the system could find out, or study that I use the app, also connected the phone to the charger, but BG task doens't run. I even don't close the app, just move it into background.

On Settings for the apps bg mode is enabled.

It just doesn't work.

I don’t have time to look at your whole post right now but this part is easy:

What about the "previous" iOS 12 approach?

The previous background fetch mechanism has the same ‘guarantees’ as BackgroundTasks framework, that is, none at all. If you search through old DevForums posts, you’ll find many complaints along similar lines.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
I think the first background fetch task is not scheduled in your code. You need to call the scheduleBackgroundBrightnessFetch at least once after registering the task identifier and from then on, every time a fetch request is executed, it will schedule the next one to happen.

Background tasks are also not working for me. I can manually start the Operation and it runs. But the scheduled background task is never ran, and “debug > simulate background task” doesn’t do anything either.

Background tasks scheduled using BGTaskScheduler not getting triggered
 
 
Q