Keep bridge destinations active while attached#253
Conversation
|
Is this a fix for non-active tabs to receive bridge messages? Or screens "under" modals? Or something else entirely? I'm just trying to wrap my head around what the screens look like when the bug appears. |
This fixes the issue where a One way to reproduce the issue in the demo app is to slow down a bridge enabled page response: Switch to the Bridge Components tab, open the Overflow menu example, and then quickly switch to another tab. Switch bar to the Bridge Components tab, and the overflow icon will be missing and/or not working. |
|
Got it, thanks @svara! |
Summary
Bridge destinations should remain eligible to receive bridge messages for as long as their web view is still attached to the bridge.
This PR changes
BridgeDelegatesodestinationIsActiveis derived from bridge ownership (bridge != nil) instead of UIKit visibility callbacks. A destination can now receiveviewDidDisappearand still process bridge messages when its web view is still active, which is the case for tab bar/container-controller flows.The bug
BridgeDelegatepreviously treated UIKit visibility as bridge activity:onViewDidLoad,onViewWillAppear, andonViewDidAppearsetdestinationIsActive = true.onViewDidDisappearsetdestinationIsActive = false.bridgeDidReceiveMessagedropped every message unlessdestinationIsActivewas true and the message URL matched the current destination URL.That makes
viewDidDisappeara hard bridge cutoff. But UIKit visibility is not the same thing as web view ownership.In tab bar/container-controller setups, a
VisitableViewControllercan receive normal UIKit disappearance callbacks while its web view remains active and attached. If the web page sends a one-shot bridge message during that window, such as a componentconnect, native ignores it as an "inactive" destination even though the bridge is still the correct communication channel.Root cause
destinationIsActivemixed two different concepts:Bridgefor the active web view and can send/receive messages.bridgeDidReceiveMessageneeds the second concept. Using the first creates a race where a valid bridge message can be dropped afterviewDidDisappearbut before the web view/bridge has actually been deactivated.The fix
Stop mutating
destinationIsActivefrom view lifecycle callbacks.Stop mutating
destinationIsActivefromwebViewDidBecomeActive(_:)/webViewDidBecomeDeactivated()directly.Make
destinationIsActivea computed bridge-ownership check:Keep
webViewDidBecomeDeactivated()as the real deactivation point by clearing the bridge delegate and niling out the bridge reference.Keep
activeComponentsguarded bydestinationIsActive, but make the guard explicit so components are exposed only while replies can still go through the bridge.View lifecycle callbacks still forward
viewDidLoad,viewWillAppear,viewDidAppear,viewWillDisappear, andviewDidDisappearto initialized components. They just no longer decide whether future bridge messages are accepted.Behavior
viewDidDisappearwhile web view remains attached, e.g. tab/container lifecycle