injectedJavaScriptForMainFrameOnly={false} is ignored on Android. No way to inject into (cross-origin) iframes.

Author: rigo-ptzCreated Aug 10, 2026Updated Aug 10, 2026
LabelsType: bug report

Bug description:

On Android, injectedJavaScriptForMainFrameOnly={false} and injectedJavaScriptBeforeContentLoadedForMainFrameOnly={false} have no effect: the injected script always runs in the main frame only, and there is no supported way to reach a (cross-origin) . The props are accepted by the API and stored on the native view, but the Android implementation never reads them. So this is a silent no-op, not a documented "iOS/macOS-only" feature.

This blocks any page that keeps logic inside a cross-origin iframe (e.g. embedded payment/bank flows) where a JS bridge must be present inside that iframe.

Current behaviour:

  • injectedJavaScript / injectedJavaScriptBeforeContentLoaded are delivered via WebView.evaluateJavascript(...) (RNCWebView.evaluateJavascriptWithFallback, called at from onPageFinished / onPageStarted). evaluateJavascript is inherently main-frame-only.

  • The *ForMainFrameOnly booleans are only written by the ViewManager setters and are never read anywhere in the Android sources. Setting the prop therefore changes nothing.

  • The Reference docs note that the all-frames behaviour is iOS/macOS only, but the props remain exposed and silently accepted on Android, which is misleading.

All-frames delivery is already used on Android by this library:

  • window.ReactNativeWebView reaches every frame because it is registered via WebViewCompat.addWebMessageListener(webView, "ReactNativeWebView", Set.of("*"), …). "*" origin rule matches all frames, main and sub.
  • injectedJavaScriptObject is likewise exposed to all frames through that same message-listener channel.

To Reproduce:

The repository's own injection example is the cleanest reproduction: example/examples/Injection.tsx. It already sets both injectedJavaScriptForMainFrameOnly={false} and injectedJavaScriptBeforeContentLoadedForMainFrameOnly={false}, loads a page containing three iframes (one cross-origin), and its injected scripts branch on window.self === window.top to apply per-iframe effects — i.e. it is explicitly written to demonstrate all-frames injection.

  1. Run the Injection example on iOS -> the per-iframe effects (the beforeContentLoaded/afterContentLoaded styling applied inside each frame) appear in the iframes.
  2. Run the same example on Android -> the per-iframe effects do not appear inside the iframes; only the main frame is affected, because the injected scripts never run in the subframes (and the *ForMainFrameOnly={false} props are ignored).

Or minimal variant:

  1. On Android, load a page in a that embeds a cross-origin .
  2. Set injectedJavaScriptBeforeContentLoadedForMainFrameOnly={false} and inject a script that sets window.__marker = 'hit'.
  3. From inside the iframe, evaluate window.__marker. It will be undefined; the script never ran there. For contrast, from the same iframe, window.ReactNativeWebView is defined.

Expected behavior:

Injection is applied to all iframes.

Screenshots/Videos:

Environment:

  • OS: Android
  • OS version: All
  • react-native version: 0.85.3
  • react-native-webview version: 13.16.1 (the same behaviour is in current master as well)

Source: react-native-webview/react-native-webview