On 9 September Apple announced that from April 2027, apps uploaded to App Store Connect must be built with the iOS 27 SDK, which means Xcode 27. Built with that SDK, an app that hasn't adopted the UIKit scene life cycle doesn't start. It stops at launch with:
Application failed to launch: UIScene life cycle is required for apps built with this SDK.
Apple announced the rule in TN3187. The check depends on the SDK you build with, not the iOS version on the phone. The same app built with Xcode 26 still runs on iOS 27, so nothing breaks for your users today. It breaks on the day you move to Xcode 27.
I run a health check on several hundred open-source React Native and Expo apps (the set I use to test NativeKeel). As of 11 October 2026:
| Apps | |
|---|---|
| React Native and Expo apps with an iOS target | 628 |
| Not on the scene life cycle yet | 583 (93%) |
| Largest groups | Expo SDK 57 (117), Expo SDK 54 (111) |
That number isn't a judgment on those apps. Until a few weeks ago, no React Native or Expo template used scenes at all.
Where React Native and Expo stand
-
React Native 0.88 is the first release whose template adopts it.
SceneDelegate.swiftstarts React Native in the window scene, andInfo.plistnames it inUIApplicationSceneManifest. 0.88 is still a release candidate (rc.4 on 7 October). 0.87 and earlier have nothing in the template, so the path is to upgrade and copy both files from the Upgrade Helper. -
Expo SDK 57 can opt in. It needs
expo57.0.23+ andexpo-build-properties57.0.20+:
["expo-build-properties", { "ios": { "enableSceneSupport": true } }]
Then run npx expo prebuild again.
- Expo SDK 58 (in beta since 15 September) generates the scene delegate by default.
- SDK 56 and earlier need an SDK upgrade first.
How do you know you've adopted it? Your Info.plist has a UIApplicationSceneManifest with scene configurations, or your app delegate implements application(_:configurationForConnecting:options:). A manifest that only sets UIApplicationSupportsMultipleScenes doesn't count.
The part that bites after you adopt it: AppDelegate has no window
In the 0.88 template the UIWindow belongs to the scene delegate. AppDelegate no longer has a window property at all.
Many iOS libraries still find the screen to present on like this:
UIViewController *root = [UIApplication sharedApplication].delegate.window.rootViewController;
On the new template that line throws:
-[AppDelegate window]: unrecognized selector sent to instance
I searched the iOS sources of popular React Native libraries for this call made without a respondsToSelector: check, and found it in 15 that are still in use. Then I built a fresh React Native 0.88.0-rc.4 app and confirmed the crash with two of them, react-native-blob-util and react-native-google-mobile-ads. Both stopped crashing after one change:
UIViewController *root = RCTPresentedViewController(); // or RCTKeyWindow().rootViewController
Both fixes are open as pull requests (react-native-blob-util#498, react-native-google-mobile-ads#911). For @react-native-firebase/messaging, which makes the call at launch, a fix was already proposed upstream (react-native-firebase#9359).
68 of the 628 apps depend on at least one of these libraries. The most common:
| Library | Apps | When it crashes |
|---|---|---|
| react-native-blob-util | 17 | presenting the open-in / options menu |
| @react-native-firebase/messaging | 17 | at launch |
| react-native-google-mobile-ads | 11 | showing banners, the consent form or the ad inspector |
| react-native-date-picker | 9 | opening the modal picker |
| react-native-image-crop-picker | 9 | opening the picker |
| rn-fetch-blob | 7 | presenting the open-in menu |
Until a release ships the fix, a patch-package patch with the line above works.
The quiet one: deep links stop arriving
With scenes, UIKit hands opened URLs and universal links to the scene delegate. application(_:open:options:) and application(_:continue:restorationHandler:) in AppDelegate aren't called anymore. If your scene delegate doesn't forward them to RCTLinkingManager, nothing crashes. Linking just never fires.
I found this in a wallet app that had already moved to scenes: its zcash: payment links stopped reaching JavaScript, both when the app was running and when the link launched it, because launchOptions was nil and the URL only arrived in the scene's connectionOptions (zingo-mobile#1595). If your app handles deep links, test them after the move: with the app running, and with the app closed.
A checklist
- Check whether you've adopted scenes (the
Info.plisttest above). - Expo: SDK 57 with
enableSceneSupport, or SDK 58. Bare React Native: plan the 0.88 upgrade. - List your dependencies against the libraries above and update or patch them before you build with Xcode 27.
- Forward URLs and user activities from the scene delegate to
RCTLinkingManager. - Build with Xcode 27 well before April. Test launch, every screen that presents a picker, menu or ad, and deep links from a cold start.
Check your app in one command
npx nativekeel
It reports whether the app has adopted the scene life cycle, which of your installed libraries read the window from the app delegate, and whether URL handlers are still only in AppDelegate. It runs locally, without an account, and doesn't upload your code. If you hit the crash already:
npx nativekeel explain "-[AppDelegate window]: unrecognized selector"
If you upgrade with an AI agent, the same checks are available over MCP, and there's a Claude Code plugin (claude plugin marketplace add AlicanAkyol/nativekeel), so the agent checks this before it starts changing versions. A longer reference with the sources is at nativekeel.com/fix/uiscene-life-cycle-required-xcode-27.
If you maintain one of the libraries above and want a hand with the fix, I'm happy to send a PR.
Top comments (0)