Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2025 System Services

WWDC25 · 19 min · System Services

Finish tasks in the background

Discover background execution advancements and understand how the system schedules runtime. We’ll discuss how to get the most out of background runtime to allow your app to deliver features in the background while maintaining a great foreground experience. We’ll also cover how APIs provide background runtime for your app, and how each API is tailored for different use cases — including new APIs in iOS and iPadOS 26 that let your app finish tasks as your app transitions from the foreground to the background.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 5 snippets

Register an app refresh task swift · at 8:27 ↗
import BackgroundTasks
import SwiftUI

@main
struct ColorFeed: App {
    var body: some Scene {
        WindowGroup {
            // ...
        }
        .backgroundTask(.appRefresh("com.colorfeed.wwdc25.appRefresh")) {
            await self.handleAppRefreshTask()
        }
    }
}
Register a processing task swift · at 9:45 ↗
import BackgroundTasks
import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        BGTaskScheduler.shared.register(
            forTaskWithIdentifier: "com.example.apple-samplecode.ColorFeed.db_cleaning",
            using: nil
        ) { task in
            self.handleAppRefresh(task: task as! BGProcessingTask)
        }
    }

    func submitProcessingTaskRequest() {
        let request = BGProcessingTaskRequest(
            identifier: "com.example.apple-samplecode.ColorFeed.db_cleaning"
        )
        request.requiresNetworkConnectivity = true
        request.requiresExternalPower = true

        BGTaskScheduler.shared.submit(request)! 
    }
}
Begin and end background task swift · at 10:51 ↗
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
   
    func saveState() { /*  ... */ }

    func handlePersistence() {
        let app = UIApplication.shared
        guard backgroundTaskID != .invalid else { return }
        backgroundTaskID = app.beginBackgroundTask(withName: "Finish Export") {
            app.endBackgroundTask(self.backgroundTaskID)
            self.backgroundTaskID = .invalid
        }

        self.saveState()

        app.endBackgroundTask(backgroundTaskID)
        backgroundTaskID = .invalid
    }
}
Continued processing task registration swift · at 14:00 ↗
import BackgroundTasks

func handleDialogConfirmation() {
    BGTaskScheduler.shared.register("com.colorfeed.wwdc25.userTask") { task in
        let task = task as! BGContinuedProcessingTask
                                                                      
        var shouldContinue = true
        task.expirationHandler = {
            shouldContinue = false
        }

        task.progress.totalUnitCount = 100
        task.progress.completedUnitCount = 0

        while shouldContinue {
            // Do some work
            task.progress.completedUnitCount += 1
        }

        task.setTaskCompleted(success: true)
    }
}
Continued processing task submission swift · at 15:47 ↗
import BackgroundTasks

func submitContinuedProcessingTaskRequest() {
    let request = BGContinuedProcessingTaskRequest(
        identifier: "com.colorfeed.wwdc25.userTask",
        title: "A succinct title",
        subtitle: "A useful and informative subtitle"
    )

    request.strategy = .fail

    BGTaskScheduler.shared.submit(request)!
}

Resources