fix(core): custom application delegate scene wiring and non-scene launch timing - #11367
Merged
Conversation
The scene configuration and discarded-session methods were installed only on the built-in Responder class, so an app assigning its own delegate - which cannot extend Responder, since NativeScript does not subclass an already extended native class - left iOS with no scene configuration at all. They are now installed on whichever delegate class is in use, per method, so a delegate bringing its own implementation still wins; defaultSceneConfiguration() and defaultDiscardSceneSessions() are public so such a delegate can handle the cases it cares about and hand the rest back.
Non-scene apps deferred the first window's content - and with it the 'launch' event - whenever the app launched into the background. Plugins rely on 'launch' arriving while the app finishes launching, background launches included. Content is resolved in applicationDidFinishLaunching again, and delaying it is once more opt-in through shouldDelayLaunchEvent, which stays deprecated but works as it always did for non-scene apps.
|
View your CI Pipeline Execution ↗ for commit 047ab6a
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗ ☁️ Nx Cloud last updated this comment at |
commit: |
NathanWalker
approved these changes
Aug 26, 2026
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.
PR Checklist
Two follow-up fixes to #11181, both on iOS.
1. A custom application delegate broke scenes entirely
Current behavior
The two scene-related
UIApplicationDelegatemethods —applicationConfigurationForConnectingSceneSessionOptionsandapplicationDidDiscardSceneSessions— were installed only on the built-inResponderclass at module load. Thedelegatesetter just stored whatever it was given, andrun()hands that class toUIApplicationMain.So an app doing
Application.ios.delegate = MyDelegate— common for push tokens,openURL, or an SDK that requires it — gave iOS a delegate with no scene methods at all, no scene configuration was ever returned, and scenes were dead. There is no workaround by subclassing: NativeScript cannot extend an already-extended native class, soclass MyDelegate extends Responderis not available.New behavior
The defaults are installed on whichever delegate class is in use, per method and only when absent, so a delegate that brings its own implementation still wins.
For the case where you want to handle some of it yourself and leave the rest to NativeScript, the defaults are now public and take the same arguments as the delegate methods:
defaultDiscardSceneSessions(application, sceneSessions)is available the same way.Also handled:
windowaccessor.Responderprovides one; a custom delegate loses it, and UIKit queriesdelegate.windowon non-scene apps. One is installed only when the class has no prototype-levelwindowat all. It stores what is assigned rather than copyingResponder's NOOP setter — silently swallowingthis.window = xon someone's own class would be worse than the original breakage.static ObjCProtocols. Without it the ObjC runtime may never dispatch to the class. Protocols are a one-time class-build parameter, so this cannot be added after the fact — assigning a delegate class that does not declareUIApplicationDelegatenow warns once, loudly, telling you to add the line.UIApplicationMaininsiderun(); assigning one afterwards warns, since it can no longer take effect.Worth noting for anyone reading this who only wants to customise scene configuration:
configureForScenes()already covers that without a custom delegate — the default consults it first and honours whatever it returns. This fix is for apps that need a custom delegate for unrelated reasons and lost the scene wiring as collateral.2.
launchno longer fired atdidFinishLaunchingon a background launchCurrent behavior
#11181 changed two things about the non-scene startup path when only one was intended.
shouldDelayLaunchEventbecame a no-op, and the first window's content — and with it the legacylaunchevent — became automatically deferred wheneverapplicationStatewasBackgroundat launch.Previously the default fired
launchand built the root view inapplicationDidFinishLaunchingregardless of background state, and deferral was strictly opt-in through the flag. Plugins rely onlauncharriving atdidFinishLaunching, background launches included — a silent push, for instance, needs handlers registered before it is processed.New behavior
The automatic background deferral is gone. Content resolves in
applicationDidFinishLaunchingagain, and delaying it is opt-in throughshouldDelayLaunchEvent, which remains deprecated but works as it always did for non-scene apps.shouldDelayLaunchEventfalse(default)ready→windowOpen→launch+ content, all indidFinishLaunchingtrueready→windowOpen;launch+ content on firstdidBecomeActivereadyindidFinishLaunching;launch+ content with the first window's scenereadyonlyreadyis unchanged: still raised indidFinishLaunchingon every path, before any window is registered.Two pieces of deprecation text were factually wrong and are corrected —
shouldDelayLaunchEvent's "has no effect", andlaunchEvent's claim that it does not fire for background launches, which now holds only for scene-based apps.Tests
413 → 419 passing. The launch-timing specs drive the real
didFinishLaunchingWithOptionsanddidBecomeActiveon a freshiOSApplication, and were mutation-verified: restoring the background check fails exactly the two tests that pin the restored behavior.No new import cycles (unchanged at android 89 / ios 88).
Not covered by CI
Device-only: that protocol conformance actually reaches the installed IMPs on a custom delegate class,
UIApplicationMainbehavior with one, and a real background launch (silent push) firinglaunchatdidFinishLaunching.