In a scene-based app, which callbacks fire at launch and on activation, and which app delegate callbacks go silent?

6.11.2 · L3 · Interview

Mental model. The company (the app) used to have one front door and one “open for business” bell. Once the company has several shops (scenes), each shop rings its own bell, and head office only announces things that concern everyone.

In an app that declares a scene manifest, the launch sequence observed on the iOS 27.2 simulator with a UIKit app logging every callback was: willFinishLaunching → didFinishLaunching → application(_:configurationForConnecting:options:) → scene(_:willConnectTo:options:) → sceneWillEnterForeground → sceneDidBecomeActive. Notice what was absent: the app delegate’s applicationDidBecomeActive, applicationWillEnterForeground, applicationWillResignActive and applicationDidEnterBackground were never called. Once an app adopts scenes, those transitions are delivered per scene (sceneDidBecomeActive, sceneDidEnterBackground, and so on) because with several windows (iPad, Mac Catalyst, visionOS, external displays) there is no single “the app became active”. The application-wide notifications (UIApplication.didBecomeActiveNotification, willResignActiveNotification) remain, and are the right place for code that is truly app-wide.

What to do with this: keep one-time setup (SDKs, dependency container, BGTaskScheduler registration, notification delegate) in didFinishLaunching, per-window state in the scene delegate, and code that pauses and resumes work on the scene callbacks or on scenePhase in SwiftUI (Q214). A cold launch triggered by a URL or a shortcut hands you the information in the scene’s connectionOptions (urlContexts, userActivities, shortcutItem), not in the app delegate’s launch options; a warm one delivers it through scene(_:openURLContexts:) and similar callbacks, so handle both paths. Be honest about the limits: this order was observed once on the simulator, not asserted by the site’s automated checks, the exact interleaving can differ across OS versions and launch paths (state restoration, prewarming, a background launch, which may connect no scene at all), and a debugger or a visible alert adds an inactive phase before activation.

Common traps

  • Putting “resume” work in applicationDidBecomeActive of a scene-based app. It will never be called; use the scene callback or the notification.
  • Handling a launch URL only in didFinishLaunching. With scenes the cold-launch URL arrives in the scene’s connection options.

They might follow up with

  • Where does SwiftUI code observe this? In scenePhase on a scene or view, and onOpenURL for links.
  • Can an app launch without any scene? Yes, when the system launches it in the background (a push, a background task); then only the app delegate runs.

Related questions

  • 6.2.1 What are the app states, and which callbacks fire as you move between them?
  • 6.2.2 What is a scene, and what is the split between AppDelegate and SceneDelegate?
  • 6.2.3 What happens inside UIApplicationMain, and how does @main on a SwiftUI App differ?
  • 6.2.4 How does the SwiftUI lifecycle map onto UIKit’s, and what is scenePhase for?
  • 6.7.2 What is the difference between a custom URL scheme and a universal link, and which do you use?
  • 6.11.1 How do launch arguments and environment variables reach an app, and why does “-key value” override…

← How do launch arguments and environment variables reach an app, and…   How do you inspect what a binary links, what load commands it has and… →