DEV Community

Cover image for iOS 27 Crashing Your App at Launch? Every Fix for the UIScene Lifecycle Error
Rushikesh Pandit
Rushikesh Pandit

Posted on

iOS 27 Crashing Your App at Launch? Every Fix for the UIScene Lifecycle Error

You rebuilt your app, it compiled with zero warnings, and the moment it opens on an iOS 27 device it vanishes. No JS error. No managed exception. Just a flash of the launch screen and a dead process.

If that's you, you've probably hit this line in the device log:

Application failed to launch: UIScene life cycle is required for apps
 built with this SDK.
Enter fullscreen mode Exit fullscreen mode

This post explains what is actually happening, and walks through every fix I could verify, from plain UIKit to React Native, Expo, and a few other stacks.

First, a correction to the common story

The popular framing is "apps built with older Xcode crash on iOS 27". The sources I checked say the opposite:

  • The check is tied to the SDK you build with, not the iOS version on the phone.
  • An app built with Xcode 26 (iOS 26 SDK) still launches on iOS 27.
  • An app built with Xcode 27 (iOS 27 SDK) that hasn't adopted the UIScene lifecycle is killed at launch on iOS 27.

Apple's iOS & iPadOS 27 release notes put it in one sentence: apps built with the latest SDK must adopt the scene-based life cycle or they fail to launch. That is why "it worked yesterday" is true: nothing in your code changed, only your toolchain did.

A nasty side effect: the same Xcode 27 build can still launch fine on iOS 26, so a smoke test on an older phone can pass while every iOS 27 user crashes.

How to confirm it's this crash

The crash report looks like this:

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0  UIKitCore  ___UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption_block_invoke
Enter fullscreen mode Exit fullscreen mode

If you see NoSceneLifecycleAdoption in the top frames, you're in the right place. It happens in both Debug and Release.

Do you need to migrate?

Per Apple's TN3187, migrate if either is true:

  1. The UIApplicationSceneManifest key is missing from your Info.plist, or it has no configurations.
  2. Your app delegate doesn't implement application(_:configurationForConnecting:options:).

Note that a manifest containing only UIApplicationSupportsMultipleScenes does not count as adopting scenes. Also, only adoption is required. You do not have to support multiple windows.

Fix 1: Adopt scenes in a native UIKit app (the real fix)

Step 1: Add the scene manifest to Info.plist

<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>
                <key>UISceneStoryboardFile</key>
                <string>Main</string>
            </dict>
        </array>
    </dict>
</dict>
Enter fullscreen mode Exit fullscreen mode

If you use a storyboard, keep the storyboard name in the scene configuration. If you build your UI in code, drop UISceneStoryboardFile.

Step 2: Create a SceneDelegate that owns the window

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        guard let windowScene = scene as? UIWindowScene else { return }

        window = UIWindow(windowScene: windowScene)
        window?.rootViewController = YourRootViewController()
        window?.makeKeyAndVisible()
    }
}
Enter fullscreen mode Exit fullscreen mode

Remove window creation from application(_:didFinishLaunchingWithOptions:). An app delegate that creates its own UIWindow with no scene delegate is exactly what triggers the crash.

Step 3: Move the lifecycle callbacks

UIApplicationDelegate UISceneDelegate
applicationDidBecomeActive(_:) sceneDidBecomeActive(_:)
applicationWillResignActive(_:) sceneWillResignActive(_:)
applicationDidEnterBackground(_:) sceneDidEnterBackground(_:)
applicationWillEnterForeground(_:) sceneWillEnterForeground(_:)

Optional: configure scenes in code instead of the plist

If you need dynamic configuration, implement this in your app delegate:

func application(
    _ application: UIApplication,
    configurationForConnecting connectingSceneSession: UISceneSession,
    options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
    UISceneConfiguration(name: "Default Configuration",
                         sessionRole: connectingSceneSession.role)
}
Enter fullscreen mode Exit fullscreen mode

Fix 2: Don't forget what silently stops working after you migrate

Adopting scenes fixes the launch crash, but it moves responsibilities. These are the regressions that compile fine and fail quietly:

  • Deep links and universal links. URL opens and user activities go to the scene delegate. application(_:open:options:) and application(_:continue:restorationHandler:) on the app delegate stop being called.
  • Cold-start links. A link that launches the app no longer shows up in launchOptions. It arrives in connectionOptions.urlContexts and connectionOptions.userActivities inside scene(_:willConnectTo:options:).
  • Startup code that assumes a window. didFinishLaunching now returns before any window exists. Anything touching the window or root view controller belongs after the scene connects.
  • Code that reads UIApplication.shared.delegate?.window. The app delegate no longer owns the window.

Test deep links two ways: with the app running, and with the app fully closed.

Fix 3: React Native

Check where you stand

You've adopted scenes if your Info.plist has a UIApplicationSceneManifest with scene configurations, or your app delegate implements application(_:configurationForConnecting:options:).

Upgrade path

  • React Native 0.88 is reported as the first release whose template adopts scenes: a SceneDelegate.swift starts React Native in the window scene and Info.plist references it. As of early October it was still a release candidate.
  • 0.87 and earlier have nothing in the template. Upgrade, then copy the scene delegate and the Info.plist changes from the Upgrade Helper.

The library crash that appears after you adopt scenes

On the new template the AppDelegate has no window property. Libraries that still do this will crash:

UIViewController *root = [UIApplication sharedApplication].delegate.window.rootViewController;
Enter fullscreen mode Exit fullscreen mode
-[AppDelegate window]: unrecognized selector sent to instance
Enter fullscreen mode Exit fullscreen mode

The one-line fix inside the library is:

UIViewController *root = RCTPresentedViewController();  // or RCTKeyWindow().rootViewController
Enter fullscreen mode Exit fullscreen mode

Libraries reported to be affected by this pattern include react-native-blob-util, @react-native-firebase/messaging (crashes at launch), react-native-google-mobile-ads, react-native-date-picker, react-native-image-crop-picker, and rn-fetch-blob. Until upstream ships fixes, a patch-package patch with the line above works. Check each library's open PRs first.

Forward deep links from the scene delegate

Nothing crashes if you forget this. Linking just stops firing. A sketch to adapt to your project:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else { return }
    RCTLinkingManager.application(UIApplication.shared, open: url, options: [:])
}

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    RCTLinkingManager.application(UIApplication.shared,
                                  continue: userActivity,
                                  restorationHandler: { _ in })
}
Enter fullscreen mode Exit fullscreen mode

Also read connectionOptions.urlContexts in willConnectTo for cold starts.

Fix 4: Expo

  • SDK 58 (in beta since mid-September) is reported to generate the scene delegate by default.
  • SDK 57 can opt in. It needs expo 57.0.23+ and expo-build-properties 57.0.20+:
["expo-build-properties", { "ios": { "enableSceneSupport": true } }]
Enter fullscreen mode Exit fullscreen mode

Then regenerate the native project:

npx expo prebuild --clean
Enter fullscreen mode Exit fullscreen mode
  • SDK 56 and earlier need an SDK upgrade first.
  • If your ios/ folder is generated by prebuild and the template still creates the window in didFinishLaunching, one team solved it durably with a small config plugin that applies the two changes on every prebuild, rather than hand-editing a folder that gets regenerated.

Fix 5: Other stacks

  • .NET MAUI. Add Platforms/iOS/SceneDelegate.cs deriving from MauiUISceneDelegate (registered as SceneDelegate), and add the scene manifest to every iOS Info.plist, using the configuration name __MAUI_DEFAULT_SCENE_CONFIGURATION__. Templates from MAUI 10.0.110 (22 Sept 2026) include this. Older projects don't get it automatically, so upgrading the package alone does not fix an existing app. Don't forget every flavor-specific plist.
  • Cordova. cordova-ios 8.1.1 apps built with Xcode 27 are reported to show a blank screen and the same error. Track the open issue in apache/cordova-ios (#1725) and update the platform and any plugins that inject windows into the app delegate.
  • Tauri / Dioxus. Release builds with a scene manifest crashed until a fix in tao, reported as shipped in tao 0.37.0. Update the dependency and regenerate the iOS project.
  • Flutter and native plugins. One vendor reported an EXC_BAD_ACCESS near GeneratedPluginRegistrant.register(with:) after adopting scenes, caused by plugin code that expected registrar setup in the app delegate. If you use Flutter, check your Flutter version's iOS scene guidance and update plugins that handle deep links.
  • Third-party SDKs. Some vendors ship separate SDK lines per Xcode major version (for example Microsoft's Intune SDK has a release line for Xcode 26 and a different one for Xcode 16). Check your SDKs' release notes before switching toolchains.

Fix 6: Stay on Xcode 26 for now (a stopgap, not a plan)

If you can't migrate this week, keep production builds on the toolchain that works. One open-source team fixed a TestFlight launch crash on iOS 27.2 by pinning their store builds to Xcode 26.6, after confirming the working build was linked against the iOS 26.5 SDK.

In practice that means:

  1. Pin Xcode 26.6 on your CI image (for EAS, a macos-tahoe-26.5-xcode-26.6 image).
  2. Keep a separate lane that builds with Xcode 27 so you find breakage early.
  3. Check your build's SDK: the DTXcode and DTSDKName keys in the built Info.plist tell you which SDK produced it.

A reported deadline makes this temporary: Apple is said to have announced that from April 2027, apps uploaded to App Store Connect must be built with the iOS 27 SDK. I could not confirm that on Apple's own pages, so verify it in your App Store Connect announcements before planning around it.

Fix 7: Other Xcode 27 issues you may hit in the same upgrade

These are build-time or tooling problems rather than the launch crash, but they tend to show up together:

  • Deployment target errors. Xcode 27 rejects pods declaring an IPHONEOS_DEPLOYMENT_TARGET below 15.0. A common fix is a post_install hook in your Podfile that raises the target for offending pods.
  • No Simulator.app. One report says Xcode 27 no longer ships Simulator.app (it ships DeviceHub.app), which broke expo run:ios on older @expo/cli versions. Update your CLI tooling.
  • Stale build data. After toolchain changes, clear it: rm -rf ~/Library/Developer/Xcode/DerivedData/* and rebuild.
  • Beta-era dyld crashes. If your app dies before any Swift runs on an iOS 27 beta device, it can be a third-party framework symbol issue rather than scenes. Update the dependency and file a Feedback report.

A checklist you can paste into a ticket

  1. Confirm the crash: NoSceneLifecycleAdoption in the report.
  2. Add UIApplicationSceneManifest with a scene configuration to every Info.plist (all flavors).
  3. Add a SceneDelegate that creates the window; remove window creation from the app delegate.
  4. Move applicationDidBecomeActive and friends to the scene equivalents.
  5. Move URL and user-activity handling to the scene delegate; handle cold-start links from connectionOptions.
  6. Audit dependencies for delegate.window and similar app-delegate assumptions.
  7. Delete DerivedData, rebuild with Xcode 27.
  8. Test on an iOS 27 simulator or device. An iOS 26 device will not show the problem.
  9. Test deep links, push taps and every picker/ad/menu that presents UI, from both warm and cold starts.

Wrap-up

The takeaway is less "old Xcode breaks on iOS 27" and more "the moment you move to Xcode 27, Apple's long-announced scene requirement becomes an assert". The fix itself is small, the follow-on regressions (deep links, window-dependent startup, third-party libraries) are where the time goes, so adopt scenes while you're still on Xcode 26, ship it, and then upgrade the toolchain.

If you've hit a variant I didn't cover, tell me in the comments and I'll add it.

Sources

Found this helpful? Drop a ❤️ on the article!
Questions or suggestions? Drop them in the comments below.

Feel free to reach out:
LinkedIn: https://www.linkedin.com/in/rushikesh-pandit-646834100/
GitHub: https://github.com/rushikeshpandit
Portfolio: https://www.rushikeshpandit.in

#ReactNative #MobileDevelopment #SoftwareEngineering #iOS #Swift #iOS27

Top comments (0)