mirror of
https://github.com/status-im/react-native-webview.git
synced 2025-02-23 09:18:38 +00:00
feat(android): Add support for injectedJavaScriptBeforeContentLoaded on Android (#1099 by @SRandazzo and @ @shirakaba)
This commit is contained in:
parent
b482bbd3a3
commit
ac4e05e0f2
@ -400,6 +400,21 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
|
|||||||
((RNCWebView) view).setInjectedJavaScript(injectedJavaScript);
|
((RNCWebView) view).setInjectedJavaScript(injectedJavaScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "injectedJavaScriptBeforeContentLoaded")
|
||||||
|
public void setInjectedJavaScriptBeforeContentLoaded(WebView view, @Nullable String injectedJavaScriptBeforeContentLoaded) {
|
||||||
|
((RNCWebView) view).setInjectedJavaScriptBeforeContentLoaded(injectedJavaScriptBeforeContentLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "injectedJavaScriptForMainFrameOnly")
|
||||||
|
public void setInjectedJavaScriptForMainFrameOnly(WebView view, boolean enabled) {
|
||||||
|
((RNCWebView) view).setInjectedJavaScriptForMainFrameOnly(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "injectedJavaScriptBeforeContentLoadedForMainFrameOnly")
|
||||||
|
public void setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(WebView view, boolean enabled) {
|
||||||
|
((RNCWebView) view).setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = "messagingEnabled")
|
@ReactProp(name = "messagingEnabled")
|
||||||
public void setMessagingEnabled(WebView view, boolean enabled) {
|
public void setMessagingEnabled(WebView view, boolean enabled) {
|
||||||
((RNCWebView) view).setMessagingEnabled(enabled);
|
((RNCWebView) view).setMessagingEnabled(enabled);
|
||||||
@ -753,6 +768,9 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
|
|||||||
super.onPageStarted(webView, url, favicon);
|
super.onPageStarted(webView, url, favicon);
|
||||||
mLastLoadFailed = false;
|
mLastLoadFailed = false;
|
||||||
|
|
||||||
|
RNCWebView reactWebView = (RNCWebView) webView;
|
||||||
|
reactWebView.callInjectedJavaScriptBeforeContentLoaded();
|
||||||
|
|
||||||
dispatchEvent(
|
dispatchEvent(
|
||||||
webView,
|
webView,
|
||||||
new TopLoadingStartEvent(
|
new TopLoadingStartEvent(
|
||||||
@ -1011,6 +1029,16 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
|
|||||||
protected static class RNCWebView extends WebView implements LifecycleEventListener {
|
protected static class RNCWebView extends WebView implements LifecycleEventListener {
|
||||||
protected @Nullable
|
protected @Nullable
|
||||||
String injectedJS;
|
String injectedJS;
|
||||||
|
protected @Nullable
|
||||||
|
String injectedJSBeforeContentLoaded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* android.webkit.WebChromeClient fundamentally does not support JS injection into frames other
|
||||||
|
* than the main frame, so these two properties are mostly here just for parity with iOS & macOS.
|
||||||
|
*/
|
||||||
|
protected boolean injectedJavaScriptForMainFrameOnly = true;
|
||||||
|
protected boolean injectedJavaScriptBeforeContentLoadedForMainFrameOnly = true;
|
||||||
|
|
||||||
protected boolean messagingEnabled = false;
|
protected boolean messagingEnabled = false;
|
||||||
protected @Nullable
|
protected @Nullable
|
||||||
String messagingModuleName;
|
String messagingModuleName;
|
||||||
@ -1105,6 +1133,18 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
|
|||||||
injectedJS = js;
|
injectedJS = js;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setInjectedJavaScriptBeforeContentLoaded(@Nullable String js) {
|
||||||
|
injectedJSBeforeContentLoaded = js;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInjectedJavaScriptForMainFrameOnly(boolean enabled) {
|
||||||
|
injectedJavaScriptForMainFrameOnly = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(boolean enabled) {
|
||||||
|
injectedJavaScriptBeforeContentLoadedForMainFrameOnly = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
protected RNCWebViewBridge createRNCWebViewBridge(RNCWebView webView) {
|
protected RNCWebViewBridge createRNCWebViewBridge(RNCWebView webView) {
|
||||||
return new RNCWebViewBridge(webView);
|
return new RNCWebViewBridge(webView);
|
||||||
}
|
}
|
||||||
@ -1159,6 +1199,14 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void callInjectedJavaScriptBeforeContentLoaded() {
|
||||||
|
if (getSettings().getJavaScriptEnabled() &&
|
||||||
|
injectedJSBeforeContentLoaded != null &&
|
||||||
|
!TextUtils.isEmpty(injectedJSBeforeContentLoaded)) {
|
||||||
|
evaluateJavascriptWithFallback("(function() {\n" + injectedJSBeforeContentLoaded + ";\n})();");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void onMessage(String message) {
|
public void onMessage(String message) {
|
||||||
ReactContext reactContext = (ReactContext) this.getContext();
|
ReactContext reactContext = (ReactContext) this.getContext();
|
||||||
RNCWebView mContext = this;
|
RNCWebView mContext = this;
|
||||||
|
@ -88,6 +88,7 @@ class MyWeb extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Controlling navigation state changes
|
### Controlling navigation state changes
|
||||||
@ -104,14 +105,14 @@ class MyWeb extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<WebView
|
<WebView
|
||||||
ref={ref => (this.webview = ref)}
|
ref={(ref) => (this.webview = ref)}
|
||||||
source={{ uri: 'https://reactnative.dev/' }}
|
source={{ uri: 'https://reactnative.dev/' }}
|
||||||
onNavigationStateChange={this.handleWebViewNavigationStateChange}
|
onNavigationStateChange={this.handleWebViewNavigationStateChange}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleWebViewNavigationStateChange = newNavState => {
|
handleWebViewNavigationStateChange = (newNavState) => {
|
||||||
// newNavState looks something like this:
|
// newNavState looks something like this:
|
||||||
// {
|
// {
|
||||||
// url?: string;
|
// url?: string;
|
||||||
@ -240,11 +241,12 @@ is used to determine if an HTTP response should be a download. On iOS 12 or olde
|
|||||||
trigger calls to `onFileDownload`.
|
trigger calls to `onFileDownload`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
onFileDownload = ({ nativeEvent }) => {
|
onFileDownload = ({ nativeEvent }) => {
|
||||||
const { downloadUrl } = nativeEvent;
|
const { downloadUrl } = nativeEvent;
|
||||||
// --> Your download code goes here <--
|
// --> Your download code goes here <--
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
To be able to save images to the gallery you need to specify this permission in your `ios/[project]/Info.plist` file:
|
To be able to save images to the gallery you need to specify this permission in your `ios/[project]/Info.plist` file:
|
||||||
@ -313,7 +315,7 @@ export default class App extends Component {
|
|||||||
|
|
||||||
This runs the JavaScript in the `runFirst` string once the page is loaded. In this case, you can see that both the body style was changed to red and the alert showed up after 2 seconds.
|
This runs the JavaScript in the `runFirst` string once the page is loaded. In this case, you can see that both the body style was changed to red and the alert showed up after 2 seconds.
|
||||||
|
|
||||||
By setting `injectedJavaScriptForMainFrameOnly: false`, the JavaScript injection will occur on all frames (not just the top frame) if supported for the given platform.
|
By setting `injectedJavaScriptForMainFrameOnly: false`, the JavaScript injection will occur on all frames (not just the main frame) if supported for the given platform. For example, if a page contains an iframe, the javascript will be injected into that iframe as well with this set to `false`. (Note this is not supported on Android.) There is also `injectedJavaScriptBeforeContentLoadedForMainFrameOnly` for injecting prior to content loading. Read more about this in the [Reference](./Reference.md#injectedjavascriptformainframeonly).
|
||||||
|
|
||||||
<img alt="screenshot of Github repo" width="200" src="https://user-images.githubusercontent.com/1479215/53609254-e5dc9c00-3b7a-11e9-9118-bc4e520ce6ca.png" />
|
<img alt="screenshot of Github repo" width="200" src="https://user-images.githubusercontent.com/1479215/53609254-e5dc9c00-3b7a-11e9-9118-bc4e520ce6ca.png" />
|
||||||
|
|
||||||
@ -354,10 +356,11 @@ export default class App extends Component {
|
|||||||
|
|
||||||
This runs the JavaScript in the `runFirst` string before the page is loaded. In this case, the value of `window.isNativeApp` will be set to true before the web code executes.
|
This runs the JavaScript in the `runFirst` string before the page is loaded. In this case, the value of `window.isNativeApp` will be set to true before the web code executes.
|
||||||
|
|
||||||
By setting `injectedJavaScriptBeforeContentLoadedForMainFrameOnly: false`, the JavaScript injection will occur on all frames (not just the top frame) if supported for the given platform. Howver, although support for `injectedJavaScriptBeforeContentLoadedForMainFrameOnly: false` has been implemented for iOS and macOS, [it is not clear](https://github.com/react-native-community/react-native-webview/pull/1119#issuecomment-600275750) that it is actually possible to inject JS into iframes at this point in the page lifecycle, and so relying on the expected behaviour of this prop when set to `false` is not recommended.
|
By setting `injectedJavaScriptBeforeContentLoadedForMainFrameOnly: false`, the JavaScript injection will occur on all frames (not just the top frame) if supported for the given platform. However, although support for `injectedJavaScriptBeforeContentLoadedForMainFrameOnly: false` has been implemented for iOS and macOS, [it is not clear](https://github.com/react-native-community/react-native-webview/pull/1119#issuecomment-600275750) that it is actually possible to inject JS into iframes at this point in the page lifecycle, and so relying on the expected behaviour of this prop when set to `false` is not recommended.
|
||||||
|
|
||||||
> On iOS, ~~`injectedJavaScriptBeforeContentLoaded` runs a method on WebView called `evaluateJavaScript:completionHandler:`~~ – this is no longer true as of version `8.2.0`. Instead, we use a `WKUserScript` with injection time `WKUserScriptInjectionTimeAtDocumentStart`. As a consequence, `injectedJavaScriptBeforeContentLoaded` no longer returns an evaluation value nor logs a warning to the console. In the unlikely event that your app depended upon this behaviour, please see migration steps [here](https://github.com/react-native-community/react-native-webview/pull/1119#issuecomment-574919464) to retain equivalent behaviour.
|
> On iOS, ~~`injectedJavaScriptBeforeContentLoaded` runs a method on WebView called `evaluateJavaScript:completionHandler:`~~ – this is no longer true as of version `8.2.0`. Instead, we use a `WKUserScript` with injection time `WKUserScriptInjectionTimeAtDocumentStart`. As a consequence, `injectedJavaScriptBeforeContentLoaded` no longer returns an evaluation value nor logs a warning to the console. In the unlikely event that your app depended upon this behaviour, please see migration steps [here](https://github.com/react-native-community/react-native-webview/pull/1119#issuecomment-574919464) to retain equivalent behaviour.
|
||||||
> On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
|
> On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
|
||||||
|
> Note on Android Compatibility: For applications targeting `Build.VERSION_CODES.N` or later, JavaScript state from an empty WebView is no longer persisted across navigations like `loadUrl(java.lang.String)`. For example, global variables and functions defined before calling `loadUrl(java.lang.String)` will not exist in the loaded page. Applications should use the Android Native API `addJavascriptInterface(Object, String)` instead to persist JavaScript objects across navigations.
|
||||||
|
|
||||||
#### The `injectJavaScript` method
|
#### The `injectJavaScript` method
|
||||||
|
|
||||||
@ -382,7 +385,7 @@ export default class App extends Component {
|
|||||||
return (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<View style={{ flex: 1 }}>
|
||||||
<WebView
|
<WebView
|
||||||
ref={r => (this.webref = r)}
|
ref={(r) => (this.webref = r)}
|
||||||
source={{
|
source={{
|
||||||
uri:
|
uri:
|
||||||
'https://github.com/react-native-community/react-native-webview',
|
'https://github.com/react-native-community/react-native-webview',
|
||||||
@ -435,7 +438,7 @@ export default class App extends Component {
|
|||||||
<View style={{ flex: 1 }}>
|
<View style={{ flex: 1 }}>
|
||||||
<WebView
|
<WebView
|
||||||
source={{ html }}
|
source={{ html }}
|
||||||
onMessage={event => {
|
onMessage={(event) => {
|
||||||
alert(event.nativeEvent.data);
|
alert(event.nativeEvent.data);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -471,7 +474,7 @@ This will set the header on the first load, but not on subsequent page navigatio
|
|||||||
In order to work around this, you can track the current URL, intercept new page loads, and navigate to them yourself ([original credit for this technique to Chirag Shah from Big Binary](https://blog.bigbinary.com/2016/07/26/passing-request-headers-on-each-webview-request-in-react-native.html)):
|
In order to work around this, you can track the current URL, intercept new page loads, and navigate to them yourself ([original credit for this technique to Chirag Shah from Big Binary](https://blog.bigbinary.com/2016/07/26/passing-request-headers-on-each-webview-request-in-react-native.html)):
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const CustomHeaderWebView = props => {
|
const CustomHeaderWebView = (props) => {
|
||||||
const { uri, onLoadStart, ...restProps } = props;
|
const { uri, onLoadStart, ...restProps } = props;
|
||||||
const [currentURI, setURI] = useState(props.source.uri);
|
const [currentURI, setURI] = useState(props.source.uri);
|
||||||
const newSource = { ...props.source, uri: currentURI };
|
const newSource = { ...props.source, uri: currentURI };
|
||||||
@ -480,7 +483,7 @@ const CustomHeaderWebView = props => {
|
|||||||
<WebView
|
<WebView
|
||||||
{...restProps}
|
{...restProps}
|
||||||
source={newSource}
|
source={newSource}
|
||||||
onShouldStartLoadWithRequest={request => {
|
onShouldStartLoadWithRequest={(request) => {
|
||||||
// If we're loading the current URI, allow it to load
|
// If we're loading the current URI, allow it to load
|
||||||
if (request.url === currentURI) return true;
|
if (request.url === currentURI) return true;
|
||||||
// We're loading a new URL -- change state first
|
// We're loading a new URL -- change state first
|
||||||
@ -539,6 +542,7 @@ const App = () => {
|
|||||||
Note that these cookies will only be sent on the first request unless you use the technique above for [setting custom headers on each page load](#Setting-Custom-Headers).
|
Note that these cookies will only be sent on the first request unless you use the technique above for [setting custom headers on each page load](#Setting-Custom-Headers).
|
||||||
|
|
||||||
### Hardware Silence Switch
|
### Hardware Silence Switch
|
||||||
|
|
||||||
There are some inconsistencies in how the hardware silence switch is handled between embedded `audio` and `video` elements and between iOS and Android platforms.
|
There are some inconsistencies in how the hardware silence switch is handled between embedded `audio` and `video` elements and between iOS and Android platforms.
|
||||||
|
|
||||||
Audio on `iOS` will be muted when the hardware silence switch is in the on position, unless the `ignoreSilentHardwareSwitch` parameter is set to true.
|
Audio on `iOS` will be muted when the hardware silence switch is in the on position, unless the `ignoreSilentHardwareSwitch` parameter is set to true.
|
||||||
|
@ -190,27 +190,25 @@ const INJECTED_JAVASCRIPT = `(function() {
|
|||||||
|
|
||||||
### `injectedJavaScriptForMainFrameOnly`
|
### `injectedJavaScriptForMainFrameOnly`
|
||||||
|
|
||||||
If `true` (default), loads the `injectedJavaScript` only into the main frame.
|
If `true` (default; mandatory for Android), loads the `injectedJavaScript` only into the main frame.
|
||||||
|
|
||||||
If `false`, loads it into all frames (e.g. iframes).
|
If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. iframes).
|
||||||
|
|
||||||
| Type | Required | Platform |
|
| Type | Required | Platform |
|
||||||
| ------ | -------- | -------- |
|
| ------ | -------- | -------- |
|
||||||
| bool | No | iOS, macOS |
|
| bool | No | iOS and macOS (only `true` supported for Android) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `injectedJavaScriptBeforeContentLoadedForMainFrameOnly`
|
### `injectedJavaScriptBeforeContentLoadedForMainFrameOnly`
|
||||||
|
|
||||||
If `true` (default), loads the `injectedJavaScriptBeforeContentLoaded` only into the main frame.
|
If `true` (default; mandatory for Android), loads the `injectedJavaScriptBeforeContentLoaded` only into the main frame.
|
||||||
|
|
||||||
If `false`, loads it into all frames (e.g. iframes).
|
If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. iframes).
|
||||||
|
|
||||||
Warning: although support for `injectedJavaScriptBeforeContentLoadedForMainFrameOnly: false` has been implemented for iOS and macOS, [it is not clear](https://github.com/react-native-community/react-native-webview/pull/1119#issuecomment-600275750) that it is actually possible to inject JS into iframes at this point in the page lifecycle, and so relying on the expected behaviour of this prop when set to `false` is not recommended.
|
|
||||||
|
|
||||||
| Type | Required | Platform |
|
| Type | Required | Platform |
|
||||||
| ------ | -------- | -------- |
|
| ------ | -------- | -------- |
|
||||||
| bool | No | iOS, macOS |
|
| bool | No | iOS and macOS (only `true` supported for Android) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@ package com.example;
|
|||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
|
||||||
import com.facebook.react.PackageList;
|
import com.facebook.react.PackageList;
|
||||||
import com.facebook.react.ReactApplication;
|
import com.facebook.react.ReactApplication;
|
||||||
import com.facebook.react.ReactNativeHost;
|
import com.facebook.react.ReactNativeHost;
|
||||||
@ -44,6 +47,10 @@ public class MainApplication extends Application implements ReactApplication {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
/* https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews */
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
|
WebView.setWebContentsDebuggingEnabled(true);
|
||||||
|
}
|
||||||
SoLoader.init(this, /* native exopackage */ false);
|
SoLoader.init(this, /* native exopackage */ false);
|
||||||
initializeFlipper(this); // Remove this line if you don't want Flipper enabled
|
initializeFlipper(this); // Remove this line if you don't want Flipper enabled
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,23 @@ import {Text, View, ScrollView} from 'react-native';
|
|||||||
|
|
||||||
import WebView from 'react-native-webview';
|
import WebView from 'react-native-webview';
|
||||||
|
|
||||||
// const HTML = `
|
const HTML = `
|
||||||
// <!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
// <html>
|
<html>
|
||||||
// <head>
|
<head>
|
||||||
// <meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
// <meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
// <title>iframe test</title>
|
<title>iframe test</title>
|
||||||
// </head>
|
</head>
|
||||||
// <body>
|
<body>
|
||||||
// <p style="">beforeContentLoaded on the top frame <span id="before_failed" style="display: inline-block;">failed</span><span id="before_succeeded" style="display: none;">succeeded</span>!</p>
|
<p style="">beforeContentLoaded on the top frame <span id="before_failed" style="display: inline-block;">failed</span><span id="before_succeeded" style="display: none;">succeeded</span>!</p>
|
||||||
// <p style="">afterContentLoaded on the top frame <span id="after_failed" style="display: inline-block;">failed</span><span id="after_succeeded" style="display: none;">succeeded</span>!</p>
|
<p style="">afterContentLoaded on the top frame <span id="after_failed" style="display: inline-block;">failed</span><span id="after_succeeded" style="display: none;">succeeded</span>!</p>
|
||||||
// <iframe src="https://birchlabs.co.uk/linguabrowse/infopages/obsol/iframe.html?v=1" name="iframe_0" style="width: 100%; height: 25px;"></iframe>
|
<iframe src="https://birchlabs.co.uk/linguabrowse/infopages/obsol/iframe.html?v=1" name="iframe_0" style="width: 100%; height: 25px;"></iframe>
|
||||||
// <iframe src="https://birchlabs.co.uk/linguabrowse/infopages/obsol/iframe2.html?v=1" name="iframe_1" style="width: 100%; height: 25px;"></iframe>
|
<iframe src="https://birchlabs.co.uk/linguabrowse/infopages/obsol/iframe2.html?v=1" name="iframe_1" style="width: 100%; height: 25px;"></iframe>
|
||||||
// <iframe src="https://www.ebay.co.uk" name="iframe_2" style="width: 100%; height: 25px;"></iframe>
|
<iframe src="https://www.ebay.co.uk" name="iframe_2" style="width: 100%; height: 25px;"></iframe>
|
||||||
// </body>
|
</body>
|
||||||
// </html>
|
</html>
|
||||||
// `;
|
`;
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
type State = {
|
type State = {
|
||||||
@ -35,11 +35,12 @@ export default class Injection extends Component<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<View style={{ }}>
|
<View style={{ }}>
|
||||||
<View style={{ height: 300 }}>
|
<View style={{ height: 400 }}>
|
||||||
<WebView
|
<WebView
|
||||||
/**
|
/**
|
||||||
* This HTML is a copy of a multi-frame JS injection test that I had lying around.
|
* This HTML is a copy of the hosted multi-frame JS injection test.
|
||||||
* @see https://birchlabs.co.uk/linguabrowse/infopages/obsol/iframeTest.html
|
* I have found that Android doesn't support beforeContentLoaded for a hosted HTML webpage, yet does for a static source.
|
||||||
|
* The cause of this is unresolved.
|
||||||
*/
|
*/
|
||||||
// source={{ html: HTML }}
|
// source={{ html: HTML }}
|
||||||
source={{ uri: "https://birchlabs.co.uk/linguabrowse/infopages/obsol/rnw_iframe_test.html" }}
|
source={{ uri: "https://birchlabs.co.uk/linguabrowse/infopages/obsol/rnw_iframe_test.html" }}
|
||||||
@ -50,10 +51,12 @@ export default class Injection extends Component<Props, State> {
|
|||||||
* JS injection user scripts, consistent with current behaviour. This is undesirable,
|
* JS injection user scripts, consistent with current behaviour. This is undesirable,
|
||||||
* so needs addressing in a follow-up PR. */
|
* so needs addressing in a follow-up PR. */
|
||||||
onMessage={() => {}}
|
onMessage={() => {}}
|
||||||
|
injectedJavaScriptBeforeContentLoadedForMainFrameOnly={false}
|
||||||
|
injectedJavaScriptForMainFrameOnly={false}
|
||||||
|
|
||||||
/* We set this property in each frame */
|
/* We set this property in each frame */
|
||||||
injectedJavaScriptBeforeContentLoaded={`
|
injectedJavaScriptBeforeContentLoaded={`
|
||||||
console.log("executing injectedJavaScriptBeforeContentLoaded...");
|
console.log("executing injectedJavaScriptBeforeContentLoaded... " + (new Date()).toString());
|
||||||
if(typeof window.top.injectedIframesBeforeContentLoaded === "undefined"){
|
if(typeof window.top.injectedIframesBeforeContentLoaded === "undefined"){
|
||||||
window.top.injectedIframesBeforeContentLoaded = [];
|
window.top.injectedIframesBeforeContentLoaded = [];
|
||||||
}
|
}
|
||||||
@ -85,11 +88,9 @@ export default class Injection extends Component<Props, State> {
|
|||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
|
|
||||||
injectedJavaScriptForMainFrameOnly={false}
|
|
||||||
|
|
||||||
/* We read the colourToUse property in each frame to recolour each frame */
|
/* We read the colourToUse property in each frame to recolour each frame */
|
||||||
injectedJavaScript={`
|
injectedJavaScript={`
|
||||||
console.log("executing injectedJavaScript...");
|
console.log("executing injectedJavaScript... " + (new Date()).toString());
|
||||||
if(typeof window.top.injectedIframesAfterContentLoaded === "undefined"){
|
if(typeof window.top.injectedIframesAfterContentLoaded === "undefined"){
|
||||||
window.top.injectedIframesAfterContentLoaded = [];
|
window.top.injectedIframesAfterContentLoaded = [];
|
||||||
}
|
}
|
||||||
@ -119,7 +120,7 @@ export default class Injection extends Component<Props, State> {
|
|||||||
// numberOfFramesAtAfterContentLoadedEle.id = "numberOfFramesAtAfterContentLoadedEle";
|
// numberOfFramesAtAfterContentLoadedEle.id = "numberOfFramesAtAfterContentLoadedEle";
|
||||||
|
|
||||||
var namedFramesAtBeforeContentLoadedEle = document.createElement('p');
|
var namedFramesAtBeforeContentLoadedEle = document.createElement('p');
|
||||||
namedFramesAtBeforeContentLoadedEle.textContent = "Names of iframes that called beforeContentLoaded: " + JSON.stringify(window.top.injectedIframesBeforeContentLoaded);
|
namedFramesAtBeforeContentLoadedEle.textContent = "Names of iframes that called beforeContentLoaded: " + JSON.stringify(window.top.injectedIframesBeforeContentLoaded || []);
|
||||||
namedFramesAtBeforeContentLoadedEle.id = "namedFramesAtBeforeContentLoadedEle";
|
namedFramesAtBeforeContentLoadedEle.id = "namedFramesAtBeforeContentLoadedEle";
|
||||||
|
|
||||||
var namedFramesAtAfterContentLoadedEle = document.createElement('p');
|
var namedFramesAtAfterContentLoadedEle = document.createElement('p');
|
||||||
@ -147,8 +148,8 @@ export default class Injection extends Component<Props, State> {
|
|||||||
<Text>✅ If the main frame becomes orange, then top-frame injection both beforeContentLoaded and afterContentLoaded is supported.</Text>
|
<Text>✅ If the main frame becomes orange, then top-frame injection both beforeContentLoaded and afterContentLoaded is supported.</Text>
|
||||||
<Text>✅ If iframe_0, and iframe_1 become orange, then multi-frame injection beforeContentLoaded and afterContentLoaded is supported.</Text>
|
<Text>✅ If iframe_0, and iframe_1 become orange, then multi-frame injection beforeContentLoaded and afterContentLoaded is supported.</Text>
|
||||||
<Text>✅ If the two texts say "beforeContentLoaded on the top frame succeeded!" and "afterContentLoaded on the top frame succeeded!", then both injection times are supported at least on the main frame.</Text>
|
<Text>✅ If the two texts say "beforeContentLoaded on the top frame succeeded!" and "afterContentLoaded on the top frame succeeded!", then both injection times are supported at least on the main frame.</Text>
|
||||||
<Text>⚠️ If either of the two iframes become coloured cyan, then for that given frame, JS injection succeeded after the content loaded, but didn't occur before the content loaded - please note that for iframes, this may not be a test failure, as it is not clear whether we would expect iframes to support an injection time of beforeContentLoaded anyway.</Text>
|
<Text>❌ If either of the two iframes become coloured cyan, then for that given frame, JS injection succeeded after the content loaded, but didn't occur before the content loaded.</Text>
|
||||||
<Text>⚠️ If "Names of iframes that called beforeContentLoaded: " is [], then see above.</Text>
|
<Text>❌ If "Names of iframes that called beforeContentLoaded: " is [], then see above.</Text>
|
||||||
<Text>❌ If "Names of iframes that called afterContentLoaded: " is [], then afterContentLoaded is not supported in iframes.</Text>
|
<Text>❌ If "Names of iframes that called afterContentLoaded: " is [], then afterContentLoaded is not supported in iframes.</Text>
|
||||||
<Text>❌ If the main frame becomes coloured cyan, then JS injection succeeded after the content loaded, but didn't occur before the content loaded.</Text>
|
<Text>❌ If the main frame becomes coloured cyan, then JS injection succeeded after the content loaded, but didn't occur before the content loaded.</Text>
|
||||||
<Text>❌ If the text "beforeContentLoaded on the top frame failed" remains unchanged, then JS injection has failed on the main frame before the content loaded.</Text>
|
<Text>❌ If the text "beforeContentLoaded on the top frame failed" remains unchanged, then JS injection has failed on the main frame before the content loaded.</Text>
|
||||||
|
@ -240,6 +240,8 @@ export interface CommonNativeWebViewProps extends ViewProps {
|
|||||||
incognito?: boolean;
|
incognito?: boolean;
|
||||||
injectedJavaScript?: string;
|
injectedJavaScript?: string;
|
||||||
injectedJavaScriptBeforeContentLoaded?: string;
|
injectedJavaScriptBeforeContentLoaded?: string;
|
||||||
|
injectedJavaScriptForMainFrameOnly?: boolean;
|
||||||
|
injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean;
|
||||||
javaScriptCanOpenWindowsAutomatically?: boolean;
|
javaScriptCanOpenWindowsAutomatically?: boolean;
|
||||||
mediaPlaybackRequiresUserAction?: boolean;
|
mediaPlaybackRequiresUserAction?: boolean;
|
||||||
messagingEnabled: boolean;
|
messagingEnabled: boolean;
|
||||||
@ -915,6 +917,18 @@ export interface WebViewSharedProps extends ViewProps {
|
|||||||
*/
|
*/
|
||||||
injectedJavaScriptBeforeContentLoaded?: string;
|
injectedJavaScriptBeforeContentLoaded?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `true` (default; mandatory for Android), loads the `injectedJavaScript` only into the main frame.
|
||||||
|
* If `false` (only supported on iOS and macOS), loads it into all frames (e.g. iframes).
|
||||||
|
*/
|
||||||
|
injectedJavaScriptForMainFrameOnly?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `true` (default; mandatory for Android), loads the `injectedJavaScriptBeforeContentLoaded` only into the main frame.
|
||||||
|
* If `false` (only supported on iOS and macOS), loads it into all frames (e.g. iframes).
|
||||||
|
*/
|
||||||
|
injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boolean value that determines whether a horizontal scroll indicator is
|
* Boolean value that determines whether a horizontal scroll indicator is
|
||||||
* shown in the `WebView`. The default value is `true`.
|
* shown in the `WebView`. The default value is `true`.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user