Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

iOS BGTaskScheduler

Hi! I'm trying to submit a task request into BGTaskScheduler when I background my app. The backgrounding triggers an update of data to a shared app groups container. I'm currently getting the following error and unsure where it's coming from:

*** Assertion failure in -[BGTaskScheduler _unsafe_submitTaskRequest:error:], BGTaskScheduler.m:274

Here is my code:

BGAppRefreshTaskRequest *request = [[BGAppRefreshTaskRequest alloc] initWithIdentifier:kRBBackgroundTaskIdentifier];
        
        NSError *error = nil;
        bool success = [[BGTaskScheduler sharedScheduler] submitTaskRequest:request error:&error];
Answered by turtlturt in 834757022

hi! we ended up finding out this was an issue on our flagging system. The register was too early in our app lifecycle and was not being run. Fixing this also resolved this issue. Thank you

It is being called under the applicationDidEnterBackground function by scheduleBackgroundTask if it helps:

if ([RBFastFlags sharedInstance].enableWidgetDataProtocol) {
        RBWidgetDataRecentlyPlayedBackgroundTaskModule* WidgetDataTask = [[RBWidgetDataRecentlyPlayedBackgroundTaskModule alloc] init];
        if ([WidgetDataTask isWidgetEnabled]) {
            NSCondition* waitForWidgetDataComplete = [[NSCondition alloc] init];
            [WidgetDataTask runBackgroundTaskModuleWithCompletionBlock:^{
                [waitForWidgetDataComplete signal];
            }];
            [waitForWidgetDataComplete waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:25]];
        }
        
        [self scheduleBackgroundTask];
        
        [WidgetTimelineReloadHelper reloadWidgets];
    }

This looks like an assertion handler associated with the message No launch handler registered for task with <TASK_ID>. Are you sure that the task identifier is listed in the BGTaskSchedulerPermittedIdentifiers property in your Info.plist?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yea, I have

<key>BGTaskSchedulerPermittedIdentifiers</key>
	<array>
	  
<string>com.(group).refreshtask</string>  
	</array>

<key>BGTaskSchedulerPermittedIdentifiers</key> <array> <string>(grouphere)refreshtask</string> </array>

Hi

I am the OP's co-worker and the engineer who wrote the originally code. Here is what I am seeing. We have the permitted identifiers set. The info.plist did lose the refresh background mode setting from my commit to the one that the OP pulled to try this.

Using the same device the OP gets the error when scheduling the job on did enter background in the app delegate, on the same code from the repo I have the background task schedule and get a success response I can log.

AFAICT there’s no specific restriction on scheduling an app refresh task from your applicationDidEnterBackground(_:) delegate callback. I tried this today with a small test app and didn’t see anything weird.

Specifically, in my test app I have code like this in my app delegate:

    let log = Logger(subsystem: "com.example.apple-samplecode.Test780407", category: "app-refresh")
    
    func register() {
        log.log("will register")
        let ok = BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.example.test-task-id", using: .main) { t in
            self.log.log("task did run")
        }
        if ok {
            log.log("did register")
        } else {
            log.log("did not register")
        }
    }
    
    var isScheduled = false
    
    func schedule(source: String) {
        do {
            if self.isScheduled {
                self.cancel()
            }
            log.log("will schedule, source: \(source, privacy: .public)")
            let request = BGAppRefreshTaskRequest(identifier: "com.example.test-task-id")
            try BGTaskScheduler.shared.submit(request)
            log.log("did schedule")
            self.isScheduled = true
        } catch {
            log.log("did not schedule, error: \(error)")
        }
    }
    
    func cancel() {
        log.log("will cancel")
        BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: "com.example.test-task-id")
        self.isScheduled = false
        log.log("did cancel")
    }

I then added:

  • A call to register() in my applicationDidFinishLaunching(_:).

  • Two buttons, Schedule and Cancel, wired up to the corresponding methods.

Using this I was able to test that the schedule and cancel functionality works in general.

Next I added this code:

func applicationDidEnterBackground(_ application: UIApplication) {
    self.schedule(source: "did enter background")
}

On moving the app to the background, I see that method run and successfully schedule the task.

Oh, and I ran this test both with the app run from Xcode and the app run from the Home screen, just in case there’s something weird about the Xcode environment.


It sounds like there’s been some recent thrash in your main app. Given that, I recommend that you start with a new test project that focuses on just this facility. You can crib my code above to get you started. I suspect you’ll find that things work there, after which it’s time to compare your main app to your test app to see what’s different.

Alternatively, if you can reproduce the exception with the test app, that’d be quite interesting. In that case I suggest you reply back here with the details, including a full crash report. See Posting a Crash Report for info on how to attach that.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

hi! we ended up finding out this was an issue on our flagging system. The register was too early in our app lifecycle and was not being run. Fixing this also resolved this issue. Thank you

iOS BGTaskScheduler
 
 
Q