Conversation
Because: - The "Continue with Firefox" tap on /poc_pair_init exists only because WebKit requires external-scheme navigations to be top-level AND user-initiated - Chromium has no such requirement, and the Android intent:// already carries its own store fallback in S.browser_fallback_url, so there is nothing for the JS watchdog to infer either - On Android the tap therefore buys nothing: the user already acted, by scanning the QR This commit: - Fires the deep link from the mount effect on Android, keeping the happy path at zero taps; iOS and armStoreFallback are untouched - Spends a one-shot sessionStorage token keyed on the target, because Back from the Play Store returns to this page in the same tab and an unguarded effect would bounce the user straight back out - Splits the read-only decision from the write, so the decision is safe to evaluate during render and the caller only navigates once the write succeeded - Treats unavailable or throwing storage as "do not auto-attempt", since without a spent-token record the bounce loop cannot be prevented - Adds ?auto=0 to restore the tap-to-continue flow for on-device A/B - Reveals the manual CTA after `timeout` for in-app WebViews that swallow intent://; state only, so it cannot race the store fallback - Shows the "Get Firefox" escape hatch on Android too, since reaching that card means S.browser_fallback_url never got the chance to run - Matches isAndroid explicitly rather than inferring "mobile and not iOS", which had swept in mobile UAs that cannot handle intent:// - Covers the guard with unit tests and records the Android finding in the file's header log Closes #FXA-14304
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Because
/poc_pair_initexists only because WebKit requires external-scheme navigations to be top-level and user-initiated. It is an iOS constraint, not a general one.intent://navigation made from page script with no user-activation bit required, and the Android intent already carries its own store fallback inS.browser_fallback_url— so there is nothing for the JS watchdog to infer either.This pull request
armStoreFallbackare untouched.sessionStoragetoken keyed on the target. Back from the Play Store returns to this page in the same tab, and an unguarded effect would re-fire the intent and bounce the user straight back out.sessionStorageis the only store that survives both a reload and the native-app round-trip.shouldAutoAttempt) from the write (claimAutoAttempt), so the decision is safe to evaluate during render — including under StrictMode's double render — and the caller only navigates once the write actually succeeded.?auto=0to restore the tap-to-continue flow, following the existing?timeout=/?grace=on-device override convention.timeoutfor in-app WebViews that swallowintent://(a link opened from Gmail, say). State only — it never navigates, so it cannot race the store fallback.S.browser_fallback_urlnever got the chance to run.isAndroidexplicitly rather than inferring "mobile and not iOS", which had swept in mobile UAs that cannot handleintent://. Those now fall through to thefirefox://+ watchdog path.Issue that this pull request solves
Closes: FXA-14304
Checklist
Put an
xin the boxes that applyHow to review (Optional)
PocPairInit/index.tsx— the mount effect and theshouldAutoAttempt/claimAutoAttemptpair. The guard is the part worth scrutiny; everything else is small.Other information (Optional)
Draft — the central claim is not yet verified on a real device. Chromium has been progressively tightening external-app launches without user activation, and a QR-initiated page load does not hand the page a user-activation bit. Commercial deep-link services (Branch, AppsFlyer, Firebase Dynamic Links) all rely on this working, so it is expected to, but that needs confirming on a phone — which is the point of the POC. If it turns out blocked, the WebView timer degrades the page to today's behaviour, so there is no regression risk either way.
On-device matrix still to run:
/poc_pair_initshowing the manual card; must not bounce back to the store. Check both a bfcache restore and a hard reloadtimeoutms, then the manual card?auto=0armStoreFallbackstill runsJudge "did we remove a tap" against stage/https, not localhost: over plain http the Android activity chooser can still appear, because the no-chooser path is verified App Links (app-side, FXA-13732).
🤖 Generated with Claude Code