@nativescript/core 9.1.0-alpha.9 → 9.1.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/accessibility/accessibility-common.d.ts +8 -0
  2. package/accessibility/accessibility-common.js +28 -0
  3. package/accessibility/accessibility-common.js.map +1 -1
  4. package/application/application-common.d.ts +187 -4
  5. package/application/application-common.js +402 -94
  6. package/application/application-common.js.map +1 -1
  7. package/application/application-interfaces.d.ts +59 -1
  8. package/application/application.android.d.ts +22 -1
  9. package/application/application.android.js +193 -15
  10. package/application/application.android.js.map +1 -1
  11. package/application/application.d.ts +121 -66
  12. package/application/application.ios.d.ts +104 -27
  13. package/application/application.ios.js +549 -352
  14. package/application/application.ios.js.map +1 -1
  15. package/application/helpers-common.d.ts +5 -0
  16. package/application/helpers-common.js +23 -1
  17. package/application/helpers-common.js.map +1 -1
  18. package/application/scene-delegate-bridge.d.ts +55 -0
  19. package/application/scene-delegate-bridge.js +122 -0
  20. package/application/scene-delegate-bridge.js.map +1 -0
  21. package/config/config.interface.d.ts +44 -2
  22. package/core-types/index.d.ts +9 -2
  23. package/core-types/index.js +7 -0
  24. package/core-types/index.js.map +1 -1
  25. package/css/CSS3Parser.js +3 -2
  26. package/css/CSS3Parser.js.map +1 -1
  27. package/css/system-classes.d.ts +9 -0
  28. package/css/system-classes.js +23 -0
  29. package/css/system-classes.js.map +1 -1
  30. package/data/observable/index.d.ts +5 -0
  31. package/data/observable/index.js +46 -9
  32. package/data/observable/index.js.map +1 -1
  33. package/debugger/dom-types.js +31 -1
  34. package/debugger/dom-types.js.map +1 -1
  35. package/fetch/index.mjs +2 -2
  36. package/file-system/file-system-access.ios.js +18 -10
  37. package/file-system/file-system-access.ios.js.map +1 -1
  38. package/file-system/index.d.ts +3 -3
  39. package/global-types.d.ts +39 -33
  40. package/globals/global-utils.d.ts +6 -1
  41. package/globals/global-utils.js +10 -5
  42. package/globals/global-utils.js.map +1 -1
  43. package/globals/index.js +14 -4
  44. package/globals/index.js.map +1 -1
  45. package/globals/polyfills/utils.js +2 -0
  46. package/globals/polyfills/utils.js.map +1 -1
  47. package/index.d.ts +2 -0
  48. package/index.js +1 -0
  49. package/index.js.map +1 -1
  50. package/inspector_modules.js +1 -1
  51. package/inspector_modules.js.map +1 -1
  52. package/native-window/index.d.ts +426 -0
  53. package/native-window/index.js +4 -0
  54. package/native-window/index.js.map +1 -0
  55. package/native-window/native-window-common.d.ts +153 -0
  56. package/native-window/native-window-common.js +340 -0
  57. package/native-window/native-window-common.js.map +1 -0
  58. package/native-window/native-window-interfaces.d.ts +186 -0
  59. package/native-window/native-window-interfaces.js +90 -0
  60. package/native-window/native-window-interfaces.js.map +1 -0
  61. package/native-window/native-window.android.d.ts +59 -0
  62. package/native-window/native-window.android.js +175 -0
  63. package/native-window/native-window.android.js.map +1 -0
  64. package/native-window/native-window.ios.d.ts +57 -0
  65. package/native-window/native-window.ios.js +208 -0
  66. package/native-window/native-window.ios.js.map +1 -0
  67. package/native-window/window-base.d.ts +103 -0
  68. package/native-window/window-base.js +78 -0
  69. package/native-window/window-base.js.map +1 -0
  70. package/package.json +1 -1
  71. package/platforms/android/widgets-release.aar +0 -0
  72. package/platforms/ios/TNSWidgets.xcframework/Info.plist +14 -14
  73. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Info.plist +0 -0
  74. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/TNSWidgets +0 -0
  75. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  76. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +78 -78
  77. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Resources/Info.plist +7 -7
  78. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Resources/Info.plist +7 -7
  79. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/TNSWidgets +0 -0
  80. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Resources/Info.plist +7 -7
  81. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/TNSWidgets +0 -0
  82. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  83. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +78 -78
  84. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/x86_64/TNSWidgets.yml +78 -78
  85. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Info.plist +0 -0
  86. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/TNSWidgets +0 -0
  87. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/_CodeSignature/CodeResources +1 -1
  88. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  89. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +78 -78
  90. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/x86_64/TNSWidgets.yml +78 -78
  91. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Info.plist +0 -0
  92. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/TNSWidgets +0 -0
  93. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  94. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +78 -78
  95. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Info.plist +0 -0
  96. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/TNSWidgets +0 -0
  97. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/_CodeSignature/CodeResources +1 -1
  98. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  99. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +78 -78
  100. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/x86_64/TNSWidgets.yml +78 -78
  101. package/platforms/ios/src/NativeScriptMainWindow.swift +72 -39
  102. package/trace/index.d.ts +2 -2
  103. package/ui/action-bar/action-bar-common.js +0 -1
  104. package/ui/action-bar/action-bar-common.js.map +1 -1
  105. package/ui/animation/keyframe-animation.d.ts +1 -1
  106. package/ui/builder/index.js +9 -1
  107. package/ui/builder/index.js.map +1 -1
  108. package/ui/core/properties/index.d.ts +24 -1
  109. package/ui/core/properties/index.js +96 -10
  110. package/ui/core/properties/index.js.map +1 -1
  111. package/ui/core/properties/property-shared.js +11 -2
  112. package/ui/core/properties/property-shared.js.map +1 -1
  113. package/ui/core/view/index.android.js +29 -7
  114. package/ui/core/view/index.android.js.map +1 -1
  115. package/ui/core/view/index.d.ts +58 -1
  116. package/ui/core/view/index.ios.js +11 -2
  117. package/ui/core/view/index.ios.js.map +1 -1
  118. package/ui/core/view/view-common.d.ts +37 -0
  119. package/ui/core/view/view-common.js +81 -0
  120. package/ui/core/view/view-common.js.map +1 -1
  121. package/ui/core/view/view-helper/index.ios.d.ts +6 -20
  122. package/ui/core/view/view-helper/index.ios.js +10 -31
  123. package/ui/core/view/view-helper/index.ios.js.map +1 -1
  124. package/ui/core/view/view-helper/view-helper-common.js +21 -3
  125. package/ui/core/view/view-helper/view-helper-common.js.map +1 -1
  126. package/ui/core/view-base/index.d.ts +13 -8
  127. package/ui/core/view-base/index.js +54 -33
  128. package/ui/core/view-base/index.js.map +1 -1
  129. package/ui/frame/frame-common.d.ts +14 -2
  130. package/ui/frame/frame-common.js +19 -17
  131. package/ui/frame/frame-common.js.map +1 -1
  132. package/ui/frame/frame-constants.d.ts +9 -0
  133. package/ui/frame/frame-constants.js +10 -0
  134. package/ui/frame/frame-constants.js.map +1 -0
  135. package/ui/frame/frame-helper-for-android.d.ts +2 -2
  136. package/ui/frame/frame-helper-for-android.js +14 -5
  137. package/ui/frame/frame-helper-for-android.js.map +1 -1
  138. package/ui/frame/frame-interfaces.d.ts +1 -1
  139. package/ui/frame/frame-stack.d.ts +17 -1
  140. package/ui/frame/frame-stack.js +32 -5
  141. package/ui/frame/frame-stack.js.map +1 -1
  142. package/ui/frame/index.android.d.ts +1 -1
  143. package/ui/frame/index.android.js +139 -38
  144. package/ui/frame/index.android.js.map +1 -1
  145. package/ui/frame/index.d.ts +15 -5
  146. package/ui/image/image-common.js +1 -1
  147. package/ui/image/image-common.js.map +1 -1
  148. package/ui/image/index.android.js +13 -1
  149. package/ui/image/index.android.js.map +1 -1
  150. package/ui/layouts/absolute-layout/index.ios.js +4 -5
  151. package/ui/layouts/absolute-layout/index.ios.js.map +1 -1
  152. package/ui/layouts/dock-layout/index.ios.js +4 -5
  153. package/ui/layouts/dock-layout/index.ios.js.map +1 -1
  154. package/ui/layouts/flexbox-layout/flexbox-layout-common.d.ts +7 -0
  155. package/ui/layouts/flexbox-layout/flexbox-layout-common.js +18 -0
  156. package/ui/layouts/flexbox-layout/flexbox-layout-common.js.map +1 -1
  157. package/ui/layouts/flexbox-layout/index.android.d.ts +5 -0
  158. package/ui/layouts/flexbox-layout/index.android.js +15 -0
  159. package/ui/layouts/flexbox-layout/index.android.js.map +1 -1
  160. package/ui/layouts/flexbox-layout/index.d.ts +19 -1
  161. package/ui/layouts/flexbox-layout/index.ios.d.ts +2 -0
  162. package/ui/layouts/flexbox-layout/index.ios.js +245 -198
  163. package/ui/layouts/flexbox-layout/index.ios.js.map +1 -1
  164. package/ui/layouts/grid-layout/index.ios.js +4 -5
  165. package/ui/layouts/grid-layout/index.ios.js.map +1 -1
  166. package/ui/layouts/layout-base-common.d.ts +1 -0
  167. package/ui/layouts/layout-base-common.js +21 -0
  168. package/ui/layouts/layout-base-common.js.map +1 -1
  169. package/ui/layouts/stack-layout/index.ios.js +4 -5
  170. package/ui/layouts/stack-layout/index.ios.js.map +1 -1
  171. package/ui/layouts/wrap-layout/index.ios.js +4 -5
  172. package/ui/layouts/wrap-layout/index.ios.js.map +1 -1
  173. package/ui/list-view/index.android.js +3 -2
  174. package/ui/list-view/index.android.js.map +1 -1
  175. package/ui/list-view/index.ios.d.ts +2 -2
  176. package/ui/list-view/index.ios.js +15 -17
  177. package/ui/list-view/index.ios.js.map +1 -1
  178. package/ui/list-view/list-view-common.d.ts +1 -0
  179. package/ui/list-view/list-view-common.js +15 -0
  180. package/ui/list-view/list-view-common.js.map +1 -1
  181. package/ui/page/index.android.d.ts +1 -0
  182. package/ui/page/index.android.js +4 -0
  183. package/ui/page/index.android.js.map +1 -1
  184. package/ui/page/index.ios.d.ts +2 -1
  185. package/ui/page/index.ios.js +8 -5
  186. package/ui/page/index.ios.js.map +1 -1
  187. package/ui/scroll-view/index.d.ts +3 -5
  188. package/ui/scroll-view/index.ios.d.ts +3 -1
  189. package/ui/scroll-view/index.ios.js +26 -20
  190. package/ui/scroll-view/index.ios.js.map +1 -1
  191. package/ui/scroll-view/scroll-view-common.js +1 -1
  192. package/ui/scroll-view/scroll-view-common.js.map +1 -1
  193. package/ui/segmented-bar/segmented-bar-common.js +6 -1
  194. package/ui/segmented-bar/segmented-bar-common.js.map +1 -1
  195. package/ui/styling/background-common.d.ts +2 -0
  196. package/ui/styling/background-common.js +9 -0
  197. package/ui/styling/background-common.js.map +1 -1
  198. package/ui/styling/background.ios.js +2 -0
  199. package/ui/styling/background.ios.js.map +1 -1
  200. package/ui/styling/css-selector.d.ts +57 -13
  201. package/ui/styling/css-selector.js +280 -51
  202. package/ui/styling/css-selector.js.map +1 -1
  203. package/ui/styling/css-utils.d.ts +16 -0
  204. package/ui/styling/css-utils.js +121 -7
  205. package/ui/styling/css-utils.js.map +1 -1
  206. package/ui/styling/style/index.d.ts +11 -0
  207. package/ui/styling/style/index.js.map +1 -1
  208. package/ui/styling/style-properties.d.ts +5 -0
  209. package/ui/styling/style-properties.js +134 -74
  210. package/ui/styling/style-properties.js.map +1 -1
  211. package/ui/styling/style-scope.d.ts +15 -3
  212. package/ui/styling/style-scope.js +299 -56
  213. package/ui/styling/style-scope.js.map +1 -1
  214. package/ui/switch/index.ios.js +2 -1
  215. package/ui/switch/index.ios.js.map +1 -1
  216. package/ui/tab-view/index.android.d.ts +3 -1
  217. package/ui/tab-view/index.android.js +56 -46
  218. package/ui/tab-view/index.android.js.map +1 -1
  219. package/ui/tab-view/index.ios.js +1 -0
  220. package/ui/tab-view/index.ios.js.map +1 -1
  221. package/ui/tab-view/tab-view-common.d.ts +1 -0
  222. package/ui/tab-view/tab-view-common.js +16 -3
  223. package/ui/tab-view/tab-view-common.js.map +1 -1
  224. package/ui/text-base/index.android.d.ts +1 -1
  225. package/ui/text-base/index.android.js +8 -8
  226. package/ui/text-base/index.android.js.map +1 -1
  227. package/ui/text-base/index.ios.js +5 -3
  228. package/ui/text-base/index.ios.js.map +1 -1
  229. package/ui/transition/shared-transition.d.ts +1 -0
  230. package/ui/transition/shared-transition.js +13 -8
  231. package/ui/transition/shared-transition.js.map +1 -1
  232. package/utils/layout-helper/index.ios.js +11 -3
  233. package/utils/layout-helper/index.ios.js.map +1 -1
  234. package/utils/native-helper.d.ts +2 -2
@@ -3,10 +3,14 @@ import { isEmbedded } from '../ui/embedding';
3
3
  import { IOSHelper } from '../ui/core/view/view-helper';
4
4
  import { getWindow } from '../utils/native-helper';
5
5
  import { SDK_VERSION } from '../utils/constants';
6
- import { ios as iosUtils, dataSerialize } from '../utils/native-helper';
7
- import { ApplicationCommon, initializeSdkVersionClass, SceneEvents } from './application-common';
6
+ import { ios as iosUtils, dataSerialize, dataDeserialize } from '../utils/native-helper';
7
+ import { ApplicationCommon } from './application-common';
8
+ import { deliverShortcutItem, forwardContinueUserActivity, forwardOpenURLContexts, oneShotCompletion } from './scene-delegate-bridge';
8
9
  import { Observable } from '../data/observable';
9
10
  import { Trace } from '../trace';
11
+ import { IOSNativeWindow } from '../native-window/native-window.ios';
12
+ import { NativeWindow } from '../native-window/native-window-common';
13
+ import { NativeWindowEvents } from '../native-window/native-window-interfaces';
10
14
  import { AccessibilityServiceEnabledPropName, CommonA11YServiceEnabledObservable, SharedA11YObservable, a11yServiceClasses, a11yServiceDisabledClass, a11yServiceEnabledClass, fontScaleCategoryClasses, fontScaleExtraLargeCategoryClass, fontScaleExtraSmallCategoryClass, fontScaleMediumCategoryClass, getCurrentA11YServiceClass, getCurrentFontScaleCategory, getCurrentFontScaleClass, getFontScaleCssClasses, setCurrentA11YServiceClass, setCurrentFontScaleCategory, setCurrentFontScaleClass, setFontScaleCssClasses, FontScaleCategory, getClosestValidFontScale, VALID_FONT_SCALES, setFontScale, getFontScale, setInitFontScale, getFontScaleCategory, setInitAccessibilityCssHelper, notifyAccessibilityFocusState, AccessibilityLiveRegion, AccessibilityRole, AccessibilityState, AccessibilityTrait, isA11yEnabled, setA11yEnabled, enforceArray, } from '../accessibility/accessibility-common';
11
15
  import { CoreTypes } from '../core-types';
12
16
  import { getiOSWindow, setA11yUpdatePropertiesCallback, setApplicationPropertiesCallback, setAppMainEntry, setiOSWindow, setRootView, setToggleApplicationEventListenersCallback } from './helpers-common';
@@ -39,6 +43,7 @@ var CADisplayLinkTarget = (function (_super) {
39
43
  return target;
40
44
  };
41
45
  CADisplayLinkTarget.prototype.onDisplayed = function (link) {
46
+ var _a;
42
47
  link.invalidate();
43
48
  var owner = this._owner.deref();
44
49
  if (!owner) {
@@ -50,6 +55,7 @@ var CADisplayLinkTarget = (function (_super) {
50
55
  object: owner,
51
56
  ios: UIApplication.sharedApplication,
52
57
  });
58
+ (_a = owner.primaryWindow) === null || _a === void 0 ? void 0 : _a._notifyEvent(NativeWindowEvents.displayed);
53
59
  owner.displayedLinkTarget = null;
54
60
  owner.displayedLink = null;
55
61
  };
@@ -80,6 +86,15 @@ function supportsMultipleScenes() {
80
86
  }
81
87
  return UIApplication.sharedApplication?.supportsMultipleScenes;
82
88
  }
89
+ /**
90
+ * Number of times the JS runtime has been soft-rebooted in this process via
91
+ * NativeScriptRuntime.reloadApplication / restartWithConfig. 0 on first boot.
92
+ * Provided as a global by the iOS runtime (v9+); older runtimes report 0.
93
+ */
94
+ function getRuntimeReloadCount() {
95
+ const runtime = globalThis.NativeScriptRuntime;
96
+ return runtime && typeof runtime.reloadCount === 'number' ? runtime.reloadCount : 0;
97
+ }
83
98
  var Responder = (function (_super) {
84
99
  __extends(Responder, _super);
85
100
  function Responder() {
@@ -104,8 +119,28 @@ if (supportsScenes()) {
104
119
  * Detected by the Info.plist existence 'UIApplicationSceneManifest'.
105
120
  * If this method is implemented when there is no manifest defined,
106
121
  * the app will boot to a white screen.
122
+ *
123
+ * Since we configure the delegate dynamically here, UISceneConfigurations
124
+ * does NOT need to be present in Info.plist — only UIApplicationSceneManifest is required.
125
+ *
126
+ * NativeScript only handles UIWindowSceneSessionRoleApplication by default.
127
+ * Other scene types (CarPlay, external displays, etc.) are ignored unless
128
+ * the user provides an `onSceneConfiguration` callback.
107
129
  */
108
130
  Responder.prototype.applicationConfigurationForConnectingSceneSessionOptions = function (application, connectingSceneSession, options) {
131
+ // Let the user intercept scene configuration for any/all scenes
132
+ const userHandler = Application.ios._onSceneConfiguration;
133
+ if (userHandler) {
134
+ const userConfig = userHandler(application, connectingSceneSession, options);
135
+ if (userConfig) {
136
+ return userConfig;
137
+ }
138
+ }
139
+ // Only handle the standard window scene role — skip CarPlay, external displays, etc.
140
+ if (connectingSceneSession.role !== UIWindowSceneSessionRoleApplication) {
141
+ // Return a bare configuration so iOS doesn't crash, but NativeScript won't manage it
142
+ return UISceneConfiguration.configurationWithNameSessionRole('Unmanaged', connectingSceneSession.role);
143
+ }
109
144
  const config = UISceneConfiguration.configurationWithNameSessionRole('Default Configuration', connectingSceneSession.role);
110
145
  config.sceneClass = UIWindowScene;
111
146
  config.delegateClass = SceneDelegate;
@@ -113,10 +148,20 @@ if (supportsScenes()) {
113
148
  };
114
149
  // scene session destruction handling
115
150
  Responder.prototype.applicationDidDiscardSceneSessions = function (application, sceneSessions) {
116
- // Note: we could emit an event here if needed
117
- // console.log('Scene sessions discarded:', sceneSessions.count);
151
+ Application.ios._onSceneSessionsDiscarded(sceneSessions);
118
152
  };
119
153
  }
154
+ /**
155
+ * Reads the payload `openWindow()` put on the activating NSUserActivity.
156
+ */
157
+ function getSceneConnectionData(connectionOptions) {
158
+ const activities = connectionOptions?.userActivities;
159
+ if (!activities || activities.count === 0) {
160
+ return undefined;
161
+ }
162
+ const activity = activities.allObjects.objectAtIndex(0);
163
+ return activity?.userInfo ? dataDeserialize(activity.userInfo) : undefined;
164
+ }
120
165
  var SceneDelegate = (function (_super) {
121
166
  __extends(SceneDelegate, _super);
122
167
  function SceneDelegate() {
@@ -139,48 +184,234 @@ var SceneDelegate = (function (_super) {
139
184
  if (!(scene instanceof UIWindowScene)) {
140
185
  return;
141
186
  }
142
- var isFirstScene = !Application.ios.getPrimaryScene() && !Application.hasLaunched();
143
- this._scene = scene;
144
- this._window = UIWindow.alloc().initWithWindowScene(scene);
145
- Application.ios._setWindowForScene(this._window, scene);
146
- Application.ios._setupWindowForScene(this._window, scene);
187
+ var windowScene = scene;
188
+ var isFirstScene = Application.ios._getWindows().length === 0;
189
+ this._scene = windowScene;
190
+ this._window = UIWindow.alloc().initWithWindowScene(windowScene);
191
+ if (!__VISIONOS__) {
192
+ this._window.backgroundColor = SDK_VERSION <= 12 || !UIColor.systemBackgroundColor ? UIColor.whiteColor : UIColor.systemBackgroundColor;
193
+ }
194
+ var nativeWindowId = IOSNativeWindow.getSceneId(windowScene);
195
+ var knownWindow = nativeWindowId ? Application.ios.getWindowById(nativeWindowId) : undefined;
196
+ var nativeWindow;
197
+ if ((knownWindow === null || knownWindow === void 0 ? void 0 : knownWindow.state) === "detached") {
198
+ nativeWindow = knownWindow;
199
+ nativeWindow._reattach(windowScene, this._window);
200
+ }
201
+ else {
202
+ var isPrimary_1 = isFirstScene || !Application.ios.primaryWindow;
203
+ nativeWindow = new IOSNativeWindow(windowScene, this._window, nativeWindowId, isPrimary_1);
204
+ Application.ios._registerWindow(nativeWindow);
205
+ }
206
+ var isPrimary = nativeWindow.isPrimary;
207
+ nativeWindow._notifyEvent(NativeWindowEvents.attached);
208
+ if (isPrimary) {
209
+ setiOSWindow(this._window);
210
+ }
211
+ nativeWindow.notify({
212
+ eventName: NativeWindowEvents.sceneWillConnect,
213
+ object: nativeWindow,
214
+ window: nativeWindow,
215
+ scene: windowScene,
216
+ uiWindow: this._window,
217
+ connectionOptions: connectionOptions,
218
+ });
147
219
  Application.ios.notify({
148
- eventName: SceneEvents.sceneWillConnect,
220
+ eventName: NativeWindowEvents.sceneWillConnect,
149
221
  object: Application.ios,
150
- scene: scene,
151
- window: this._window,
222
+ window: nativeWindow,
223
+ scene: windowScene,
224
+ uiWindow: this._window,
152
225
  connectionOptions: connectionOptions,
153
226
  });
154
- if (scene === Application.ios.getPrimaryScene()) {
227
+ if (isPrimary) {
155
228
  this._window.makeKeyAndVisible();
156
229
  }
157
- else {
158
- Application.ios.notify({
159
- eventName: SceneEvents.sceneContentSetup,
160
- object: Application.ios,
161
- scene: scene,
162
- window: this._window,
163
- connectionOptions: connectionOptions,
230
+ if (nativeWindow.role === "application") {
231
+ Application.ios._resolveWindowContent(nativeWindow, {
232
+ window: nativeWindow,
233
+ isPrimary: isPrimary,
234
+ data: getSceneConnectionData(connectionOptions),
235
+ ios: { connectionOptions: connectionOptions },
164
236
  });
165
237
  }
166
- if (isFirstScene) {
167
- Application.ios._notifySceneAppStarted();
168
- }
169
238
  };
170
239
  SceneDelegate.prototype.sceneDidBecomeActive = function (scene) {
240
+ var windowScene = scene;
241
+ var nativeWindow = Application.ios._getWindowForScene(windowScene);
242
+ if (nativeWindow) {
243
+ nativeWindow._notifyEvent(NativeWindowEvents.activate);
244
+ nativeWindow.notify({
245
+ eventName: NativeWindowEvents.sceneDidActivate,
246
+ object: nativeWindow,
247
+ window: nativeWindow,
248
+ scene: windowScene,
249
+ });
250
+ }
251
+ Application.ios.notify({
252
+ eventName: NativeWindowEvents.sceneDidActivate,
253
+ object: Application.ios,
254
+ window: nativeWindow,
255
+ scene: windowScene,
256
+ });
257
+ var rootView = nativeWindow === null || nativeWindow === void 0 ? void 0 : nativeWindow.rootView;
258
+ if (rootView && !rootView.isLoaded) {
259
+ rootView.callLoaded();
260
+ }
171
261
  };
172
262
  SceneDelegate.prototype.sceneWillResignActive = function (scene) {
263
+ var windowScene = scene;
264
+ var nativeWindow = Application.ios._getWindowForScene(windowScene);
265
+ if (nativeWindow) {
266
+ nativeWindow._notifyEvent(NativeWindowEvents.deactivate);
267
+ nativeWindow.notify({
268
+ eventName: NativeWindowEvents.sceneWillResignActive,
269
+ object: nativeWindow,
270
+ window: nativeWindow,
271
+ scene: windowScene,
272
+ });
273
+ }
173
274
  Application.ios.notify({
174
- eventName: SceneEvents.sceneWillResignActive,
275
+ eventName: NativeWindowEvents.sceneWillResignActive,
175
276
  object: Application.ios,
176
- scene: scene,
277
+ window: nativeWindow,
278
+ scene: windowScene,
177
279
  });
178
280
  };
179
281
  SceneDelegate.prototype.sceneWillEnterForeground = function (scene) {
282
+ var windowScene = scene;
283
+ var nativeWindow = Application.ios._getWindowForScene(windowScene);
284
+ if (nativeWindow) {
285
+ nativeWindow._notifyEvent(NativeWindowEvents.foreground);
286
+ nativeWindow.notify({
287
+ eventName: NativeWindowEvents.sceneWillEnterForeground,
288
+ object: nativeWindow,
289
+ window: nativeWindow,
290
+ scene: windowScene,
291
+ });
292
+ }
293
+ Application.ios.notify({
294
+ eventName: NativeWindowEvents.sceneWillEnterForeground,
295
+ object: Application.ios,
296
+ window: nativeWindow,
297
+ scene: windowScene,
298
+ });
180
299
  };
181
300
  SceneDelegate.prototype.sceneDidEnterBackground = function (scene) {
301
+ var windowScene = scene;
302
+ var nativeWindow = Application.ios._getWindowForScene(windowScene);
303
+ if (nativeWindow) {
304
+ nativeWindow._notifyEvent(NativeWindowEvents.background);
305
+ nativeWindow.notify({
306
+ eventName: NativeWindowEvents.sceneDidEnterBackground,
307
+ object: nativeWindow,
308
+ window: nativeWindow,
309
+ scene: windowScene,
310
+ });
311
+ }
312
+ Application.ios.notify({
313
+ eventName: NativeWindowEvents.sceneDidEnterBackground,
314
+ object: Application.ios,
315
+ window: nativeWindow,
316
+ scene: windowScene,
317
+ });
318
+ var rootView = nativeWindow === null || nativeWindow === void 0 ? void 0 : nativeWindow.rootView;
319
+ if (rootView && rootView.isLoaded) {
320
+ rootView.callUnloaded();
321
+ }
182
322
  };
183
323
  SceneDelegate.prototype.sceneDidDisconnect = function (scene) {
324
+ var windowScene = scene;
325
+ var nativeWindow = Application.ios._getWindowForScene(windowScene);
326
+ if (nativeWindow) {
327
+ var isClosing = nativeWindow._closeRequested || !nativeWindow._hasSessionIdentity;
328
+ if (isClosing) {
329
+ nativeWindow._notifyEvent(NativeWindowEvents.close);
330
+ }
331
+ nativeWindow.notify({
332
+ eventName: NativeWindowEvents.sceneDidDisconnect,
333
+ object: nativeWindow,
334
+ window: nativeWindow,
335
+ scene: windowScene,
336
+ });
337
+ if (isClosing) {
338
+ Application.ios._unregisterWindow(nativeWindow);
339
+ }
340
+ else {
341
+ nativeWindow._detach();
342
+ }
343
+ }
344
+ Application.ios.notify({
345
+ eventName: NativeWindowEvents.sceneDidDisconnect,
346
+ object: Application.ios,
347
+ window: nativeWindow,
348
+ scene: windowScene,
349
+ });
350
+ };
351
+ SceneDelegate.prototype.sceneOpenURLContexts = function (scene, URLContexts) {
352
+ var windowScene = scene;
353
+ var nativeWindow = Application.ios._getWindowForScene(windowScene);
354
+ if (nativeWindow) {
355
+ nativeWindow.notify({
356
+ eventName: NativeWindowEvents.sceneOpenURLContexts,
357
+ object: nativeWindow,
358
+ window: nativeWindow,
359
+ scene: windowScene,
360
+ urlContexts: URLContexts,
361
+ });
362
+ }
363
+ Application.ios.notify({
364
+ eventName: NativeWindowEvents.sceneOpenURLContexts,
365
+ object: Application.ios,
366
+ window: nativeWindow,
367
+ scene: windowScene,
368
+ urlContexts: URLContexts,
369
+ });
370
+ forwardOpenURLContexts(Application.ios.delegate, UIApplication.sharedApplication, URLContexts);
371
+ };
372
+ SceneDelegate.prototype.sceneContinueUserActivity = function (scene, userActivity) {
373
+ var windowScene = scene;
374
+ var nativeWindow = Application.ios._getWindowForScene(windowScene);
375
+ if (nativeWindow) {
376
+ nativeWindow.notify({
377
+ eventName: NativeWindowEvents.sceneContinueUserActivity,
378
+ object: nativeWindow,
379
+ window: nativeWindow,
380
+ scene: windowScene,
381
+ userActivity: userActivity,
382
+ });
383
+ }
384
+ Application.ios.notify({
385
+ eventName: NativeWindowEvents.sceneContinueUserActivity,
386
+ object: Application.ios,
387
+ window: nativeWindow,
388
+ scene: windowScene,
389
+ userActivity: userActivity,
390
+ });
391
+ forwardContinueUserActivity(Application.ios.delegate, UIApplication.sharedApplication, userActivity);
392
+ };
393
+ SceneDelegate.prototype.windowScenePerformActionForShortcutItemCompletionHandler = function (windowScene, shortcutItem, completionHandler) {
394
+ var nativeWindow = Application.ios._getWindowForScene(windowScene);
395
+ var deliver = oneShotCompletion(completionHandler);
396
+ if (nativeWindow) {
397
+ nativeWindow.notify({
398
+ eventName: NativeWindowEvents.scenePerformActionForShortcutItem,
399
+ object: nativeWindow,
400
+ window: nativeWindow,
401
+ scene: windowScene,
402
+ shortcutItem: shortcutItem,
403
+ completionHandler: deliver,
404
+ });
405
+ }
406
+ Application.ios.notify({
407
+ eventName: NativeWindowEvents.scenePerformActionForShortcutItem,
408
+ object: Application.ios,
409
+ window: nativeWindow,
410
+ scene: windowScene,
411
+ shortcutItem: shortcutItem,
412
+ completionHandler: deliver,
413
+ });
414
+ deliverShortcutItem(Application.ios.delegate, UIApplication.sharedApplication, shortcutItem, deliver);
184
415
  };
185
416
  SceneDelegate.ObjCProtocols = [UIWindowSceneDelegate];
186
417
  return SceneDelegate;
@@ -194,12 +425,12 @@ export class iOSApplication extends ApplicationCommon {
194
425
  constructor() {
195
426
  super();
196
427
  this._delegateHandlers = new Map();
197
- this.launchEventCalled = false;
198
- this._windowSceneMap = new Map();
199
- this._primaryScene = null;
200
- this._openedScenesById = new Map();
201
428
  this._notificationObservers = [];
429
+ this._softRebootSceneDelegates = new Map();
202
430
  this.displayedOnce = false;
431
+ /**
432
+ * @deprecated Has no effect. Application initialization is signalled by the 'ready' event, which is never deferred.
433
+ */
203
434
  this.shouldDelayLaunchEvent = false;
204
435
  this.addNotificationObserver(UIApplicationDidFinishLaunchingNotification, this.didFinishLaunchingWithOptions.bind(this));
205
436
  this.addNotificationObserver(UIApplicationDidBecomeActiveNotification, this.didBecomeActive.bind(this));
@@ -207,14 +438,6 @@ export class iOSApplication extends ApplicationCommon {
207
438
  this.addNotificationObserver(UIApplicationWillTerminateNotification, this.willTerminate.bind(this));
208
439
  this.addNotificationObserver(UIApplicationDidReceiveMemoryWarningNotification, this.didReceiveMemoryWarning.bind(this));
209
440
  this.addNotificationObserver(UIApplicationDidChangeStatusBarOrientationNotification, this.didChangeStatusBarOrientation.bind(this));
210
- // Add scene lifecycle notification observers only if scenes are supported
211
- if (this.supportsScenes()) {
212
- this.addNotificationObserver('UISceneWillConnectNotification', this.sceneWillConnect.bind(this));
213
- this.addNotificationObserver('UISceneDidActivateNotification', this.sceneDidActivate.bind(this));
214
- this.addNotificationObserver('UISceneWillEnterForegroundNotification', this.sceneWillEnterForeground.bind(this));
215
- this.addNotificationObserver('UISceneDidEnterBackgroundNotification', this.sceneDidEnterBackground.bind(this));
216
- this.addNotificationObserver('UISceneDidDisconnectNotification', this.sceneDidDisconnect.bind(this));
217
- }
218
441
  }
219
442
  getRootView() {
220
443
  return this._rootView;
@@ -277,6 +500,8 @@ export class iOSApplication extends ApplicationCommon {
277
500
  UIApplicationMain(0, null, null, this.delegate ? NSStringFromClass(this.delegate) : NSStringFromClass(Responder));
278
501
  }
279
502
  runAsEmbeddedApp() {
503
+ this.notifyReady();
504
+ this._reattachNativeDelegatesAfterSoftReboot();
280
505
  // TODO: this rootView should be held alive until rootController dismissViewController is called.
281
506
  const rootView = this.createRootView(this._rootView, true);
282
507
  if (!rootView) {
@@ -308,8 +533,23 @@ export class iOSApplication extends ApplicationCommon {
308
533
  }
309
534
  if (targetScene) {
310
535
  window = UIWindow.alloc().initWithWindowScene(targetScene);
311
- this._setWindowForScene(window, targetScene);
312
- this._setupWindowForScene?.(window, targetScene);
536
+ if (!__VISIONOS__) {
537
+ window.backgroundColor = SDK_VERSION <= 12 || !UIColor.systemBackgroundColor ? UIColor.whiteColor : UIColor.systemBackgroundColor;
538
+ }
539
+ // The registry lives in JS and was lost with the previous isolate, so
540
+ // the still-connected scene needs a fresh NativeWindow to be reachable.
541
+ const isPrimary = !this.primaryWindow;
542
+ const nativeWindow = new IOSNativeWindow(targetScene, window, IOSNativeWindow.getSceneId(targetScene), isPrimary);
543
+ this._registerWindow(nativeWindow);
544
+ if (isPrimary) {
545
+ setiOSWindow(window);
546
+ }
547
+ // If the scene's delegate was recreated after a soft reboot, point it
548
+ // at the new window so `scene.delegate.window` queries resolve.
549
+ const freshSceneDelegate = this._softRebootSceneDelegates.get(targetScene);
550
+ if (freshSceneDelegate) {
551
+ freshSceneDelegate.window = window;
552
+ }
313
553
  }
314
554
  }
315
555
  if (!window) {
@@ -318,37 +558,78 @@ export class iOSApplication extends ApplicationCommon {
318
558
  // May be null on a freshly recreated window — expected; the replace-root
319
559
  // path below sets it. Only the embedder path needs an existing controller.
320
560
  const rootController = window.rootViewController;
321
- const controller = this.getViewController(rootView);
322
561
  const embedderDelegate = NativeScriptEmbedder.sharedInstance().delegate;
323
- rootView._setupAsRootView({});
324
- rootView.on(IOSHelper.traitCollectionColorAppearanceChangedEvent, () => {
325
- const userInterfaceStyle = controller.traitCollection.userInterfaceStyle;
326
- const newSystemAppearance = this.getSystemAppearanceValue(userInterfaceStyle);
327
- this.setSystemAppearance(newSystemAppearance);
328
- });
329
- rootView.on(IOSHelper.traitCollectionLayoutDirectionChangedEvent, () => {
330
- const layoutDirection = controller.traitCollection.layoutDirection;
331
- const newLayoutDirection = this.getLayoutDirectionValue(layoutDirection);
332
- this.setLayoutDirection(newLayoutDirection);
333
- });
334
- if (embedderDelegate) {
335
- // Embed into host app.
336
- // present over the host's existing root view controller.
337
- if (!rootController) {
338
- return;
339
- }
340
- this.setViewControllerView(rootView);
341
- embedderDelegate.presentNativeScriptApp(controller);
562
+ // Embed into host app requires an existing root view controller
563
+ if (embedderDelegate && !rootController) {
564
+ return;
342
565
  }
343
- else {
344
- // No embedder delegate = NativeScript owns the UIApplication.
345
- // Attach the root to the window.
346
- this.setViewControllerView(rootView);
347
- this.setWindowRootView(window, rootView);
566
+ let hostWindow = this.primaryWindow;
567
+ if (!hostWindow) {
568
+ // Only an embedder delegate makes this window a guest: without one NativeScript
569
+ // owns the UIApplication and the window has to attach its own content.
570
+ const role = embedderDelegate ? 'embedded' : 'application';
571
+ hostWindow = new IOSNativeWindow(window.windowScene ?? undefined, window, 'embedded-main', true, role);
572
+ this._registerWindow(hostWindow);
573
+ hostWindow._notifyEvent(NativeWindowEvents.attached);
348
574
  }
349
- this.initRootView(rootView);
575
+ hostWindow.setContent(rootView);
350
576
  this.notifyAppStarted();
351
577
  }
578
+ /**
579
+ * After an in-process soft reboot (NativeScriptRuntime.reloadApplication /
580
+ * restartWithConfig), the Objective-C delegate classes created by the
581
+ * previous JS isolate still exist and UIKit keeps dispatching to their
582
+ * now-inert instances: their method callbacks bail out because the isolate
583
+ * that implemented them is gone. Notification-center observers are
584
+ * re-registered by the new isolate, but delegate-based dispatch (custom
585
+ * UIApplicationDelegate methods like push-token/openURL callbacks, and the
586
+ * UIScene delegates used by scene-lifecycle apps) stays pinned to the old
587
+ * bundle. Recreate those delegates from this bundle's classes and re-point
588
+ * UIKit at them.
589
+ */
590
+ _reattachNativeDelegatesAfterSoftReboot() {
591
+ if (getRuntimeReloadCount() <= 0) {
592
+ // First boot: UIApplicationMain (or the host app) set up delegates.
593
+ return;
594
+ }
595
+ if (isEmbedded()) {
596
+ // The host app owns the UIApplication delegate; never touch it.
597
+ return;
598
+ }
599
+ const app = UIApplication.sharedApplication;
600
+ if (!app) {
601
+ return;
602
+ }
603
+ // Fresh application delegate from the new bundle. Assigning `delegate`
604
+ // does not retain (unlike the UIApplicationMain launch path), so keep a
605
+ // strong reference ourselves.
606
+ this.delegate ?? (this.delegate = Responder);
607
+ const freshDelegate = this.delegate.new();
608
+ this._softRebootAppDelegate = freshDelegate;
609
+ app.delegate = freshDelegate;
610
+ // Re-point already-connected scenes at fresh scene delegates so scene
611
+ // lifecycle and user-implemented scene delegate methods (shortcuts,
612
+ // openURLContexts, userActivity continuation, etc.) reach this isolate.
613
+ // Newly connecting scenes are covered by the fresh application delegate's
614
+ // applicationConfigurationForConnectingSceneSessionOptions, which returns
615
+ // this bundle's SceneDelegate class.
616
+ if (this.supportsScenes()) {
617
+ this._softRebootSceneDelegates.clear();
618
+ const scenes = app.connectedScenes?.allObjects;
619
+ for (let i = 0; scenes && i < scenes.count; i++) {
620
+ const scene = scenes.objectAtIndex(i);
621
+ if (!(scene instanceof UIWindowScene)) {
622
+ continue;
623
+ }
624
+ const freshSceneDelegate = SceneDelegate.new();
625
+ scene.delegate = freshSceneDelegate;
626
+ this._softRebootSceneDelegates.set(scene, freshSceneDelegate);
627
+ }
628
+ }
629
+ if (Trace.isEnabled()) {
630
+ Trace.write(`Reattached application delegate${this._softRebootSceneDelegates.size ? ` and ${this._softRebootSceneDelegates.size} scene delegate(s)` : ''} after soft reboot (reloadCount: ${getRuntimeReloadCount()})`, Trace.categories.NativeLifecycle);
631
+ }
632
+ }
352
633
  getViewController(rootView) {
353
634
  let viewController = rootView.viewController || rootView.ios;
354
635
  if (!(viewController instanceof UIViewController)) {
@@ -533,7 +814,6 @@ export class iOSApplication extends ApplicationCommon {
533
814
  }
534
815
  }
535
816
  notifyAppStarted(notification) {
536
- this.launchEventCalled = true;
537
817
  const root = this.notifyLaunch({
538
818
  ios: notification?.userInfo?.objectForKey('UIApplicationLaunchOptionsLocalNotificationKey') ?? null,
539
819
  });
@@ -546,10 +826,6 @@ export class iOSApplication extends ApplicationCommon {
546
826
  setiOSWindow(this.window);
547
827
  }
548
828
  }
549
- // Public method for scene-based app startup
550
- _notifySceneAppStarted() {
551
- this.notifyAppStarted();
552
- }
553
829
  _onLivesync(context) {
554
830
  // Handle application root module
555
831
  const isAppRootModuleChanged = context && context.path && context.path.includes(this.getMainEntry().moduleName) && context.type !== 'style';
@@ -564,14 +840,23 @@ export class iOSApplication extends ApplicationCommon {
564
840
  }
565
841
  }
566
842
  setWindowContent(view) {
843
+ const rootView = this.createRootView(view);
844
+ const primaryWindow = this.primaryWindow;
845
+ if (primaryWindow) {
846
+ primaryWindow.setContent(rootView);
847
+ return;
848
+ }
849
+ this.setWindowContentFallback(rootView);
850
+ }
851
+ /**
852
+ * Attaches content to the raw `UIWindow`. Every launch path registers a primary
853
+ * NativeWindow, so this only runs when no window is left to own the content.
854
+ */
855
+ setWindowContentFallback(rootView) {
567
856
  if (this._rootView) {
568
- // if we already have a root view, we reset it.
569
857
  this._rootView._onRootViewReset();
570
858
  }
571
- const rootView = this.createRootView(view);
572
859
  const controller = this.getViewController(rootView);
573
- this._rootView = rootView;
574
- setRootView(rootView);
575
860
  // setup view as styleScopeHost
576
861
  rootView._setupAsRootView({});
577
862
  this.setViewControllerView(rootView);
@@ -581,17 +866,7 @@ export class iOSApplication extends ApplicationCommon {
581
866
  if (!haveController) {
582
867
  win.makeKeyAndVisible();
583
868
  }
584
- this.initRootView(rootView);
585
- rootView.on(IOSHelper.traitCollectionColorAppearanceChangedEvent, () => {
586
- const userInterfaceStyle = controller.traitCollection.userInterfaceStyle;
587
- const newSystemAppearance = this.getSystemAppearanceValue(userInterfaceStyle);
588
- this.setSystemAppearance(newSystemAppearance);
589
- });
590
- rootView.on(IOSHelper.traitCollectionLayoutDirectionChangedEvent, () => {
591
- const layoutDirection = controller.traitCollection.layoutDirection;
592
- const newLayoutDirection = this.getLayoutDirectionValue(layoutDirection);
593
- this.setLayoutDirection(newLayoutDirection);
594
- });
869
+ this.adoptRootView(rootView);
595
870
  }
596
871
  // Observers
597
872
  didFinishLaunchingWithOptions(notification) {
@@ -609,6 +884,8 @@ export class iOSApplication extends ApplicationCommon {
609
884
  }
610
885
  }
611
886
  }
887
+ // Must precede every window registration below and every scene connect that follows.
888
+ this.notifyReady();
612
889
  this.setMaxRefreshRate();
613
890
  // Only set up window if NOT using scene-based lifecycle
614
891
  if (!this.supportsScenes()) {
@@ -622,9 +899,26 @@ export class iOSApplication extends ApplicationCommon {
622
899
  if (!__VISIONOS__) {
623
900
  this.window.backgroundColor = SDK_VERSION <= 12 || !UIColor.systemBackgroundColor ? UIColor.whiteColor : UIColor.systemBackgroundColor;
624
901
  }
625
- this.launchEventCalled = false;
626
- if (!this.shouldDelayLaunchEvent) {
627
- this.notifyAppStarted();
902
+ if (!this.primaryWindow) {
903
+ const nativeWindow = new IOSNativeWindow(undefined, this.window, 'main', true, 'application');
904
+ this._registerWindow(nativeWindow);
905
+ nativeWindow._notifyEvent(NativeWindowEvents.attached);
906
+ }
907
+ const primaryWindow = this.primaryWindow;
908
+ const resolveContent = () => this._resolveWindowContent(primaryWindow, {
909
+ window: primaryWindow,
910
+ isPrimary: true,
911
+ }, {
912
+ launchData: {
913
+ ios: notification?.userInfo?.objectForKey('UIApplicationLaunchOptionsLocalNotificationKey') ?? null,
914
+ },
915
+ });
916
+ if (UIApplication.sharedApplication.applicationState === 2 /* UIApplicationState.Background */) {
917
+ // A background launch has no UI to build yet, so content waits for the first activation.
918
+ this._pendingWindowContentResolve = resolveContent;
919
+ }
920
+ else {
921
+ resolveContent();
628
922
  }
629
923
  }
630
924
  else {
@@ -632,17 +926,22 @@ export class iOSApplication extends ApplicationCommon {
632
926
  }
633
927
  }
634
928
  didBecomeActive(notification) {
635
- if (!this.launchEventCalled) {
636
- this.notifyAppStarted(notification);
929
+ const pendingWindowContentResolve = this._pendingWindowContentResolve;
930
+ if (pendingWindowContentResolve) {
931
+ this._pendingWindowContentResolve = null;
932
+ pendingWindowContentResolve();
637
933
  }
638
934
  const additionalData = {
639
935
  ios: UIApplication.sharedApplication,
640
936
  };
641
937
  this.setInBackground(false, additionalData);
642
938
  this.setSuspended(false, additionalData);
643
- const rootView = this._rootView;
644
- if (rootView && !rootView.isLoaded) {
645
- rootView.callLoaded();
939
+ // In scene mode the root view belongs to a window, so the scene delegate loads it.
940
+ if (!this.supportsScenes()) {
941
+ const rootView = this._rootView;
942
+ if (rootView && !rootView.isLoaded) {
943
+ rootView.callLoaded();
944
+ }
646
945
  }
647
946
  }
648
947
  didEnterBackground(notification) {
@@ -651,9 +950,11 @@ export class iOSApplication extends ApplicationCommon {
651
950
  };
652
951
  this.setInBackground(true, additionalData);
653
952
  this.setSuspended(true, additionalData);
654
- const rootView = this._rootView;
655
- if (rootView && rootView.isLoaded) {
656
- rootView.callUnloaded();
953
+ if (!this.supportsScenes()) {
954
+ const rootView = this._rootView;
955
+ if (rootView && rootView.isLoaded) {
956
+ rootView.callUnloaded();
957
+ }
657
958
  }
658
959
  }
659
960
  willTerminate(notification) {
@@ -675,157 +976,111 @@ export class iOSApplication extends ApplicationCommon {
675
976
  });
676
977
  }
677
978
  didChangeStatusBarOrientation(notification) {
678
- const statusBarOrientation = UIApplication.sharedApplication.statusBarOrientation;
679
- const newOrientation = this.getOrientationValue(statusBarOrientation);
680
- this.setOrientation(newOrientation);
681
- }
682
- // Scene lifecycle notification handlers
683
- sceneWillConnect(notification) {
684
- const scene = notification.object;
685
- if (!scene || !(scene instanceof UIWindowScene)) {
686
- return;
687
- }
688
- // Store as primary scene if it's the first one
689
- if (!this._primaryScene) {
690
- this._primaryScene = scene;
979
+ // The notification is app-wide, but scenes rotate independently, so every attached
980
+ // window is refreshed from its own scene.
981
+ for (const nativeWindow of this._windows) {
982
+ if (nativeWindow.state !== 'attached') {
983
+ continue;
984
+ }
985
+ const orientation = nativeWindow.ios?.scene?.interfaceOrientation ?? UIApplication.sharedApplication.statusBarOrientation;
986
+ nativeWindow._setOrientation(this.getOrientationValue(orientation));
691
987
  }
692
- this.notify({
693
- eventName: SceneEvents.sceneWillConnect,
694
- object: this,
695
- scene: scene,
696
- userInfo: notification.userInfo,
697
- });
698
988
  }
699
- sceneDidActivate(notification) {
700
- const scene = notification.object;
701
- this.notify({
702
- eventName: SceneEvents.sceneDidActivate,
703
- object: this,
704
- scene: scene,
705
- });
706
- // If this is the primary scene, trigger traditional app lifecycle
707
- if (scene === this._primaryScene) {
708
- const additionalData = {
709
- ios: UIApplication.sharedApplication,
710
- scene: scene,
711
- };
712
- this.setInBackground(false, additionalData);
713
- this.setSuspended(false, additionalData);
714
- if (this._rootView && !this._rootView.isLoaded) {
715
- this._rootView.callLoaded();
716
- }
989
+ // --- App-level root view mirror ---
990
+ /**
991
+ * Keeps the app-level root view state (`getRootView()`, the global root view and the
992
+ * `initRootView` event) following whatever the primary window shows.
993
+ */
994
+ mirrorPrimaryWindow(nativeWindow) {
995
+ if (this._mirroredWindow === nativeWindow) {
996
+ return;
997
+ }
998
+ this._mirroredWindow?.off(NativeWindowEvents.contentLoaded, this.onPrimaryWindowContentLoaded, this);
999
+ this._mirroredWindow = nativeWindow;
1000
+ nativeWindow.on(NativeWindowEvents.contentLoaded, this.onPrimaryWindowContentLoaded, this);
1001
+ if (nativeWindow.rootView && nativeWindow.rootView !== this._rootView) {
1002
+ this.adoptRootView(nativeWindow.rootView);
717
1003
  }
718
1004
  }
719
- sceneWillEnterForeground(notification) {
720
- const scene = notification.object;
721
- this.notify({
722
- eventName: SceneEvents.sceneWillEnterForeground,
723
- object: this,
724
- scene: scene,
725
- });
1005
+ onPrimaryWindowContentLoaded(data) {
1006
+ this.adoptRootView(data.window.rootView);
726
1007
  }
727
- sceneDidEnterBackground(notification) {
728
- const scene = notification.object;
729
- this.notify({
730
- eventName: SceneEvents.sceneDidEnterBackground,
731
- object: this,
732
- scene: scene,
733
- });
734
- // If this is the primary scene, trigger traditional app lifecycle
735
- if (scene === this._primaryScene) {
736
- const additionalData = {
737
- ios: UIApplication.sharedApplication,
738
- scene: scene,
739
- };
740
- this.setInBackground(true, additionalData);
741
- this.setSuspended(true, additionalData);
742
- if (this._rootView && this._rootView.isLoaded) {
743
- this._rootView.callUnloaded();
744
- }
1008
+ adoptRootView(rootView) {
1009
+ if (!rootView) {
1010
+ return;
745
1011
  }
1012
+ this._rootView = rootView;
1013
+ setRootView(rootView);
1014
+ this.initRootView(rootView, this._mirroredWindow);
746
1015
  }
747
- sceneDidDisconnect(notification) {
748
- const scene = notification.object;
749
- this._removeWindowForScene(scene);
750
- // If primary scene disconnected, clear it
751
- if (scene === this._primaryScene) {
752
- this._primaryScene = null;
1016
+ // --- NativeWindow registry ---
1017
+ /**
1018
+ * @internal - iOS reports discarded sessions for windows this JS context may never
1019
+ * have seen (they can arrive on a later launch), so unknown ids are ignored.
1020
+ */
1021
+ _onSceneSessionsDiscarded(sessions) {
1022
+ const all = sessions?.allObjects;
1023
+ if (!all) {
1024
+ return;
753
1025
  }
754
- if (this._primaryScene) {
755
- if (SDK_VERSION >= 17) {
756
- const request = UISceneSessionActivationRequest.requestWithSession(this._primaryScene.session);
757
- UIApplication.sharedApplication.activateSceneSessionForRequestErrorHandler(request, (err) => {
758
- if (err) {
759
- console.log('Failed to activate primary scene:', err.localizedDescription);
760
- }
761
- });
762
- }
763
- else {
764
- UIApplication.sharedApplication.requestSceneSessionActivationUserActivityOptionsErrorHandler(this._primaryScene.session, null, null, (err) => {
765
- if (err) {
766
- console.log('Failed to activate primary scene (legacy):', err.localizedDescription);
767
- }
768
- });
1026
+ for (let i = 0; i < all.count; i++) {
1027
+ const persistentIdentifier = all.objectAtIndex(i)?.persistentIdentifier;
1028
+ const nativeWindow = persistentIdentifier ? this.getWindowById(`${persistentIdentifier}`) : undefined;
1029
+ if (!nativeWindow) {
1030
+ continue;
769
1031
  }
1032
+ nativeWindow._notifyEvent(NativeWindowEvents.close);
1033
+ this._unregisterWindow(nativeWindow);
770
1034
  }
771
- this.notify({
772
- eventName: SceneEvents.sceneDidDisconnect,
773
- object: this,
774
- scene: scene,
775
- });
776
- }
777
- // Scene management helper methods
778
- _setWindowForScene(window, scene) {
779
- this._windowSceneMap.set(scene, window);
780
- }
781
- _removeWindowForScene(scene) {
782
- this._windowSceneMap.delete(scene);
783
- // also untrack opened scene id
784
- try {
785
- const s = scene;
786
- if (s && s.session) {
787
- const id = this._getSceneId(s);
788
- this._openedScenesById.delete(id);
789
- }
790
- }
791
- catch { }
792
1035
  }
1036
+ /**
1037
+ * @internal - Get a NativeWindow by its scene.
1038
+ */
793
1039
  _getWindowForScene(scene) {
794
- return this._windowSceneMap.get(scene);
1040
+ return this._windows.find((nw) => nw.ios?.scene === scene);
795
1041
  }
796
- _setupWindowForScene(window, scene) {
797
- if (!window) {
798
- return;
799
- }
800
- // track opened scene
801
- try {
802
- const id = this._getSceneId(scene);
803
- this._openedScenesById.set(id, scene);
1042
+ _onWindowRegistered(nativeWindow) {
1043
+ if (nativeWindow.isPrimary) {
1044
+ this.mirrorPrimaryWindow(nativeWindow);
804
1045
  }
805
- catch { }
806
- // Set up window background
807
- if (!__VISIONOS__) {
808
- window.backgroundColor = SDK_VERSION <= 12 || !UIColor.systemBackgroundColor ? UIColor.whiteColor : UIColor.systemBackgroundColor;
809
- }
810
- // If this is the primary scene, set up the main application content
811
- if (scene === this._primaryScene || !this._primaryScene) {
812
- this._primaryScene = scene;
813
- if (!getiOSWindow()) {
814
- setiOSWindow(window);
815
- }
816
- // During initial scene startup we must wait for launch to be notified first.
817
- // Some frameworks provide root content from launch handlers.
818
- // Guard: skip setWindowContent when no main entry is configured yet.
819
- // During Vite HMR dev boot, the placeholder calls Application.run() with
820
- // no entry; the real entry is set later when the HTTP-loaded main module
821
- // calls Application.run({ moduleName: ... }). Without this guard the
822
- // scene handler would throw "Main entry is missing" and leave the window
823
- // in a broken state (root view reset but no replacement created).
824
- if (this.hasLaunched() && this.getMainEntry()) {
825
- this.setWindowContent();
826
- }
1046
+ }
1047
+ _onPrimaryWindowPromoted(nativeWindow) {
1048
+ const promotedWindow = nativeWindow.ios?.uiWindow;
1049
+ if (promotedWindow) {
1050
+ setiOSWindow(promotedWindow);
827
1051
  }
1052
+ this.mirrorPrimaryWindow(nativeWindow);
1053
+ }
1054
+ /**
1055
+ * Register a callback to intercept scene configuration.
1056
+ *
1057
+ * Called for every new scene session. Return a `UISceneConfiguration` to handle
1058
+ * the scene yourself (e.g. CarPlay, external display), or return `null`/`undefined`
1059
+ * to let NativeScript handle it with the default SceneDelegate.
1060
+ *
1061
+ * NativeScript only auto-manages `UIWindowSceneSessionRoleApplication` scenes.
1062
+ * All other scene roles are ignored unless you provide a configuration here.
1063
+ *
1064
+ * @example
1065
+ * ```ts
1066
+ * Application.ios.onSceneConfiguration = (app, session, options) => {
1067
+ * if (session.role === CPTemplateApplicationSceneSessionRoleApplication) {
1068
+ * const config = UISceneConfiguration.configurationWithNameSessionRole('CarPlay', session.role);
1069
+ * config.delegateClass = MyCarPlaySceneDelegate;
1070
+ * return config;
1071
+ * }
1072
+ * // Return null to let NativeScript handle the default window scene
1073
+ * return null;
1074
+ * };
1075
+ * ```
1076
+ */
1077
+ set onSceneConfiguration(handler) {
1078
+ this._onSceneConfiguration = handler;
1079
+ }
1080
+ get onSceneConfiguration() {
1081
+ return this._onSceneConfiguration;
828
1082
  }
1083
+ // Scene management helper methods (kept for backward compat)
829
1084
  get sceneDelegate() {
830
1085
  if (!this._sceneDelegate) {
831
1086
  this._sceneDelegate = SceneDelegate.new();
@@ -839,10 +1094,12 @@ export class iOSApplication extends ApplicationCommon {
839
1094
  * Multi-window support
840
1095
  */
841
1096
  /**
842
- * Opens a new window with the specified data.
843
- * @param data The data to pass to the new window.
1097
+ * Opens a new window (scene).
1098
+ *
1099
+ * @param options Options for the new window. `options.data` is serialized into the
1100
+ * activating scene's `NSUserActivity.userInfo`.
844
1101
  */
845
- openWindow(data) {
1102
+ openWindow(options) {
846
1103
  if (!supportsMultipleScenes()) {
847
1104
  console.log('Cannot create a new scene - not supported on this device.');
848
1105
  return;
@@ -851,34 +1108,18 @@ export class iOSApplication extends ApplicationCommon {
851
1108
  const app = UIApplication.sharedApplication;
852
1109
  // iOS 17+
853
1110
  if (SDK_VERSION >= 17) {
854
- // Create a new scene activation request with proper role
855
1111
  let request;
856
1112
  try {
857
- // Use the correct factory method to create request with role
858
- // Based on the type definitions, this is the proper way
859
1113
  request = UISceneSessionActivationRequest.requestWithRole(UIWindowSceneSessionRoleApplication);
860
- // Note: may be useful to allow user defined activity type through optional string typed data in future
861
1114
  const activity = NSUserActivity.alloc().initWithActivityType(`${NSBundle.mainBundle.bundleIdentifier}.scene`);
862
- activity.userInfo = dataSerialize(data);
1115
+ activity.userInfo = dataSerialize(options?.data ?? {});
863
1116
  request.userActivity = activity;
864
- // Set proper options with requesting scene
865
- const options = UISceneActivationRequestOptions.new();
866
- // Note: explore secondary windows spawning other windows
867
- // and if this context needs to change in those cases
868
- const mainWindow = Application.ios.getPrimaryWindow();
869
- options.requestingScene = mainWindow?.windowScene;
870
- /**
871
- * Note: This does not work in testing but worth exploring further sometime
872
- * regarding the size/dimensions of opened secondary windows.
873
- * The initial size is ultimately determined by the system
874
- * based on available space and user context.
875
- */
876
- // Get the size restrictions from the window scene
877
- // const sizeRestrictions = (options.requestingScene as UIWindowScene).sizeRestrictions;
878
- // // Set your minimum and maximum dimensions
879
- // sizeRestrictions.minimumSize = CGSizeMake(320, 400);
880
- // sizeRestrictions.maximumSize = CGSizeMake(600, 800);
881
- request.options = options;
1117
+ const activationOptions = UISceneActivationRequestOptions.new();
1118
+ const primary = this.primaryWindow;
1119
+ if (primary?.ios?.scene) {
1120
+ activationOptions.requestingScene = primary.ios.scene;
1121
+ }
1122
+ request.options = activationOptions;
882
1123
  }
883
1124
  catch (roleError) {
884
1125
  console.log('Error creating request:', roleError);
@@ -887,32 +1128,25 @@ export class iOSApplication extends ApplicationCommon {
887
1128
  app.activateSceneSessionForRequestErrorHandler(request, (error) => {
888
1129
  if (error) {
889
1130
  console.log('Error creating new scene (iOS 17+):', error);
890
- // Log additional debugging info
891
1131
  if (error.userInfo) {
892
1132
  console.error(`Error userInfo: ${error.userInfo.description}`);
893
1133
  }
894
- // Handle specific error types
895
1134
  if (error.localizedDescription.includes('role') && error.localizedDescription.includes('nil')) {
896
- this.createSceneWithLegacyAPI(data);
1135
+ this.createSceneWithLegacyAPI(options?.data);
897
1136
  }
898
1137
  else if (error.domain === 'FBSWorkspaceErrorDomain' && error.code === 2) {
899
- this.createSceneWithLegacyAPI(data);
1138
+ this.createSceneWithLegacyAPI(options?.data);
900
1139
  }
901
1140
  }
902
1141
  });
903
1142
  }
904
- // iOS 13-16 - Use the legacy requestSceneSessionActivationUserActivityOptionsErrorHandler method
905
1143
  else if (SDK_VERSION >= 13 && SDK_VERSION < 17) {
906
- app.requestSceneSessionActivationUserActivityOptionsErrorHandler(null, // session
907
- null, // userActivity
908
- null, // options
909
- (error) => {
1144
+ app.requestSceneSessionActivationUserActivityOptionsErrorHandler(null, null, null, (error) => {
910
1145
  if (error) {
911
1146
  console.log('Error creating new scene (legacy):', error);
912
1147
  }
913
1148
  });
914
1149
  }
915
- // Fallback for older iOS versions or unsupported configurations
916
1150
  else {
917
1151
  console.log('Neither new nor legacy scene activation methods are available');
918
1152
  }
@@ -923,71 +1157,66 @@ export class iOSApplication extends ApplicationCommon {
923
1157
  }
924
1158
  /**
925
1159
  * Closes a secondary window/scene.
926
- * Usage examples:
927
- * - Application.ios.closeWindow() // best-effort close of a non-primary scene
928
- * - Application.ios.closeWindow(button) // from a tap handler within the scene
929
- * - Application.ios.closeWindow(window)
930
- * - Application.ios.closeWindow(scene)
931
- * - Application.ios.closeWindow('scene-id')
1160
+ * Accepts a NativeWindow, View, UIWindow, UIWindowScene, or string id.
932
1161
  */
933
1162
  closeWindow(target) {
934
1163
  if (!__APPLE__) {
935
1164
  return;
936
1165
  }
937
1166
  try {
938
- const scene = this._resolveScene(target);
939
- if (!scene) {
940
- console.log('closeWindow: No scene resolved for target');
941
- return;
1167
+ let nativeWindow;
1168
+ if (target instanceof NativeWindow) {
1169
+ nativeWindow = target;
942
1170
  }
943
- // Don't allow closing the primary scene
944
- if (scene === this._primaryScene) {
945
- console.log('closeWindow: Refusing to close the primary scene');
946
- return;
1171
+ else {
1172
+ const scene = this._resolveScene(target);
1173
+ if (scene) {
1174
+ nativeWindow = this._getWindowForScene(scene);
1175
+ }
947
1176
  }
948
- const session = scene.session;
949
- if (!session) {
950
- console.log('closeWindow: Scene has no session to destroy');
1177
+ if (!nativeWindow) {
1178
+ console.log('closeWindow: No window resolved for target');
951
1179
  return;
952
1180
  }
953
- const app = UIApplication.sharedApplication;
954
- if (app.requestSceneSessionDestructionOptionsErrorHandler) {
955
- app.requestSceneSessionDestructionOptionsErrorHandler(session, null, (error) => {
956
- if (error) {
957
- console.log('closeWindow: destruction error', error);
958
- }
959
- else {
960
- // clean up tracked id
961
- const id = this._getSceneId(scene);
962
- this._openedScenesById.delete(id);
963
- }
964
- });
965
- }
966
- else {
967
- console.info('closeWindow: Scene destruction API not available on this iOS version');
968
- }
1181
+ nativeWindow.close();
969
1182
  }
970
1183
  catch (err) {
971
1184
  console.log('closeWindow: Unexpected error', err);
972
1185
  }
973
1186
  }
1187
+ /**
1188
+ * @deprecated Use `getWindows()` instead.
1189
+ */
974
1190
  getAllWindows() {
975
- return Array.from(this._windowSceneMap.values());
1191
+ return this._windows.map((nw) => nw.ios?.uiWindow).filter(Boolean);
976
1192
  }
1193
+ /**
1194
+ * @deprecated Use `getWindows()` instead.
1195
+ */
977
1196
  getAllScenes() {
978
- return Array.from(this._windowSceneMap.keys());
1197
+ return this._windows.map((nw) => nw.ios?.scene).filter(Boolean);
979
1198
  }
1199
+ /**
1200
+ * @deprecated Use `getWindows()` instead.
1201
+ */
980
1202
  getWindowScenes() {
981
1203
  return this.getAllScenes().filter((scene) => scene instanceof UIWindowScene);
982
1204
  }
1205
+ /**
1206
+ * @deprecated Use `primaryWindow?.ios?.uiWindow` instead.
1207
+ */
983
1208
  getPrimaryWindow() {
984
- if (this._primaryScene) {
985
- return this._getWindowForScene(this._primaryScene) || getiOSWindow();
1209
+ const primary = this.primaryWindow;
1210
+ if (primary?.ios?.uiWindow) {
1211
+ return primary.ios.uiWindow;
986
1212
  }
987
1213
  return getiOSWindow();
988
1214
  }
1215
+ /**
1216
+ * @deprecated Use `primaryWindow?.ios?.scene` instead.
1217
+ */
989
1218
  getPrimaryScene() {
990
- return this._primaryScene;
1219
+ return this.primaryWindow?.ios?.scene || null;
991
1220
  }
992
1221
  // Scene lifecycle management
993
1222
  supportsScenes() {
@@ -997,7 +1226,7 @@ export class iOSApplication extends ApplicationCommon {
997
1226
  return supportsMultipleScenes();
998
1227
  }
999
1228
  isUsingSceneLifecycle() {
1000
- return this.supportsScenes() && this._windowSceneMap.size > 0;
1229
+ return this.supportsScenes() && this._windows.length > 0;
1001
1230
  }
1002
1231
  // Call this to set up scene-based configuration
1003
1232
  configureForScenes() {
@@ -1005,34 +1234,6 @@ export class iOSApplication extends ApplicationCommon {
1005
1234
  console.warn('Scene-based lifecycle is only supported on iOS 13+ iPad or visionOS with multi-scene enabled apps.');
1006
1235
  return;
1007
1236
  }
1008
- // Additional scene configuration can be added here
1009
- // For now, the notification observers are already set up in the constructor
1010
- }
1011
- // Stable scene id for lookups
1012
- _getSceneId(scene) {
1013
- try {
1014
- if (!scene) {
1015
- return 'Unknown';
1016
- }
1017
- // Prefer session persistentIdentifier when available (stable across lifetime)
1018
- const session = scene.session;
1019
- const persistentId = session && session.persistentIdentifier;
1020
- if (persistentId) {
1021
- return `${persistentId}`;
1022
- }
1023
- // Fallbacks
1024
- if (scene.hash != null) {
1025
- return `${scene.hash}`;
1026
- }
1027
- const desc = scene.description;
1028
- if (desc) {
1029
- return `${desc}`;
1030
- }
1031
- }
1032
- catch (err) {
1033
- // ignore
1034
- }
1035
- return 'Unknown';
1036
1237
  }
1037
1238
  // Resolve a UIWindowScene from various input types
1038
1239
  _resolveScene(target) {
@@ -1040,12 +1241,10 @@ export class iOSApplication extends ApplicationCommon {
1040
1241
  return null;
1041
1242
  }
1042
1243
  if (!target) {
1043
- // Try to pick a non-primary foreground active scene, else last known scene
1044
- const scenes = this.getWindowScenes?.() || [];
1045
- const nonPrimary = scenes.filter((s) => s !== this._primaryScene);
1046
- return nonPrimary[0] || scenes[0] || null;
1244
+ // Try to pick a non-primary window's scene
1245
+ const nonPrimary = this._windows.filter((nw) => !nw.isPrimary);
1246
+ return nonPrimary[0]?.ios?.scene || this.primaryWindow?.ios?.scene || null;
1047
1247
  }
1048
- // If a View was passed, derive its window.scene
1049
1248
  if (target && typeof target === 'object') {
1050
1249
  // UIWindowScene
1051
1250
  if (target.session && target.activationState !== undefined) {
@@ -1064,15 +1263,15 @@ export class iOSApplication extends ApplicationCommon {
1064
1263
  }
1065
1264
  // String id lookup
1066
1265
  if (typeof target === 'string') {
1067
- if (this._openedScenesById.has(target)) {
1068
- return this._openedScenesById.get(target);
1266
+ const found = this.getWindowById(target);
1267
+ if (found) {
1268
+ return found.ios?.scene || null;
1069
1269
  }
1070
- // Try matching by persistentIdentifier or hash among known scenes
1071
- const scenes = this.getWindowScenes?.() || [];
1072
- for (const s of scenes) {
1073
- const sid = this._getSceneId(s);
1074
- if (sid === target) {
1075
- return s;
1270
+ // Try matching among known scenes
1271
+ for (const nw of this._windows) {
1272
+ const scene = nw.ios?.scene;
1273
+ if (scene && IOSNativeWindow.getSceneId(scene) === target) {
1274
+ return scene;
1076
1275
  }
1077
1276
  }
1078
1277
  }
@@ -1085,7 +1284,7 @@ export class iOSApplication extends ApplicationCommon {
1085
1284
  }
1086
1285
  // Create user activity for the new scene
1087
1286
  const userActivity = NSUserActivity.alloc().initWithActivityType(`${NSBundle.mainBundle.bundleIdentifier}.scene`);
1088
- userActivity.userInfo = dataSerialize(data);
1287
+ userActivity.userInfo = dataSerialize(data ?? {});
1089
1288
  // Use the legacy API
1090
1289
  const options = UISceneActivationRequestOptions.new();
1091
1290
  options.requestingScene = windowScene;
@@ -1466,14 +1665,12 @@ export class AccessibilityServiceEnabledObservable extends CommonA11YServiceEnab
1466
1665
  }
1467
1666
  }
1468
1667
  let accessibilityServiceObservable;
1469
- export function ensureClasses() {
1668
+ export function ensureA11yClasses() {
1470
1669
  if (accessibilityServiceObservable) {
1471
1670
  return;
1472
1671
  }
1473
1672
  setFontScaleCssClasses(new Map(VALID_FONT_SCALES.map((fs) => [fs, `a11y-fontscale-${Number(fs * 100).toFixed(0)}`])));
1474
1673
  accessibilityServiceObservable = new AccessibilityServiceEnabledObservable();
1475
- // Initialize SDK version CSS class once
1476
- initializeSdkVersionClass(Application.getRootView());
1477
1674
  }
1478
1675
  export function updateCurrentHelperClasses(applyRootCssClass) {
1479
1676
  const fontScale = getFontScale();
@@ -1542,7 +1739,7 @@ function applyFontScaleToRootViews() {
1542
1739
  rootModalViews.forEach((rootModalView) => (rootModalView.style.fontScaleInternal = fontScale));
1543
1740
  }
1544
1741
  export function initAccessibilityCssHelper() {
1545
- ensureClasses();
1742
+ ensureA11yClasses();
1546
1743
  updateCurrentHelperClasses(applyRootCssClass);
1547
1744
  applyFontScaleToRootViews();
1548
1745
  Application.on(Application.fontScaleChangedEvent, () => {