ConfusedByCode
ConfusedByCode

Reputation: 1730

Can I handle a BGProcessingTask with SwiftUI's backgroundTask(_:) scene modifier?

I'm working on an app that needs to process cached location data in the background periodically. While the task usually completes in less than 30 seconds, it could potentially be battery- and network-intensive, as it reverse-geocodes multiple cached locations. And since the task can be considered "database maintenance", I would like to implement it as a background processing task (BGProcessingTask).

I am trying to use SwiftUI's backgroundTask(_:) scene modifier to handle the task. I have watched the "Efficiency Awaits" WWDC video (https://developer.apple.com/wwdc22/10142) and read the documentation, and I have not found any information about how to handle BGProcessingTasks. BackgroundTask provides appRefresh and urlSession tasks, but not background processing tasks.

I have tried registering a BGProcessingTaskRequest, and then handling it with .appRefresh. A simplified version of my code looks like this:

struct MyApp: App {
    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { _, newValue in
            if case .background = newValue {
                scheduleBackgroundTasks()
            }
        }
        .backgroundTask(.appRefresh("com.MyCompany.MyApp-ProcessLocations")) {
            scheduleBackgroundTasks()
            do {
                try await AppDataStore.processLocations()
            } catch {
                print(error)
            }
        }
    }
}

func scheduleBackgroundTasks() {
    let taskDate = nextTaskDate()
    let bgTaskRequest = BGProcessingTaskRequest(
        identifier: "com.MyCompany.MyApp-ProcessLocations"
    )
    bgTaskRequest.earliestBeginDate = taskDate
    bgTaskRequest.requiresExternalPower = true
    bgTaskRequest.requiresNetworkConnectivity = true
    try? BGTaskScheduler.shared.submit(bgTaskRequest)
}

The task successfully runs when triggering it with the debugging method used in the WWDC videos, but since I can't find any published info on the subject, I don't know if it's safe to do this in production.

What are the implications of handling the processing task with .appRefresh? For example will the system allow my app to run for the amount of time allocated to processing tasks, or will it be terminated after 30 seconds like an app refresh task? Will the backgroundTask modifier correctly tell the system when the task completes?

Finally, if the backgroundTask modifier can't be used, how should background processing tasks be handled in a SwiftUI app?

Upvotes: 1

Views: 295

Answers (0)

Related Questions