Even in a very simple UIKit test project, I'm not able to get BGContinuedProcessingTask (new in iOS 26) to do anything.
But using essentially the same code in a SwiftUI project, it works fine.
So my question is: has anyone been able to work out a way of getting BGContinuedProcessingTask to work in a UIKit project?
The example code here is based on https://github.com/infinitepower18/BGContinuedProcessingTaskDemo — I'm doing exactly what that code does, and indeed that code works fine on my device, but when I put the same code into a UIKit project, the task never runs. (You should assume that I've set up my Info.Plist and capabilities correctly; that's not the issue.)
import UIKit
import BackgroundTasks
import SwiftUI
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
register()
}
var registeredCleanupTask = false
/// Registers the background continued processing task with the system.
private func register() {
if registeredCleanupTask {
return
}
registeredCleanupTask = true
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.neuburg.matt.test.cleanup2", using: nil) { task in
guard let task = task as? BGContinuedProcessingTask else { return }
var wasExpired = false
task.expirationHandler = {
wasExpired = true
}
task.progress.totalUnitCount = 100
task.progress.completedUnitCount = 0
while (task.progress.completedUnitCount < task.progress.totalUnitCount) && !wasExpired && !task.progress.isFinished {
sleep(1)
task.progress.completedUnitCount += 1
task.updateTitle("Title", subtitle: "\(task.progress.completedUnitCount)% complete")
}
task.setTaskCompleted(success: true)
}
}
/// Runs the background continued processing task.
private func runTask() {
let request = BGContinuedProcessingTaskRequest(
identifier: "com.neuburg.matt.test.cleanup2",
title: "Title",
subtitle: "Running..."
)
request.strategy = .queue
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print(error)
}
}
@IBAction func doButton(_ sender: Any) {
runTask()
}
}
Using UIKit is totally fine here. There is a undocumented behaviour here:
You must prefix task id with your app's bundle ID
Other wise an error in console will hints us:
[bgContinuedProcessing-com.task.background] Does not have the correct prefix (expected com.cleverlearn.continueTaskDemo, found com.task.background)
Interestingly, apple mentioned this requirement in BGContinuedProcessingTaskRequest's init method:
/// Creates an instance on behalf of the currently foregrounded app.
///
/// Apps and their extensions should use this method to initialize any tasks due to the underlying association to the
/// currently foregrounded app. Please note that ``BGTaskRequest/earliestBeginDate`` will be outright ignored by the
/// scheduler in favor of `NSDate.now`.
///
/// The identifier ought to use wildcard notation, where the prefix of the identifier must at least contain the bundle
/// ID of the submitting application, followed by optional semantic context, and finally ending with `.*`. An example:
/// `<MainBundle>.<SemanticContext>.*` which would transform to `com.foo.MyApplication.continuedProcessingTask.*`. Thus,
/// a submitted identifier would be of the form `com.foo.MyApplication.continuedProcessingTask.HD830D`.
///
/// - Parameters:
/// - identifier: The task identifier.
/// - title: The localized title displayed to the user before the task begins running.
/// - subtitle: The localized subtitle displayed to the user before the task begins running.
/// - Warning: Successful creation of this object does not guarantee successful submission to the scheduler.
public init(identifier: String, title: String, subtitle: String)
Which confirms that we need to prefix the task id with bundle id.