Summary
WebView::is_programmatic_navigation_ (packages/flutter_inappwebview/tizen/src/webview.cc) is a single shared bool used to tell OnNavigationPolicy "the next navigation was requested by the app (loadUrl/goBack/goForward/reload/etc.), so skip the shouldOverrideUrlLoading round-trip." It is set in NavigateProgrammatically() and cleared from five different places: OnNavigationPolicy, OnLoadStarted, OnLoadFinished, and OnLoadError.
Because it's a single bit with no identifier tying it to a specific call, and because the EWK callbacks that clear it are asynchronous relative to the platform-channel call that set it, overlapping navigations can clear/consume the flag out of order.
Repro scenario
- Dart calls
loadUrl(X). NavigateProgrammatically sets the flag, ewk_view_url_set(X) starts.
policy,navigation,decide for X arrives, sees the flag, correctly treats X as programmatic, clears the flag.
load,started for X arrives.
- Before X finishes loading, Dart calls
goBack(). The flag is set again, ewk_view_back() runs and effectively abandons X's in-flight load.
- EWK fires
load,error for the now-abandoned X before the back navigation's own policy,navigation,decide arrives. OnLoadError unconditionally clears the flag — but this event belongs to X, not to the pending goBack().
policy,navigation,decide for the back navigation arrives with the flag already false, so it is treated as a normal (non-programmatic) navigation: the view is suspended and shouldOverrideUrlLoading is invoked for a navigation the app itself requested via goBack().
The reverse can also happen: a genuine user-initiated navigation (e.g. a link click) whose policy decision arrives while an unrelated programmatic flag is still pending could be incorrectly skipped past the delegate.
Why it's not a quick fix
The EWK smart callbacks (policy,navigation,decide, load,started, load,finished, load,error) don't carry any per-call correlation id, so there's no reliable way to tell which NavigateProgrammatically() call a given callback invocation corresponds to when two navigations are in flight at once. A counter instead of a bool reduces but doesn't eliminate the ambiguity — the callback sites still can't tell whose counter decrement they're performing.
A real fix likely needs one of:
- Correlating navigations via whatever navigation/frame identifier EWK exposes (needs investigation into what's actually available from the chromium-ewk API), or
- Removing the redundant clears from
OnLoadStarted/OnLoadFinished/OnLoadError (added in a prior fix for a stale-flag bug) in favor of a design that doesn't need them, without reopening that original bug.
Context
Found during review of #1083 (see this discussion thread and the follow-up reply). Not fixed as part of that PR; filing separately to track.
Summary
WebView::is_programmatic_navigation_(packages/flutter_inappwebview/tizen/src/webview.cc) is a single sharedboolused to tellOnNavigationPolicy"the next navigation was requested by the app (loadUrl/goBack/goForward/reload/etc.), so skip theshouldOverrideUrlLoadinground-trip." It is set inNavigateProgrammatically()and cleared from five different places:OnNavigationPolicy,OnLoadStarted,OnLoadFinished, andOnLoadError.Because it's a single bit with no identifier tying it to a specific call, and because the EWK callbacks that clear it are asynchronous relative to the platform-channel call that set it, overlapping navigations can clear/consume the flag out of order.
Repro scenario
loadUrl(X).NavigateProgrammaticallysets the flag,ewk_view_url_set(X)starts.policy,navigation,decidefor X arrives, sees the flag, correctly treats X as programmatic, clears the flag.load,startedfor X arrives.goBack(). The flag is set again,ewk_view_back()runs and effectively abandons X's in-flight load.load,errorfor the now-abandoned X before the back navigation's ownpolicy,navigation,decidearrives.OnLoadErrorunconditionally clears the flag — but this event belongs to X, not to the pendinggoBack().policy,navigation,decidefor the back navigation arrives with the flag already false, so it is treated as a normal (non-programmatic) navigation: the view is suspended andshouldOverrideUrlLoadingis invoked for a navigation the app itself requested viagoBack().The reverse can also happen: a genuine user-initiated navigation (e.g. a link click) whose policy decision arrives while an unrelated programmatic flag is still pending could be incorrectly skipped past the delegate.
Why it's not a quick fix
The EWK smart callbacks (
policy,navigation,decide,load,started,load,finished,load,error) don't carry any per-call correlation id, so there's no reliable way to tell whichNavigateProgrammatically()call a given callback invocation corresponds to when two navigations are in flight at once. A counter instead of a bool reduces but doesn't eliminate the ambiguity — the callback sites still can't tell whose counter decrement they're performing.A real fix likely needs one of:
OnLoadStarted/OnLoadFinished/OnLoadError(added in a prior fix for a stale-flag bug) in favor of a design that doesn't need them, without reopening that original bug.Context
Found during review of #1083 (see this discussion thread and the follow-up reply). Not fixed as part of that PR; filing separately to track.