Skip to content

[Android] Replace JavascriptInterface with WebMessageListener - #424

Merged
kiftio merged 1 commit into
mainfrom
dk/web-message-listener
Jul 14, 2026
Merged

[Android] Replace JavascriptInterface with WebMessageListener#424
kiftio merged 1 commit into
mainfrom
dk/web-message-listener

Conversation

@kiftio

@kiftio kiftio commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

What changes are you making?

Replaces the addJavascriptInterface transport for the Embedded Checkout Protocol (ECP) bridge with WebViewCompat.addWebMessageListener, a more secure and modern WebView API.

See
https://developer.android.com/privacy-and-security/risks/insecure-webview-native-bridges

The addJavascriptInterface method injects a supplied Java object into every frame of the WebView, including iframes, which means it is susceptible to attack by malicious third parties injecting frames into a legitimate website.

Recommended here. And addJavaScriptInterface is referred to as legacy further down on the same page.

The bridge is now registered via WebViewCompat.addWebMessageListener when WebViewFeature.WEB_MESSAGE_LISTENER is supported, and torn down via WebViewCompat.removeWebMessageListener on detach.

EmbeddedCheckoutProtocolBridge.postMessage now delegates to a new internal receiveMessage method, and CheckoutWebView exposes a receiveWebMessage entry point that filters out child-frame messages before forwarding to the bridge.

A new CheckoutWebViewFeatureSupport object centralises feature detection, exposes the web_view_not_supported error code and exception, and provides test override/reset helpers. When WEB_MESSAGE_LISTENER is not available, present immediately callsonCheckoutFailed with a CheckoutKitException carrying the web_view_not_supported error code and returns null, andpreload exits early without creating a cached view.

The Android README documents the new web_view_not_supported error code in the exceptions table and adds a troubleshooting entry advising callers to open the checkout URL in Chrome, Chrome Custom Tabs, or another full browser, or to prompt the buyer to update Android System WebView or Chrome. The minimum supported WebView version is Android System WebView / Chrome 83 (released May 2020).


WebMessageListener Support

- M83 / 83.0.4103.x: stable WEB_MESSAGE_LISTENER advertised.
- M79-M82: present only as WEB_MESSAGE_LISTENER:dev, so not supported on normal production Android builds.
- M78 and older: not present.

Components

  • ShopifyCheckoutKit — entry point; supplies the production transport publicly while allowing transport injection in tests.
  • CheckoutBottomSheet — binds presentation concerns: listener, protocol client, and the retained or newly created WebView.
  • CheckoutWebView — owns the bridge for the WebView’s lifetime, including preloaded WebViews.
  • WebMessageTransport — internal messaging boundary for attaching/detaching listeners and sending responses.
  • WebMessageListenerTransport — production AndroidX WebKit implementation of the above interface, including feature detection, listener registration, JavaScript evaluation, escaping, and main-thread dispatch.
  • EmbeddedCheckoutProtocolBridge — owns transport lifecycle, filters inbound messages, decodes/routes protocol messages on a serial executor, composes built-in and merchant handlers, and sends responses.

How to test

  1. Run the Android unit tests to verify the new WebMessageListener transport path and unsupported-WebView behaviour.
  2. Verify that the web message is received by protocol bridge test passes, confirming that messages delivered via receiveWebMessage are correctly handled by the protocol bridge.
  3. Verify that the web message from child frame is ignored test passes, confirming that messages from child frames are filtered out.
  4. Verify that present emits unsupported WebView error and returns null and preload does nothing when WebView is unsupported pass, confirming early-exit behaviour when the feature is unavailable.
  5. On a device or emulator with a WebView version that supports WEB_MESSAGE_LISTENER, load a checkout and confirm that ECP messages are received and processed correctly.
  6. On a device or emulator where WEB_MESSAGE_LISTENER is not supported, confirm that present calls onCheckoutFailed with web_view_not_supported and does not display the bottom sheet.

Before you merge

Important

  • I've added tests to support my implementation
  • I have read and agree with the Contribution Guidelines
  • I have read and agree with the Code of Conduct
  • I've updated the relevant platform README (platforms/swift/README.md and/or platforms/android/README.md)

Releasing a new Swift version?
  • I have bumped the version in ShopifyCheckoutKit.podspec
  • I have bumped the version in platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift
  • I have updated the SwiftPM/CocoaPods version snippets in platforms/swift/README.md (major version only)
Releasing a new Embedded Checkout Protocol version?
  • I have bumped embeddedCheckoutProtocolAndroid in platforms/android/gradle/libs.versions.toml
  • I have updated protocol/languages/kotlin/embedded-checkout-protocol/api/embedded-checkout-protocol.api if the public API changed
Releasing a new Android version?
  • I have bumped checkoutKitAndroid in platforms/android/gradle/libs.versions.toml
  • I have updated the Gradle/Maven version snippets in platforms/android/README.md

Tip

See the Contributing documentation for the full release process per platform.

@github-actions github-actions Bot added the #gsd:50662 Rebase Checkout Kit on UCP label Jul 8, 2026
@kiftio
kiftio force-pushed the dk/web-message-listener branch from d97376b to 4f9359a Compare July 9, 2026 09:23

kiftio commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@kiftio kiftio changed the title use web message listner when available Use web message listener when available Jul 9, 2026
@kiftio
kiftio marked this pull request as ready for review July 9, 2026 09:50
@kiftio
kiftio requested a review from a team as a code owner July 9, 2026 09:50
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

React Native — Coverage Report

Lines Statements Branches Functions
Coverage: 92%
91.85% (327/356) 87.98% (183/208) 100% (86/86)

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Package Size

Platform Artifact Base Head Delta
Android release AAR 222.6 KiB 232.6 KiB +10.0 KiB
Android file breakdown
File Base Head Delta
classes.jar 235.5 KiB 246.2 KiB +10.7 KiB
res/layout/checkout_sheet_content.xml 4.0 KiB 4.0 KiB 0 B
res/values/values.xml 1.2 KiB 1.2 KiB 0 B
R.txt 1.0 KiB 1.0 KiB 0 B
proguard.txt 798 B 798 B 0 B
AndroidManifest.xml 578 B 578 B 0 B
res/drawable/close.xml 431 B 431 B 0 B
res/menu/checkout_menu.xml 354 B 354 B 0 B
META-INF/com/android/build/gradle/aar-metadata.properties 157 B 157 B 0 B

Measured from the PR base SHA and PR head SHA. The file breakdown shows uncompressed sizes within each package artifact, so individual files do not sum to the compressed artifact total. This comment reports package artifact sizes only; it is not a final app binary-size report.

@kiftio
kiftio force-pushed the dk/web-message-listener branch 3 times, most recently from f0c8de2 to 0b38f90 Compare July 9, 2026 21:56
}

internal fun receiveWebMessage(message: String?, isMainFrame: Boolean = true) {
if (!isMainFrame) {

@kiftio kiftio Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new check. Some potential for issues if we're relying on any sub-frames to emit message

I don't see why we would be though

@kiftio
kiftio force-pushed the dk/web-message-listener branch from 0b38f90 to d63a691 Compare July 10, 2026 08:41
Comment thread platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutWebView.kt Outdated
@kiftio
kiftio force-pushed the dk/web-message-listener branch 2 times, most recently from f14f9d6 to 1f74d2c Compare July 10, 2026 09:34
@kiftio kiftio changed the title Use web message listener when available [Android] Replace JavascriptInterface with WebMessageListener Jul 10, 2026
Comment thread platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutWebView.kt Outdated
Comment thread platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutWebView.kt Outdated
@kiftio
kiftio requested a review from michaeljsXu July 10, 2026 14:02
@kiftio
kiftio force-pushed the dk/web-message-listener branch 4 times, most recently from 83fa948 to 8437018 Compare July 13, 2026 08:55
@kiftio
kiftio marked this pull request as draft July 13, 2026 09:21
fun detach(webView: WebView, jsObjectName: String)
}

internal object WebMessageListenerTransport : WebMessageTransport {

@kieran-osgood-shopify kieran-osgood-shopify Jul 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this - was mulling over something to just wrap up the combination of the isfeaturesupported + addWebMessageListener would be a nice compromise to the mocking

Decoupling the feature supported checks from CheckoutWebView looks great

@kiftio
kiftio force-pushed the dk/web-message-listener branch 2 times, most recently from 0f18bd2 to 08fdf1d Compare July 13, 2026 11:38
@kiftio
kiftio force-pushed the dk/web-message-listener branch 2 times, most recently from d45dd70 to ad74a4d Compare July 13, 2026 13:34
@kiftio
kiftio marked this pull request as ready for review July 13, 2026 13:38
Comment thread platforms/android/lib/src/main/java/com/shopify/checkoutkit/ShopifyCheckoutKit.kt Outdated
@kiftio
kiftio merged commit 3fc47fb into main Jul 14, 2026
32 checks passed
@kiftio
kiftio deleted the dk/web-message-listener branch July 14, 2026 13:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

#gsd:50662 Rebase Checkout Kit on UCP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants