fix(ios): adopt the UIScene life cycle so Xcode 27 builds launch - #29649
Draft
chrisnojima wants to merge 3 commits into
Draft
chrisnojima wants to merge 3 commits into
chrisnojima wants to merge 3 commits into
Conversation
Apps built with the iOS 27 SDK trap at launch in _UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption unless they use scenes. SceneDelegate builds on Expo's ExpoAppSceneDelegate, which forwards lifecycle, URL and user-activity events to the AppDelegate overrides, and moves React Native's root view controller into a KeyboardWindow so hardware enter/shift-enter keep working.
…s under scenes sceneDidBecomeActive is forwarded to applicationDidBecomeActive while applicationState still reads .inactive, so notifyAppState told Go INACTIVE and the local http server stayed stopped, leaving images blank.
Use the stock @objc(SceneDelegate) ExpoAppSceneDelegate with only a post-connect hook for root view setup. Drop KeyboardWindow in favor of handling hardware enter/shift-enter on the app delegate at the end of the responder chain, and drop the manual RCTLinkingManager overrides that Expo's scene forwarder already covers.
chrisnojima
added this pull request to stack #29658
September 21, 2026 18:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack 1/9, splitting #29637. Base:
master.Why
iOS 27 requires an app to adopt the UIScene life cycle. Without it, a build made with Xcode 27 traps at launch inside
_UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption— the app does not start at all. That makes this a prerequisite for building the app with the current toolchain, independent of everything else in the stack.What master does today
UIApplicationSceneManifest, no scene delegate: the app is still on the pre-sceneUIApplicationlife cycle and cannot launch under Xcode 27.AppDelegate.didFinishLaunchingbuilds aKeyboardWindowand starts React Native itself, so all root-view setup is tied to launch rather than to a scene connecting.KeyboardWindowsubclass.What this changes and why each piece
Info.plistgains aUIApplicationSceneManifestnamingSceneDelegate;SceneDelegatesubclasses Expo'sExpoAppSceneDelegate. This is the adoption itself.didFinishLaunchinginto a newdidStartReactNative(in:), because under scenes the window does not exist until a scene connects.BGTaskScheduler.registerdeliberately stays indidFinishLaunching— iOS requires it to run before that returns.KeyboardWindowis deleted and hardware enter / shift-enter move topressesBeganon the delegate. Expo's scene delegate owns window creation now, so a customUIWindowsubclass has nowhere to be installed; the responder chain gives the same behaviour.RCTLinkingManagerpassthrough overrides are deleted because Expo'sSceneEventForwarderalready forwards them; keeping both would double-deliver. Thekeybase://incoming-sharepath re-adds an explicit call, since it does not go through the forwarder.applicationDidBecomeActivereports foreground directly.sceneDidBecomeActiveis forwarded whileUIApplication.applicationStatestill reads.inactive, so the old state-derived path would have concluded "not foreground" and stopped the local http server — which shows up as blank images.Scope
No Go, JS or protocol change. The Swift symbol set is identical to master's, so no rebuilt
Keybasego.xcframeworkis required. That is what lets this land first and alone.Verification
iOS builds under Xcode 27 (
BUILD SUCCEEDED, no warnings in our code).Worth a manual pass, because these are behaviours the compiler cannot check: cold launch, images loading, hardware enter / shift-enter in the chat input, and a universal link plus a
keybase://link both cold and warm — the linking overrides were removed rather than relocated.Ordering
Under scenes RN's
AppStatecan stick atinactive(RCTAppStatededupes on last-known state), somobileAppStatestays wrong until #29651 takes the app state from the service. Merging this alone leaves that window open on master.