ios: support iOS 27 UIScene lifecycle (TN3187)#634
Open
benface wants to merge 2 commits into
Open
Conversation
This was referenced Jun 13, 2026
iOS 27 SDK enforces the UIScene lifecycle for window management. UIWindow created via `initWithFrame:` from AppDelegate's `didFinishLaunching` is no longer auto-attached to a scene, so it stays invisible. Apps that don't declare `UIApplicationSceneManifest` in Info.plist also refuse to launch. Defer window creation to a `UISceneWillConnectNotification` observer and use `initWithWindowScene:` with the scene iOS provides. The view and view controller created during `didFinishLaunching` are stashed in thread_local storage for the observer to adopt. Also observe `UISceneDidActivateNotification` to re-send `Message::Resume`. iOS 27 fires `applicationWillResignActive:` during the scene-attach handoff (legacy lifecycle compat path) which sends Pause and blocks the render thread, with no follow-up `applicationDidBecomeActive:` to wake it back up. Apps using this patched miniquad must declare `UIApplicationSceneManifest` in Info.plist or iOS 27 will refuse to launch them.
- Merge `PENDING_SCENE_VIEW` + `PENDING_SCENE_VIEW_CTRL` into a single `PENDING_SCENE_VIEW_AND_CTRL: Option<(ObjcId, ObjcId)>` thread_local. The two values are always set together and always taken together; a single tuple makes the invariant structural and drops one `match` arm at the take site. - Reorder `scene_will_connect` and `scene_did_activate` so the declaration order matches the lifecycle order (will-connect first, did-activate second). Selector registrations and observer hookups were already in this order. No functional change.
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.
Problem
The iOS 27 SDK enforces the UIScene lifecycle for window management (per Apple's TN3187). Two consequences for apps built with the new SDK:
UIApplicationSceneManifestinInfo.plistrefuse to launch with the error "UIScene life cycle is required for apps built with this SDK".UIWindowcreated viainitWithFrame:fromapplication:didFinishLaunchingWithOptions:is no longer auto-attached to a scene, so it stays orphan and invisible. The user sees a black screen after the splash; the GL/Metal view is never visible.miniquad's current iOS path hits both. Note that already-shipped apps run fine on iOS 27 — the enforcement is SDK-bound, not runtime-bound. The bug only appears when rebuilding against Xcode 27 / the iOS 27 SDK.
Fix
This patch:
Defers
UIWindowcreation fromdid_finish_launching_with_optionsto aUISceneWillConnectNotificationobserver (scene_will_connect). The observer creates the window viainitWithWindowScene:with the scene iOS provides, then adopts the view + view controller thatdidFinishLaunchinghad already set up. The view + view_ctrl are stashed inthread_localstorage between the two callbacks (both run on the main thread).Observes
UISceneDidActivateNotificationto re-sendMessage::Resume. Without this, iOS 27 fires a spuriousapplicationWillResignActive:during the scene-attach handoff (legacy lifecycle compat path) which sendsMessage::Pauseand blocks the render thread onrx.recv(), with no follow-upapplicationDidBecomeActive:to wake it back up. The symptom is exactly one frame of work happening (whatever ran synchronously up to the firstnext_frame().await), then nothing.The patch is iOS-only and additive — pre-iOS-13 paths aren't touched, and
UISceneWillConnectNotificationhas been available since iOS 13.Caller responsibilities
Apps using a miniquad with this patch must declare
UIApplicationSceneManifestinInfo.plistwith at least one scene configuration, including aUISceneDelegateClassNamepointing to either a stubUIWindowSceneDelegate-conforming class or the platform-provided default. Without the manifest, iOS 27 still refuses to launch the app — that part of the enforcement is unrelated to the patch.A minimal stub delegate is enough; this patch handles all window/view wiring itself, so the scene delegate doesn't need any methods implemented:
Tested on
iPhone running iOS 27 beta. Verified: launches past splash, window is visible, render thread runs continuously, asset loading completes, game renders + responds to input. Tested against the unpatched
miniquad@0.4.10baseline (black screen / hang after first frame) for comparison.Why not a separate version bump
Happy to bump if preferred — this branch is built on top of the last commit at
version = "0.4.10"on master to keep the diff minimal. Patch is ~80 lines net.