| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b54537d commit 8bd41bf
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,36 @@ | |||
| 1 | + import { ApplicationCommon } from './application-common'; | ||
| 2 | + import { getAppMainEntry, setAppMainEntry } from './helpers-common'; | ||
| 3 | + | ||
| 4 | + class TestApplication extends ApplicationCommon { | ||
| 5 | + getRootView() { | ||
| 6 | + return null as any; | ||
| 7 | + } | ||
| 8 | + } | ||
| 9 | + | ||
| 10 | + describe('__onApplicationReload', () => { | ||
| 11 | + afterEach(() => { | ||
| 12 | + setAppMainEntry(undefined); | ||
| 13 | + delete global.__onApplicationReload; | ||
| 14 | + }); | ||
| 15 | + | ||
| 16 | + it('remounts the current main entry without constructing a new Application', () => { | ||
| 17 | + const app = new TestApplication(); | ||
| 18 | + const entry = { moduleName: 'app-root' }; | ||
| 19 | + setAppMainEntry(entry); | ||
| 20 | + | ||
| 21 | + const remount = vi.spyOn(app, 'resetRootView'); | ||
| 22 | + global.__onApplicationReload(); | ||
| 23 | + | ||
| 24 | + expect(remount).toHaveBeenCalledWith(entry); | ||
| 25 | + expect(getAppMainEntry()).toBe(entry); | ||
| 26 | + }); | ||
| 27 | + | ||
| 28 | + it('is a no-op when the app has no main entry yet', () => { | ||
| 29 | + const app = new TestApplication(); | ||
| 30 | + const remount = vi.spyOn(app, 'resetRootView'); | ||
| 31 | + | ||
| 32 | + global.__onApplicationReload(); | ||
| 33 | + | ||
| 34 | + expect(remount).not.toHaveBeenCalled(); | ||
| 35 | + }); | ||
| 36 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -227,6 +227,15 @@ export class ApplicationCommon { | |||
| 227 | 227 | const rootView = this.getRootView(); | |
| 228 | 228 | this.livesync(rootView, context); | |
| 229 | 229 | }; | |
| 230 | + | ||
| 231 | + // Isolate-preserving reload remounts the current entry without a new runtime. | ||
| 232 | + global.__onApplicationReload = () => { | ||
| 233 | + const entry = getAppMainEntry(); | ||
| 234 | + if (!entry) { | ||
| 235 | + return; | ||
| 236 | + } | ||
| 237 | + this.resetRootView(entry); | ||
| 238 | + }; | ||
| 230 | 239 | } | |
| 231 | 240 | ||
| 232 | 241 | /** | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -127,16 +127,6 @@ function supportsMultipleScenes(): boolean { | |||
| 127 | 127 | return UIApplication.sharedApplication?.supportsMultipleScenes; | |
| 128 | 128 | } | |
| 129 | 129 | ||
| 130 | - /** | ||
| 131 | - * Number of times the JS runtime has been soft-rebooted in this process via | ||
| 132 | - * NativeScriptRuntime.reloadApplication / restartWithConfig. 0 on first boot. | ||
| 133 | - * Provided as a global by the iOS runtime (v9+); older runtimes report 0. | ||
| 134 | - */ | ||
| 135 | - function getRuntimeReloadCount(): number { | ||
| 136 | - const runtime = (globalThis as any).NativeScriptRuntime; | ||
| 137 | - return runtime && typeof runtime.reloadCount === 'number' ? runtime.reloadCount : 0; | ||
| 138 | - } | ||
| 139 | - | ||
| 140 | 130 | @NativeClass | |
| 141 | 131 | class Responder extends UIResponder implements UIApplicationDelegate { | |
| 142 | 132 | get window(): UIWindow { | |
@@ -279,13 +269,6 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication | |||
| 279 | 269 | ||
| 280 | 270 | private _notificationObservers: NotificationObserver[] = []; | |
| 281 | 271 | ||
| 282 | - // Strong references to delegates recreated after an in-process soft reboot | ||
| 283 | - // (NativeScriptRuntime.reloadApplication). UIApplication.delegate is an | ||
| 284 | - // `assign` property and UIScene keeps its own reference to the delegate we | ||
| 285 | - // replace, so without these the fresh instances would be deallocated. | ||
| 286 | - private _softRebootAppDelegate: UIApplicationDelegate; | ||
| 287 | - private _softRebootSceneDelegates = new Map<UIScene, UIWindowSceneDelegate>(); | ||
| 288 | - | ||
| 289 | 272 | displayedOnce = false; | |
| 290 | 273 | displayedLinkTarget: CADisplayLinkTarget; | |
| 291 | 274 | displayedLink: CADisplayLink; | |
@@ -378,8 +361,6 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication | |||
| 378 | 361 | } | |
| 379 | 362 | ||
| 380 | 363 | private runAsEmbeddedApp() { | |
| 381 | - this._reattachNativeDelegatesAfterSoftReboot(); | ||
| 382 | - | ||
| 383 | 364 | // TODO: this rootView should be held alive until rootController dismissViewController is called. | |
| 384 | 365 | const rootView = this.createRootView(this._rootView, true); | |
| 385 | 366 | if (!rootView) { | |
@@ -391,10 +372,6 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication | |||
| 391 | 372 | let window = getWindow() as UIWindow; | |
| 392 | 373 | ||
| 393 | 374 | if (!window) { | |
| 394 | - // In-process soft reboot with OTAs. | ||
| 395 | - // Original UIWindow is deallocated when the old JS isolate is torn down. | ||
| 396 | - // Recreate a window bound to the active UIWindowScene so the | ||
| 397 | - // root has somewhere to attach. | ||
| 398 | 375 | const app = UIApplication.sharedApplication; | |
| 399 | 376 | const all = app && app.connectedScenes ? app.connectedScenes.allObjects : null; | |
| 400 | 377 | let targetScene: UIWindowScene; | |
@@ -414,13 +391,6 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication | |||
| 414 | 391 | window = UIWindow.alloc().initWithWindowScene(targetScene); | |
| 415 | 392 | this._setWindowForScene(window, targetScene); | |
| 416 | 393 | this._setupWindowForScene?.(window, targetScene); | |
| 417 | - | ||
| 418 | - // If the scene's delegate was recreated after a soft reboot, point it | ||
| 419 | - // at the new window so `scene.delegate.window` queries resolve. | ||
| 420 | - const freshSceneDelegate = this._softRebootSceneDelegates.get(targetScene); | ||
| 421 | - if (freshSceneDelegate) { | ||
| 422 | - freshSceneDelegate.window = window; | ||
| 423 | - } | ||
| 424 | 394 | } | |
| 425 | 395 | } | |
| 426 | 396 | ||
@@ -470,67 +440,6 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication | |||
| 470 | 440 | this.notifyAppStarted(); | |
| 471 | 441 | } | |
| 472 | 442 | ||
| 473 | - /** | ||
| 474 | - * After an in-process soft reboot (NativeScriptRuntime.reloadApplication / | ||
| 475 | - * restartWithConfig), the Objective-C delegate classes created by the | ||
| 476 | - * previous JS isolate still exist and UIKit keeps dispatching to their | ||
| 477 | - * now-inert instances: their method callbacks bail out because the isolate | ||
| 478 | - * that implemented them is gone. Notification-center observers are | ||
| 479 | - * re-registered by the new isolate, but delegate-based dispatch (custom | ||
| 480 | - * UIApplicationDelegate methods like push-token/openURL callbacks, and the | ||
| 481 | - * UIScene delegates used by scene-lifecycle apps) stays pinned to the old | ||
| 482 | - * bundle. Recreate those delegates from this bundle's classes and re-point | ||
| 483 | - * UIKit at them. | ||
| 484 | - */ | ||
| 485 | - private _reattachNativeDelegatesAfterSoftReboot(): void { | ||
| 486 | - if (getRuntimeReloadCount() <= 0) { | ||
| 487 | - // First boot: UIApplicationMain (or the host app) set up delegates. | ||
| 488 | - return; | ||
| 489 | - } | ||
| 490 | - | ||
| 491 | - if (isEmbedded()) { | ||
| 492 | - // The host app owns the UIApplication delegate; never touch it. | ||
| 493 | - return; | ||
| 494 | - } | ||
| 495 | - | ||
| 496 | - const app = UIApplication.sharedApplication; | ||
| 497 | - if (!app) { | ||
| 498 | - return; | ||
| 499 | - } | ||
| 500 | - | ||
| 501 | - // Fresh application delegate from the new bundle. Assigning `delegate` | ||
| 502 | - // does not retain (unlike the UIApplicationMain launch path), so keep a | ||
| 503 | - // strong reference ourselves. | ||
| 504 | - this.delegate ??= Responder as any; | ||
| 505 | - const freshDelegate = (<any>this.delegate).new() as UIApplicationDelegate; | ||
| 506 | - this._softRebootAppDelegate = freshDelegate; | ||
| 507 | - app.delegate = freshDelegate; | ||
| 508 | - | ||
| 509 | - // Re-point already-connected scenes at fresh scene delegates so scene | ||
| 510 | - // lifecycle and user-implemented scene delegate methods (shortcuts, | ||
| 511 | - // openURLContexts, userActivity continuation, etc.) reach this isolate. | ||
| 512 | - // Newly connecting scenes are covered by the fresh application delegate's | ||
| 513 | - // applicationConfigurationForConnectingSceneSessionOptions, which returns | ||
| 514 | - // this bundle's SceneDelegate class. | ||
| 515 | - if (this.supportsScenes()) { | ||
| 516 | - this._softRebootSceneDelegates.clear(); | ||
| 517 | - const scenes = app.connectedScenes?.allObjects; | ||
| 518 | - for (let i = 0; scenes && i < scenes.count; i++) { | ||
| 519 | - const scene = scenes.objectAtIndex(i); | ||
| 520 | - if (!(scene instanceof UIWindowScene)) { | ||
| 521 | - continue; | ||
| 522 | - } | ||
| 523 | - const freshSceneDelegate = SceneDelegate.new() as UIWindowSceneDelegate; | ||
| 524 | - scene.delegate = freshSceneDelegate; | ||
| 525 | - this._softRebootSceneDelegates.set(scene, freshSceneDelegate); | ||
| 526 | - } | ||
| 527 | - } | ||
| 528 | - | ||
| 529 | - if (Trace.isEnabled()) { | ||
| 530 | - Trace.write(`Reattached application delegate${this._softRebootSceneDelegates.size ? ` and ${this._softRebootSceneDelegates.size} scene delegate(s)` : ''} after soft reboot (reloadCount: ${getRuntimeReloadCount()})`, Trace.categories.NativeLifecycle); | ||
| 531 | - } | ||
| 532 | - } | ||
| 533 | - | ||
| 534 | 443 | private getViewController(rootView: View): UIViewController { | |
| 535 | 444 | let viewController: UIViewController = rootView.viewController || rootView.ios; | |
| 536 | 445 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -111,6 +111,7 @@ declare module globalThis { | |||
| 111 | 111 | var __extends: any; | |
| 112 | 112 | var __onLiveSync: (context?: { type: string; path: string }) => void; | |
| 113 | 113 | var __onLiveSyncCore: (context?: { type: string; path: string }) => void; | |
| 114 | + var __onApplicationReload: () => void; | ||
| 114 | 115 | var __onUncaughtError: (error: NativeScriptError) => void; | |
| 115 | 116 | var __onDiscardedError: (error: NativeScriptError) => void; | |
| 116 | 117 | var __snapshot: boolean; | |
@@ -165,39 +166,39 @@ interface NodeModule { | |||
| 165 | 166 | } | |
| 166 | 167 | ||
| 167 | 168 | declare enum RequestContext { | |
| 168 | - 'audio', | ||
| 169 | - 'beacon', | ||
| 170 | - 'cspreport', | ||
| 171 | - 'download', | ||
| 172 | - 'embed', | ||
| 173 | - 'eventsource', | ||
| 174 | - 'favicon', | ||
| 175 | - 'fetch', | ||
| 176 | - 'font', | ||
| 177 | - 'form', | ||
| 178 | - 'frame', | ||
| 179 | - 'hyperlink', | ||
| 180 | - 'iframe', | ||
| 181 | - 'image', | ||
| 182 | - 'imageset', | ||
| 183 | - 'import', | ||
| 184 | - 'internal', | ||
| 185 | - 'location', | ||
| 186 | - 'manifest', | ||
| 187 | - 'object', | ||
| 188 | - 'ping', | ||
| 189 | - 'plugin', | ||
| 190 | - 'prefetch', | ||
| 191 | - 'script', | ||
| 192 | - 'serviceworker', | ||
| 193 | - 'sharedworker', | ||
| 194 | - 'subresource', | ||
| 195 | - 'style', | ||
| 196 | - 'track', | ||
| 197 | - 'video', | ||
| 198 | - 'worker', | ||
| 199 | - 'xmlhttprequest', | ||
| 200 | - 'xslt', | ||
| 169 | + audio, | ||
| 170 | + beacon, | ||
| 171 | + cspreport, | ||
| 172 | + download, | ||
| 173 | + embed, | ||
| 174 | + eventsource, | ||
| 175 | + favicon, | ||
| 176 | + fetch, | ||
| 177 | + font, | ||
| 178 | + form, | ||
| 179 | + frame, | ||
| 180 | + hyperlink, | ||
| 181 | + iframe, | ||
| 182 | + image, | ||
| 183 | + imageset, | ||
| 184 | + import, | ||
| 185 | + internal, | ||
| 186 | + location, | ||
| 187 | + manifest, | ||
| 188 | + object, | ||
| 189 | + ping, | ||
| 190 | + plugin, | ||
| 191 | + prefetch, | ||
| 192 | + script, | ||
| 193 | + serviceworker, | ||
| 194 | + sharedworker, | ||
| 195 | + subresource, | ||
| 196 | + style, | ||
| 197 | + track, | ||
| 198 | + video, | ||
| 199 | + worker, | ||
| 200 | + xmlhttprequest, | ||
| 201 | + xslt, | ||
| 201 | 202 | } | |
| 202 | 203 | ||
| 203 | 204 | // Extend the lib.dom.d.ts Body interface with `formData` | |
| Back | FazBrowse Home | New Git URL |
0 commit comments