From 56df33ca6210c00474631c23f352b1cb383d43a2 Mon Sep 17 00:00:00 2001 From: Denis Svara Date: Tue, 7 Jul 2026 16:26:07 +0200 Subject: [PATCH 1/2] Keep bridge destinations active while attached --- Source/Bridge/BridgeDelegate.swift | 10 +++------- Tests/Bridge/BridgeDelegate+DestinationTests.swift | 10 +++++++--- Tests/Bridge/BridgeDelegateTests.swift | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/Bridge/BridgeDelegate.swift b/Source/Bridge/BridgeDelegate.swift index 2d5a1ff1..4c024c20 100644 --- a/Source/Bridge/BridgeDelegate.swift +++ b/Source/Bridge/BridgeDelegate.swift @@ -52,7 +52,6 @@ public final class BridgeDelegate: BridgingDelegate { public func webViewDidBecomeActive(_ webView: WKWebView) { bridge = Bridge.getBridgeFor(webView) bridge?.delegate = self - destinationIsActive = true if bridge == nil { logger.warning("bridgeNotInitializedForWebView") @@ -62,7 +61,6 @@ public final class BridgeDelegate: BridgingDelegate { public func webViewDidBecomeDeactivated() { bridge?.delegate = nil bridge = nil - destinationIsActive = false } @discardableResult @@ -84,19 +82,16 @@ public final class BridgeDelegate: BridgingDelegate { public func onViewDidLoad() { logger.debug("[Bridge] bridgeDestinationViewDidLoad: \(self.resolvedLocation)") - destinationIsActive = true activeComponents.forEach { $0.viewDidLoad() } } public func onViewWillAppear() { logger.debug("[Bridge] bridgeDestinationViewWillAppear: \(self.resolvedLocation)") - destinationIsActive = true activeComponents.forEach { $0.viewWillAppear() } } public func onViewDidAppear() { logger.debug("[Bridge] bridgeDestinationViewDidAppear: \(self.resolvedLocation)") - destinationIsActive = true activeComponents.forEach { $0.viewDidAppear() } } @@ -107,7 +102,6 @@ public final class BridgeDelegate: BridgingDelegate { public func onViewDidDisappear() { activeComponents.forEach { $0.viewDidDisappear() } - destinationIsActive = false logger.debug("[Bridge] bridgeDestinationViewDidDisappear: \(self.resolvedLocation)") } @@ -147,8 +141,10 @@ public final class BridgeDelegate: BridgingDelegate { // MARK: Private private var initializedComponents: [String: BridgeComponent] = [:] - private var destinationIsActive = false private let componentTypes: [BridgeComponent.Type] + private var destinationIsActive: Bool { + bridge != nil + } private var resolvedLocation: String { webView?.url?.absoluteString ?? location } diff --git a/Tests/Bridge/BridgeDelegate+DestinationTests.swift b/Tests/Bridge/BridgeDelegate+DestinationTests.swift index 88178f7e..b42b368f 100644 --- a/Tests/Bridge/BridgeDelegate+DestinationTests.swift +++ b/Tests/Bridge/BridgeDelegate+DestinationTests.swift @@ -57,17 +57,21 @@ class BridgeDelegateDestinationTests: XCTestCase { XCTAssertNotNil(component) } - func testBridgeDestinationIsInactiveAfterViewDidDisappear() { + func testBridgeDestinationRemainsActiveAfterViewDidDisappearWhenWebViewIsStillActive() { + // Tab bar destinations can receive view disappearance callbacks while + // their web view remains active and attached to the bridge. delegate.onViewDidLoad() delegate.onViewDidDisappear() delegate.bridgeDidReceiveMessage(.test) let component: BridgeComponentSpy? = delegate.component() - XCTAssertNil(component) + XCTAssertNotNil(component) } func testBridgeDestinationIsActiveAfterWebViewDidBecomeActive() { - delegate.webViewDidBecomeActive(WKWebView()) + let webView = WKWebView() + Bridge.initialize(webView) + delegate.webViewDidBecomeActive(webView) delegate.bridgeDidReceiveMessage(.test) let component: BridgeComponentSpy? = delegate.component() diff --git a/Tests/Bridge/BridgeDelegateTests.swift b/Tests/Bridge/BridgeDelegateTests.swift index 9f64c811..58b0c3ad 100644 --- a/Tests/Bridge/BridgeDelegateTests.swift +++ b/Tests/Bridge/BridgeDelegateTests.swift @@ -125,7 +125,7 @@ class BridgeDelegateTests: XCTestCase { XCTAssertNotNil(component?.delegate) } - func testBridgeIgnoresMessageForInactiveDestination() { + func testBridgeIgnoresMessageAfterWebViewBecomesDeactivated() { let message = Message(id: "1", component: "one", event: "connect", @@ -137,7 +137,7 @@ class BridgeDelegateTests: XCTestCase { var component: OneBridgeComponent? = delegate.component() XCTAssertNotNil(component) - delegate.onViewDidDisappear() + delegate.webViewDidBecomeDeactivated() XCTAssertFalse(delegate.bridgeDidReceiveMessage(message)) component = delegate.component() From e87b2fda7ccedc48c75f9f2bcd294c4cf6b80fbc Mon Sep 17 00:00:00 2001 From: Denis Svara Date: Tue, 7 Jul 2026 16:34:52 +0200 Subject: [PATCH 2/2] Simplify bridge components guard --- Source/Bridge/BridgeDelegate.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Bridge/BridgeDelegate.swift b/Source/Bridge/BridgeDelegate.swift index 4c024c20..f767c144 100644 --- a/Source/Bridge/BridgeDelegate.swift +++ b/Source/Bridge/BridgeDelegate.swift @@ -150,7 +150,11 @@ public final class BridgeDelegate: BridgingDelegate { } private var activeComponents: [BridgeComponent] { - return initializedComponents.values.filter { _ in destinationIsActive } + guard destinationIsActive else { + return [] + } + + return Array(initializedComponents.values) } private func getOrCreateComponent(name: String) -> BridgeComponent? {