Apple's guide Transitioning to the UIKit scene-based life cycle has one sentence every UIKit team should read: beginning in iOS 27, apps built with the latest SDK "must adopt the scene-based life cycle or they fail to launch."
The deadline that turns this into everyone's problem is on App Store submissions: "Starting April 2027", iOS and iPadOS apps uploaded to App Store Connect "must be built with the iOS & iPadOS 27 SDK or later", and target iOS 15 or later. Today the Upcoming Requirements page still asks for Xcode 26 and the iOS 26 SDK, so you have time. You do not have a warning, though: the project compiles with Xcode 27 and stops only when it runs.
This article is about native UIKit apps. Adding a scene manifest is the easy half. The harder half is the app delegate code that silently stops running once a scene exists.
The test app
To have something concrete, I use the native-uikit fixture from sdkbump, an open-source CLI I wrote. It is a small UIKit app called Shelf that does everything the old way: it creates the window in application(_:didFinishLaunchingWithOptions:), reads links and quick actions from launchOptions, handles custom-scheme links, universal links and Handoff in the app delegate, and finds the window through keyWindow.
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = UINavigationController(rootViewController: router.root)
window.makeKeyAndVisible()
self.window = window
if let url = launchOptions?[.url] as? URL {
router.open(url)
}
According to the fixture notes in the repository (recorded 15 October 2026, not repeated today), built with Xcode 27.0 and launched on an iOS 27.0 simulator, the app stops with: "UIScene life cycle is required for apps built with this SDK."
What a static check finds
In the app folder:
npx @mcamdali/sdkbump
Excerpt of today's output (sdkbump 0.1.5, rules ios27@2026.10.27, exit code 1):
Shelf · native iOS · .
target Shelf: app delegate life cycle (Shelf/Info.plist)
Fails to launch when built with the iOS 27 SDK.
ERROR SCN001 No scene configuration
ERROR SCN002 Window created in the app delegate
WARNING SCN003 launchOptions[.url] is empty with scenes
WARNING SCN003 launchOptions[.shortcutItem] is empty with scenes
WARNING SCN003 application(_:open:options:) is not called with scenes
WARNING SCN003 application(_:continue:restorationHandler:) is not called with scenes
WARNING SCN003 application(_:performActionFor:completionHandler:) is not called with scenes
WARNING SCN003 applicationDidBecomeActive(_:) is not called with scenes
WARNING SCN003 applicationDidEnterBackground(_:) is not called with scenes
WARNING SCN004 Window looked up through keyWindow
WARNING SCN004 Window looked up through UIApplication.windows
2 errors, 9 warnings
The two errors are the launch problems. The nine warnings are the reason I wrote the tool: each one is code that compiles, runs today, and does nothing once the app has a scene.
Where each callback goes
This table is the report's own advice for each warning, condensed:
| App delegate code | With scenes, use |
|---|---|
launchOptions[.url] |
connectionOptions.urlContexts in scene(_:willConnectTo:options:)
|
launchOptions[.shortcutItem] |
connectionOptions.shortcutItem |
application(_:open:options:) |
scene(_:openURLContexts:) |
application(_:continue:restorationHandler:) |
scene(_:continue:), plus connectionOptions.userActivities
|
application(_:performActionFor:completionHandler:) |
windowScene(_:performActionFor:completionHandler:) |
applicationDidBecomeActive(_:) |
sceneDidBecomeActive(_:), or UIApplication.didBecomeActiveNotification for the whole app |
applicationDidEnterBackground(_:) |
sceneDidEnterBackground(_:), or UIApplication.didEnterBackgroundNotification
|
keyWindow, UIApplication.shared.windows
|
view.window, or the foreground UIWindowScene from connectedScenes
|
Notice the pattern in the first rows. Every entry point now has two places: one for a link or action that launches the app (the connection options) and one for a link that arrives while it is running (the scene callback). Moving only the second is the most common way to ship a broken cold-start deep link.
The migrated version
The same repository has native-uikit-scenes, Shelf moved to a scene delegate by hand. The window and the launch-time links move into scene(_:willConnectTo:options:):
guard let windowScene = scene as? UIWindowScene else { return }
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UINavigationController(rootViewController: router.root)
window.makeKeyAndVisible()
self.window = window
// Links and quick actions that launch the app arrive here instead of in launchOptions.
if let url = connectionOptions.urlContexts.first?.url {
router.open(url)
}
if let url = connectionOptions.userActivities.first?.webpageURL {
router.open(url)
}
if let item = connectionOptions.shortcutItem {
router.perform(item)
}
Info.plist gets the scene manifest, with one scene:
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
And the app delegate shrinks to application(_:didFinishLaunchingWithOptions:) returning true. Run against that project:
target Shelf: scene life cycle (Shelf/Info.plist)
No findings for the checks in ios27@2026.10.27.
0 errors, 0 warnings
Limitations
- sdkbump reads files. It does not build, run or change the project, so it cannot see code generated at build time or behaviour that depends on runtime state.
- The checks are patterns over source files, not a compiler. Treat each warning as a place to review, not as proof of a bug.
- The launch failure itself comes from Apple's documentation and the repository's recorded simulator run; I did not repeat the simulator run for this article. Build with Xcode 27 and launch on a device before you trust any checklist, this one included.
- It is a young tool (0.1.5). Reports of wrong findings are the most useful feedback.
Try it
In your app folder (native iOS, Flutter or React Native/Expo):
npx @mcamdali/sdkbump
npx @mcamdali/sdkbump --format markdown --output sdkbump.md
npx @mcamdali/sdkbump --fail-on warning
The exit code is 1 when there are findings at or above --fail-on (default: error), so the third line works as a CI gate. On the migrated fixture it exits 0; on the original it exits 1.
React Native teams have a version-specific path; it is in "React Native 0.88 is not enough for iOS 27: the SceneDelegate move you still have to make".
Repository: github.com/muhittincamdali/sdkbump (MIT).
Muhittin Camdali is a mobile engineer (iOS, Flutter, React Native) and the author of sdkbump.
Top comments (0)