fix: support OAuth/Sign-in-with-Google popups on both engines#17
Merged
Conversation
Google sign-in and other OAuth/SSO flows open their consent screen in a popup via window.open()/target=_blank. Neither engine surfaced it: - System WebView never overrode onCreateWindow, so the popup was silently dropped and sign-in could not complete. - GeckoView loaded the popup URL into the main session, destroying the window.opener relationship the flow needs. Both engines now create a real popup window and hand it to the host via BrowserEngineCallback.onShowPopup/onClosePopup; BrowserEngine.closeTopPopup lets the host dismiss the topmost one. WebViewManager enables multiple windows. GeckoView returns a new unopened child session (per contract) that inherits the parent contextId so cookies are shared with the opener.
Display engine popups (onShowPopup) as full-bleed overlays in the WebView container and remove them on onClosePopup. For System WebView popups the per-app isolation profile is re-applied so sign-in cookies land in the app's own store; GeckoView popups inherit the parent contextId. Back-press dismisses the topmost popup before navigating the page.
Real System WebView test drives window.open() and asserts the popup overlay appears and back-press dismisses it. Real GeckoView test taps a sign-in button (Gecko's popup blocker requires a user gesture) and asserts the overlay appears; it is gated behind assumeTrue(isInstalled()) so it skips on CI where the Gecko runtime is absent. A fake-engine test covers the shared host wiring used by both engines.
…engine isExternalScheme treated every non-http(s) URL as an external link, handing data:/blob:/about:/javascript: to startActivity() instead of loading them in the WebView. These are web-content schemes used by OAuth popups (window.open + about:blank/document.write) and JS-generated documents — externalizing them left the popup blank so its script never ran. Only genuinely external schemes (tel:, mailto:, intent:, custom app schemes) are dispatched to the host now.
Adds two on-device System WebView E2E tests: a popup that loads (about:blank + document.write — Chromium blocks window.open to data: URLs) and calls window.close() must dismiss its overlay; and a popup that postMessages its window.opener must round-trip (opener opens a second window on receipt).
Loads https://shellify.app/tools.html and invokes its own openSelfClosing() instead of an injected fixture, asserting the popup appears and self-dismisses. Skips (assumeTrue) when the page is unreachable so it never reds an offline runner. Requires the deployed page to use the about:blank popup pattern.
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.
Fixes #14
Problem
"Sign in with Google" (and other OAuth/SSO flows) open their consent screen in a popup via
window.open()/target="_blank". Neither browser engine surfaced that popup, so sign-in could never complete — the site then falls back to a generic "cookies required" message (the symptom reported in #14 on System WebView).WebChromeClient.onCreateWindow, so the popup was silently dropped.onNewSessionloaded the popup URL into the main session, navigating the page away and destroying thewindow.openerrelationship the flow needs.Fix
Both engines now open a real popup window and surface it to the host:
WebViewManagerenablessetSupportMultipleWindows(true)+javaScriptCanOpenWindowsAutomatically.SystemWebViewEngineoverridesonCreateWindow(spawns a popupWebView) andonCloseWindow(dismisses it).GeckoViewEngine.onNewSessionreturns a new unopened childGeckoSession(per the GeckoView contract) built from the parent's settings, so it inherits thecontextIdand shares cookies/storage with the opener;ContentDelegate.onCloseRequestdismisses it.BrowserEngineCallback.onShowPopup/onClosePopupandBrowserEngine.closeTopPopup().WebViewActivityhosts popups as full-screen overlays. For System WebView popups it re-applies the per-app isolation profile so sign-in cookies land in the app's own store (Android 13+). Back-press dismisses the topmost popup first.Tests
Verified on a real arm64 emulator (incl. a real GeckoView runtime):
systemWebView_windowOpen_showsPopupOverlay_andBackDismissesgeckoView_windowOpen_showsPopupOverlayassumeTrue(isInstalled()))popupHostingContract_showsAndRemovesOverlayPlus
ExternalSchemeTestunit tests.detekt,lintDebug,testDebugUnitTest(+ Konsist) andverifyRoborazziDebugall pass.Note
Google additionally blocks OAuth inside embedded WebViews by user-agent (
disallowed_useragent) for some sites; that is independent of this popup fix and would need a Custom Tab path if it surfaces.