How does a background URLSession keep working when the app is not running?

6.5.4 · L3 · Interview

Predict first

What are the defaults for a background session configuration?

import Foundation

let c = URLSessionConfiguration.background(withIdentifier: "x")
print(c.sessionSendsLaunchEvents, c.isDiscretionary, URLSessionConfiguration.default.sessionSendsLaunchEvents)
  • false false false
  • true false false
  • true true true

Mental model. You hand a parcel to a courier and go home. The courier delivers it and knocks on your door to tell you when it is done.

A session created with URLSessionConfiguration.background(withIdentifier:) hands its transfers to a system daemon, which performs them outside your process. They continue while the app is suspended and even after it is terminated. When something needs your attention the system relaunches the app in the background. In the app delegate, application(_:handleEventsForBackgroundURLSession:completionHandler:) gives you a completion handler to keep, and you recreate the session with the same identifier; its delegate then receives the pending events, and urlSessionDidFinishEvents(forBackgroundURLSession:) is the place to call the handler.

The constraints follow from the design. A background session works with delegates only (no completion handlers or async API), uploads must come from a file and not an in-memory Data, and downloads arrive as temporary files you must move before the delegate returns. isDiscretionary lets the system choose a good time (Wi-Fi, power) for large, non-urgent transfers, and sessionSendsLaunchEvents controls whether the app is relaunched; it is on by default for background sessions. Keep the identifier stable, and handle that the app may be launched purely to receive these events.

A background configuration sends launch events by default and is not discretionary. A default (foreground) configuration does neither.

Common traps

  • Creating the session lazily and with a new identifier each launch. You lose the pending events from the previous run.
  • Using an in-memory body for a background upload. It must be a file the system can read after your process is gone.

They might follow up with

  • What happens if the user force-quits the app? The system stops its background transfers; they are not guaranteed to continue.
  • Why must the session identifier stay the same? It is how the system matches the pending transfers to the session you recreate.

Related questions

  • 6.5.1 An app goes to the background. What can it still do, and how do you choose a mechanism?
  • 6.5.3 How does BGTaskScheduler work, and why does your task not run when you ask?

← How does BGTaskScheduler work, and why does your task not run when…