feat(iOS): new prop injectedJavaScriptBeforeContentLoaded (#1038)
* Run the injectedJavaScript on DocumentStart for iOS * Add new prop injectedJavaScriptBeforeContentLoaded Update types Update docs * Self review
This commit is contained in:
parent
5ddd6c6fc2
commit
604495e399
|
@ -336,6 +336,39 @@ _Under the hood_
|
|||
> On iOS, `injectedJavaScript` runs a method on WebView called `evaluateJavaScript:completionHandler:`
|
||||
> On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
|
||||
|
||||
|
||||
#### The `injectedJavaScriptBeforeContentLoaded` prop
|
||||
|
||||
This is a script that runs **before** the web page loads for the first time. It only runs once, even if the page is reloaded or navigated away. This is useful if you want to inject anything into the window, localstorage, or document prior to the web code executing.
|
||||
|
||||
```jsx
|
||||
import React, { Component } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { WebView } from 'react-native-webview';
|
||||
|
||||
export default class App extends Component {
|
||||
render() {
|
||||
const runFirst = `
|
||||
window.isNativeApp = true;
|
||||
true; // note: this is required, or you'll sometimes get silent failures
|
||||
`;
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<WebView
|
||||
source={{
|
||||
uri:
|
||||
'https://github.com/react-native-community/react-native-webview',
|
||||
}}
|
||||
injectedJavaScriptBeforeContentLoaded={runFirst}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
#### The `injectJavaScript` method
|
||||
|
||||
While convenient, the downside to the previously mentioned `injectedJavaScript` prop is that it only runs once. That's why we also expose a method on the webview ref called `injectJavaScript` (note the slightly different name!).
|
||||
|
|
|
@ -7,6 +7,7 @@ This document lays out the current public properties and methods for the React N
|
|||
- [`source`](Reference.md#source)
|
||||
- [`automaticallyAdjustContentInsets`](Reference.md#automaticallyadjustcontentinsets)
|
||||
- [`injectedJavaScript`](Reference.md#injectedjavascript)
|
||||
- [`injectedJavaScriptBeforeContentLoaded`](Reference.md#injectedJavaScriptBeforeContentLoaded)
|
||||
- [`mediaPlaybackRequiresUserAction`](Reference.md#mediaplaybackrequiresuseraction)
|
||||
- [`nativeConfig`](Reference.md#nativeconfig)
|
||||
- [`onError`](Reference.md#onerror)
|
||||
|
@ -144,6 +145,35 @@ const INJECTED_JAVASCRIPT = `(function() {
|
|||
|
||||
---
|
||||
|
||||
### `injectedJavaScriptBeforeContentLoaded`
|
||||
|
||||
Set this to provide JavaScript that will be injected into the web page after the document element is created, but before any other content is loaded. Make sure the string evaluates to a valid type (`true` works) and doesn't otherwise throw an exception.
|
||||
On iOS, see [WKUserScriptInjectionTimeAtDocumentStart](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime/wkuserscriptinjectiontimeatdocumentstart?language=objc)
|
||||
|
||||
| Type | Required |
|
||||
| ------ | -------- |
|
||||
| string | No |
|
||||
|
||||
To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
|
||||
|
||||
Example:
|
||||
|
||||
Post message a JSON object of `window.location` to be handled by [`onMessage`](Reference.md#onmessage)
|
||||
|
||||
```jsx
|
||||
const INJECTED_JAVASCRIPT = `(function() {
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(window.location));
|
||||
})();`;
|
||||
|
||||
<WebView
|
||||
source={{ uri: 'https://facebook.github.io/react-native' }}
|
||||
injectedJavaScriptBeforeContentLoaded={INJECTED_JAVASCRIPT}
|
||||
onMessage={this.onMessage}
|
||||
/>;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `mediaPlaybackRequiresUserAction`
|
||||
|
||||
Boolean that determines whether HTML5 audio and video requires the user to tap them before they start playing. The default value is `true`. (Android API minimum version 17).
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
@property (nonatomic, copy) NSDictionary * _Nullable source;
|
||||
@property (nonatomic, assign) BOOL messagingEnabled;
|
||||
@property (nonatomic, copy) NSString * _Nullable injectedJavaScript;
|
||||
@property (nonatomic, copy) NSString * _Nullable injectedJavaScriptBeforeContentLoaded;
|
||||
@property (nonatomic, assign) BOOL scrollEnabled;
|
||||
@property (nonatomic, assign) BOOL sharedCookiesEnabled;
|
||||
@property (nonatomic, assign) BOOL pagingEnabled;
|
||||
|
|
|
@ -165,6 +165,12 @@ static NSDictionary* customCertificatesForHost;
|
|||
|
||||
WKUserScript *script = [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
|
||||
[wkWebViewConfig.userContentController addUserScript:script];
|
||||
|
||||
if (_injectedJavaScriptBeforeContentLoaded) {
|
||||
// If user has provided an injectedJavascript prop, execute it at the start of the document
|
||||
WKUserScript *injectedScript = [[WKUserScript alloc] initWithSource:_injectedJavaScriptBeforeContentLoaded injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
|
||||
[wkWebViewConfig.userContentController addUserScript:injectedScript];
|
||||
}
|
||||
}
|
||||
|
||||
wkWebViewConfig.allowsInlineMediaPlayback = _allowsInlineMediaPlayback;
|
||||
|
@ -949,19 +955,19 @@ static NSDictionary* customCertificatesForHost;
|
|||
* Called when the navigation is complete.
|
||||
* @see https://fburl.com/rtys6jlb
|
||||
*/
|
||||
- (void) webView:(WKWebView *)webView
|
||||
- (void)webView:(WKWebView *)webView
|
||||
didFinishNavigation:(WKNavigation *)navigation
|
||||
{
|
||||
if (_injectedJavaScript) {
|
||||
[self evaluateJS: _injectedJavaScript thenCall: ^(NSString *jsEvaluationValue) {
|
||||
NSMutableDictionary *event = [self baseEvent];
|
||||
event[@"jsEvaluationValue"] = jsEvaluationValue;
|
||||
if (_injectedJavaScript) {
|
||||
[self evaluateJS: _injectedJavaScript thenCall: ^(NSString *jsEvaluationValue) {
|
||||
NSMutableDictionary *event = [self baseEvent];
|
||||
event[@"jsEvaluationValue"] = jsEvaluationValue;
|
||||
|
||||
if (self.onLoadingFinish) {
|
||||
self.onLoadingFinish(event);
|
||||
}
|
||||
}];
|
||||
} else if (_onLoadingFinish) {
|
||||
if (self.onLoadingFinish) {
|
||||
self.onLoadingFinish(event);
|
||||
}
|
||||
}];
|
||||
} else if (_onLoadingFinish) {
|
||||
_onLoadingFinish([self baseEvent]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ RCT_EXPORT_VIEW_PROPERTY(onHttpError, RCTDirectEventBlock)
|
|||
RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onContentProcessDidTerminate, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptBeforeContentLoaded, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(javaScriptEnabled, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(mediaPlaybackRequiresUserAction, BOOL)
|
||||
|
|
|
@ -20,7 +20,7 @@ type AndroidWebViewCommands = 'clearHistory' | 'clearCache' | 'clearFormData';
|
|||
|
||||
interface RNCWebViewUIManager<Commands extends string> extends UIManagerStatic {
|
||||
getViewManagerConfig: (
|
||||
name: string,
|
||||
name: string,
|
||||
) => {
|
||||
Commands: {[key in Commands]: number};
|
||||
};
|
||||
|
@ -216,6 +216,7 @@ export interface CommonNativeWebViewProps extends ViewProps {
|
|||
cacheEnabled?: boolean;
|
||||
incognito?: boolean;
|
||||
injectedJavaScript?: string;
|
||||
injectedJavaScriptBeforeContentLoaded?: string;
|
||||
mediaPlaybackRequiresUserAction?: boolean;
|
||||
messagingEnabled: boolean;
|
||||
onScroll?: (event: NativeScrollEvent) => void;
|
||||
|
@ -501,7 +502,7 @@ export interface AndroidWebViewProps extends WebViewSharedProps {
|
|||
*/
|
||||
geolocationEnabled?: boolean;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Boolean that sets whether JavaScript running in the context of a file
|
||||
* scheme URL should be allowed to access content from other file scheme URLs.
|
||||
|
@ -685,6 +686,12 @@ export interface WebViewSharedProps extends ViewProps {
|
|||
*/
|
||||
injectedJavaScript?: string;
|
||||
|
||||
/**
|
||||
* Set this to provide JavaScript that will be injected into the web page
|
||||
* once the webview is initialized but before the view loads any content.
|
||||
*/
|
||||
injectedJavaScriptBeforeContentLoaded?: string;
|
||||
|
||||
/**
|
||||
* Boolean value that determines whether a horizontal scroll indicator is
|
||||
* shown in the `WebView`. The default value is `true`.
|
||||
|
|
Loading…
Reference in New Issue