iosswiftbackground-process

BGContinuedProcessingTask - is this thing on? in UIKit, that is


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()
    }
}


Solution

  • 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)

    enter image description here

    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.