How it works
BackgroundTask is a structure that names a kind of background work your app can be launched or resumed to handle — app refresh, URL session completions, push-triggered processing, and similar system-scheduled events. When the system wakes your app outside of normal foreground use, it does so on behalf of one of these tasks, and BackgroundTask is the identifier SwiftUI uses to route that wake-up to the right handler. Reach for it whenever you need to declaratively register code that runs while your app is in the background, rather than managing those callbacks imperatively through the app delegate.
Register a handler with backgroundTask(_:action:)
You don't construct a
BackgroundTaskdirectly; instead you attach thebackgroundTask(_:action:)scene or view modifier and pass the task you want to respond to. SwiftUI invokes the supplied action whenever the system runs that background task. Here the modifier is applied to the refresh card so its closure fires when the registered task is scheduled.Choose the task with a static factory like appRefresh
The first argument is a typed value describing the category of background work —
BackgroundTaskexposes static factories such as.appRefreshthat produce the matching task descriptor. The example registers.appRefresh("com.example.refresh"), tying the handler to an app-refresh task whose identifier the system uses when it decides to wake the app.Match the task identifier to your declared identifier
The string passed to the factory must correspond to a background task identifier your app has declared to the system. In the example that identifier is
"com.example.refresh"; the system schedules and dispatches work against this exact name, so it links the SwiftUI registration to the platform's background task plumbing.Do the work in the action closure
The action you provide runs when the task executes, and it is where you perform the background work — fetching new data, finishing a transfer, or updating state. The example's closure assigns to
lastRefresh, standing in for the real work and surfacing that the background task ran by updating the visibleText("Last run: \(lastRefresh)").
lastRefresh to the current time, e.g. lastRefresh = Date().formatted(), so each background run is visibly distinct instead of always reading "Background fetch complete".Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct BackgroundTaskDemo: View {
@State private var lastRefresh = "Never"
var body: some View {
VStack(spacing: 12) {
Image(systemName: "arrow.clockwise.circle")
.font(.largeTitle)
.foregroundStyle(.blue)
Text("App Refresh Task")
.font(.headline)
Text("Last run: \(lastRefresh)")
.font(.caption)
.foregroundStyle(.secondary)
}
.padding()
.backgroundTask(.appRefresh("com.example.refresh")) {
lastRefresh = "Background fetch complete"
}
}
}