Merge branch 'master' into @salakar/bugfix/androidx-rn60

This commit is contained in:
Thibault Malbranche 2019-05-17 00:27:44 +02:00 committed by GitHub
commit eed7cc9e52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 322 additions and 78 deletions

View File

@ -6,12 +6,17 @@ import android.app.DownloadManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.webkit.ConsoleMessage;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
@ -24,7 +29,11 @@ import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import com.facebook.react.views.scroll.ScrollEvent;
import com.facebook.react.views.scroll.ScrollEventType;
import com.facebook.react.views.scroll.OnScrollDispatchHelper;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactContext;
@ -106,6 +115,9 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
protected static final String BLANK_URL = "about:blank";
protected WebViewConfig mWebViewConfig;
protected RNCWebChromeClient mWebChromeClient = null;
protected boolean mAllowsFullscreenVideo = false;
public RNCWebViewManager() {
mWebViewConfig = new WebViewConfig() {
public void configWebView(WebView webView) {
@ -137,59 +149,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected WebView createViewInstance(ThemedReactContext reactContext) {
RNCWebView webView = createRNCWebViewInstance(reactContext);
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onConsoleMessage(ConsoleMessage message) {
if (ReactBuildConfig.DEBUG) {
return super.onConsoleMessage(message);
}
// Ignore console logs in non debug builds.
return true;
}
@Override
public void onProgressChanged(WebView webView, int newProgress) {
super.onProgressChanged(webView, newProgress);
WritableMap event = Arguments.createMap();
event.putDouble("target", webView.getId());
event.putString("title", webView.getTitle());
event.putBoolean("canGoBack", webView.canGoBack());
event.putBoolean("canGoForward", webView.canGoForward());
event.putDouble("progress", (float) newProgress / 100);
dispatchEvent(
webView,
new TopLoadingProgressEvent(
webView.getId(),
event));
}
@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
}
protected void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType) {
getModule(reactContext).startPhotoPickerIntent(filePathCallback, acceptType);
}
protected void openFileChooser(ValueCallback<Uri> filePathCallback) {
getModule(reactContext).startPhotoPickerIntent(filePathCallback, "");
}
protected void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType, String capture) {
getModule(reactContext).startPhotoPickerIntent(filePathCallback, acceptType);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
String[] acceptTypes = fileChooserParams.getAcceptTypes();
boolean allowMultiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE;
Intent intent = fileChooserParams.createIntent();
return getModule(reactContext).startPhotoPickerIntent(filePathCallback, intent, acceptTypes, allowMultiple);
}
});
setupWebChromeClient(reactContext, webView);
reactContext.addLifecycleEventListener(webView);
mWebViewConfig.configWebView(webView);
WebSettings settings = webView.getSettings();
@ -210,7 +170,6 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
setGeolocationEnabled(webView, false);
if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
@ -290,6 +249,8 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
public void setHardwareAccelerationDisabled(WebView view, boolean disabled) {
if (disabled) {
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
} else {
view.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
@ -452,6 +413,14 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
}
}
@ReactProp(name = "allowsFullscreenVideo")
public void setAllowsFullscreenVideo(
WebView view,
@Nullable Boolean allowsFullscreenVideo) {
mAllowsFullscreenVideo = allowsFullscreenVideo != null && allowsFullscreenVideo;
setupWebChromeClient((ReactContext)view.getContext(), view);
}
@ReactProp(name = "allowFileAccess")
public void setAllowFileAccess(
WebView view,
@ -480,6 +449,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
}
export.put(TopLoadingProgressEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingProgress"));
export.put(TopShouldStartLoadWithRequestEvent.EVENT_NAME, MapBuilder.of("registrationName", "onShouldStartLoadWithRequest"));
export.put(ScrollEventType.SCROLL.getJSEventName(), MapBuilder.of("registrationName", "onScroll"));
return export;
}
@ -552,10 +522,67 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
((RNCWebView) webView).cleanupCallbacksAndDestroy();
}
public RNCWebViewModule getModule(ReactContext reactContext) {
public static RNCWebViewModule getModule(ReactContext reactContext) {
return reactContext.getNativeModule(RNCWebViewModule.class);
}
protected void setupWebChromeClient(ReactContext reactContext, WebView webView) {
if (mAllowsFullscreenVideo) {
mWebChromeClient = new RNCWebChromeClient(reactContext, webView) {
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
if (mVideoView != null) {
callback.onCustomViewHidden();
return;
}
mVideoView = view;
mCustomViewCallback = callback;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mVideoView.setSystemUiVisibility(FULLSCREEN_SYSTEM_UI_VISIBILITY);
mReactContext.getCurrentActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
mVideoView.setBackgroundColor(Color.BLACK);
getRootView().addView(mVideoView, FULLSCREEN_LAYOUT_PARAMS);
mWebView.setVisibility(View.GONE);
mReactContext.addLifecycleEventListener(this);
}
@Override
public void onHideCustomView() {
if (mVideoView == null) {
return;
}
mVideoView.setVisibility(View.GONE);
getRootView().removeView(mVideoView);
mCustomViewCallback.onCustomViewHidden();
mVideoView = null;
mCustomViewCallback = null;
mWebView.setVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mReactContext.getCurrentActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
mReactContext.removeLifecycleEventListener(this);
}
};
webView.setWebChromeClient(mWebChromeClient);
} else {
if (mWebChromeClient != null) {
mWebChromeClient.onHideCustomView();
}
mWebChromeClient = new RNCWebChromeClient(reactContext, webView);
webView.setWebChromeClient(mWebChromeClient);
}
}
protected static class RNCWebViewClient extends WebViewClient {
protected boolean mLastLoadFailed = false;
@ -653,6 +680,99 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
}
}
protected static class RNCWebChromeClient extends WebChromeClient implements LifecycleEventListener {
protected static final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER);
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
protected static final int FULLSCREEN_SYSTEM_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_IMMERSIVE |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
protected ReactContext mReactContext;
protected View mWebView;
protected View mVideoView;
protected WebChromeClient.CustomViewCallback mCustomViewCallback;
public RNCWebChromeClient(ReactContext reactContext, WebView webView) {
this.mReactContext = reactContext;
this.mWebView = webView;
}
@Override
public boolean onConsoleMessage(ConsoleMessage message) {
if (ReactBuildConfig.DEBUG) {
return super.onConsoleMessage(message);
}
// Ignore console logs in non debug builds.
return true;
}
@Override
public void onProgressChanged(WebView webView, int newProgress) {
super.onProgressChanged(webView, newProgress);
WritableMap event = Arguments.createMap();
event.putDouble("target", webView.getId());
event.putString("title", webView.getTitle());
event.putBoolean("canGoBack", webView.canGoBack());
event.putBoolean("canGoForward", webView.canGoForward());
event.putDouble("progress", (float) newProgress / 100);
dispatchEvent(
webView,
new TopLoadingProgressEvent(
webView.getId(),
event));
}
@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
}
protected void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType) {
getModule(mReactContext).startPhotoPickerIntent(filePathCallback, acceptType);
}
protected void openFileChooser(ValueCallback<Uri> filePathCallback) {
getModule(mReactContext).startPhotoPickerIntent(filePathCallback, "");
}
protected void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType, String capture) {
getModule(mReactContext).startPhotoPickerIntent(filePathCallback, acceptType);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
String[] acceptTypes = fileChooserParams.getAcceptTypes();
boolean allowMultiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE;
Intent intent = fileChooserParams.createIntent();
return getModule(mReactContext).startPhotoPickerIntent(filePathCallback, intent, acceptTypes, allowMultiple);
}
@Override
public void onHostResume() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && mVideoView != null && mVideoView.getSystemUiVisibility() != FULLSCREEN_SYSTEM_UI_VISIBILITY) {
mVideoView.setSystemUiVisibility(FULLSCREEN_SYSTEM_UI_VISIBILITY);
}
}
@Override
public void onHostPause() { }
@Override
public void onHostDestroy() { }
protected ViewGroup getRootView() {
return (ViewGroup) mReactContext.getCurrentActivity().findViewById(android.R.id.content);
}
}
/**
* Subclass of {@link WebView} that implements {@link LifecycleEventListener} interface in order
* to call {@link WebView#destroy} on activity destroy event and also to clear the client
@ -664,6 +784,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
protected @Nullable
RNCWebViewClient mRNCWebViewClient;
protected boolean sendContentSizeChangeEvents = false;
private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
/**
* WebView must be created with an context of the current activity
@ -770,6 +891,26 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
dispatchEvent(this, new TopMessageEvent(this.getId(), message));
}
protected void onScrollChanged(int x, int y, int oldX, int oldY) {
super.onScrollChanged(x, y, oldX, oldY);
if (mOnScrollDispatchHelper.onScrollChanged(x, y)) {
ScrollEvent event = ScrollEvent.obtain(
this.getId(),
ScrollEventType.SCROLL,
x,
y,
mOnScrollDispatchHelper.getXFlingVelocity(),
mOnScrollDispatchHelper.getYFlingVelocity(),
this.computeHorizontalScrollRange(),
this.computeVerticalScrollRange(),
this.getWidth(),
this.getHeight());
dispatchEvent(this, event);
}
}
protected void cleanupCallbacksAndDestroy() {
setWebViewClient(null);
destroy();

View File

@ -14,7 +14,6 @@ _This guide is currently a work in progress._
- [Add support for File Download](Guide.md#add-support-for-file-download)
- [Communicating between JS and Native](Guide.md#communicating-between-js-and-native)
### Basic inline HTML
The simplest way to use the WebView is to simply pipe in the HTML you want to display. Note that setting an `html` source requires the [originWhiteList](Reference.md#originWhiteList) property to be set to `['*']`.
@ -48,9 +47,7 @@ import { WebView } from 'react-native-webview';
class MyWeb extends Component {
render() {
return (
<WebView
source={{uri: 'https://facebook.github.io/react-native/'}}
/>
<WebView source={{ uri: 'https://facebook.github.io/react-native/' }} />
);
}
}
@ -71,7 +68,7 @@ class MyWeb extends Component {
return (
<WebView
ref={ref => (this.webview = ref)}
source={{uri: 'https://facebook.github.io/react-native/'}}
source={{ uri: 'https://facebook.github.io/react-native/' }}
onNavigationStateChange={this.handleWebViewNavigationStateChange}
/>
);
@ -87,7 +84,7 @@ class MyWeb extends Component {
// canGoForward?: boolean;
// }
const { url } = newNavState;
if (!url) return
if (!url) return;
// handle certain doctypes
if (url.includes('.pdf')) {
@ -112,10 +109,48 @@ class MyWeb extends Component {
const redirectTo = 'window.location = "' + newURL + '"';
this.webview.injectJavaScript(redirectTo);
}
}
};
}
```
#### Intercepting hash URL changes
While `onNavigationStateChange` will trigger on URL changes, it does not trigger when only the hash URL ("anchor") changes, e.g. from `https://example.com/users#list` to `https://example.com/users#help`.
You can inject some JavaScript to wrap the history functions in order to intercept these hash URL changes.
```jsx
<WebView
source={{ uri: someURI }}
injectedJavaScript={`
(function() {
function wrap(fn) {
return function wrapper() {
var res = fn.apply(this, arguments);
window.ReactNativeWebView.postMessage('navigationStateChange');
return res;
}
}
history.pushState = wrap(history.pushState);
history.replaceState = wrap(history.replaceState);
window.addEventListener('popstate', function() {
window.ReactNativeWebView.postMessage('navigationStateChange');
});
})();
true;
`}
onMessage={({ nativeEvent: state }) => {
if (state.data === 'navigationStateChange') {
// Navigation state updated, can check state.canGoBack, etc.
}
}}
/>
```
Thanks to [Janic Duplessis](https://github.com/react-native-community/react-native-webview/issues/24#issuecomment-483956651) for this workaround.
### Add support for File Upload
##### iOS
@ -123,18 +158,21 @@ class MyWeb extends Component {
For iOS, all you need to do is specify the permissions in your `ios/[project]/Info.plist` file:
Photo capture:
```
<key>NSCameraUsageDescription</key>
<string>Take pictures for certain activities</string>
```
Gallery selection:
```
<key>NSPhotoLibraryUsageDescription</key>
<string>Select pictures for certain activities</string>
```
Video recording:
```
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for recording videos</string>
@ -143,6 +181,7 @@ Video recording:
##### Android
Add permission in AndroidManifest.xml:
```xml
<manifest ...>
......
@ -173,7 +212,7 @@ WebView.isFileUploadSupported().then(res => {
### Multiple Files Upload
You can control __single__ or __multiple__ file selection by specifing the [`multiple`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple) attribute on your `input` element:
You can control **single** or **multiple** file selection by specifing the [`multiple`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple) attribute on your `input` element:
```
// multiple file selection
@ -190,6 +229,7 @@ You can control __single__ or __multiple__ file selection by specifing the [`mul
For iOS, all you need to do is specify the permissions in your `ios/[project]/Info.plist` file:
Save to gallery:
```
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Save pictures for certain activities.</string>
@ -225,9 +265,9 @@ To accomplish this, React Native WebView exposes three different options:
This is a script that runs immediately after the web page loads for the first time. It only runs once, even if the page is reloaded or navigated away.
```jsx
import React, { Component } from "react";
import { View } from "react-native";
import { WebView } from "react-native-webview";
import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';
export default class App extends Component {
render() {
@ -241,7 +281,7 @@ export default class App extends Component {
<WebView
source={{
uri:
"https://github.com/react-native-community/react-native-webview"
'https://github.com/react-native-community/react-native-webview',
}}
injectedJavaScript={runFirst}
/>
@ -255,7 +295,7 @@ This runs the JavaScript in the `runFirst` string once the page is loaded. In th
<img alt="screenshot of Github repo" width="200" src="https://user-images.githubusercontent.com/1479215/53609254-e5dc9c00-3b7a-11e9-9118-bc4e520ce6ca.png" />
*Under the hood*
_Under the hood_
> On iOS, `injectedJavaScript` runs a method on WKWebView called `evaluateJavaScript:completionHandler:`
> On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
@ -265,9 +305,9 @@ This runs the JavaScript in the `runFirst` string once the page is loaded. In th
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!).
```jsx
import React, { Component } from "react";
import { View } from "react-native";
import { WebView } from "react-native-webview";
import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';
export default class App extends Component {
render() {
@ -286,7 +326,7 @@ export default class App extends Component {
ref={r => (this.webref = r)}
source={{
uri:
"https://github.com/react-native-community/react-native-webview"
'https://github.com/react-native-community/react-native-webview',
}}
/>
</View>
@ -299,7 +339,7 @@ After 3 seconds, this code turns the background blue:
<img alt="Screenshot of app showing injected javascript" width="200" src="https://user-images.githubusercontent.com/1479215/53670433-93a98280-3c2f-11e9-85a5-0e4650993817.png" />
*Under the hood*
_Under the hood_
> On iOS, `injectJavaScript` calls WKWebView's `evaluateJS:andThen:`
> On Android, `injectJavaScript` calls Android WebView's `evaluateJavascriptWithFallback` method
@ -313,9 +353,9 @@ You _must_ set `onMessage` or the `window.ReactNativeWebView.postMessage` method
`window.ReactNativeWebView.postMessage` only accepts one argument which must be a string.
```jsx
import React, { Component } from "react";
import { View } from "react-native";
import { WebView } from "react-native-webview";
import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';
export default class App extends Component {
render() {
@ -349,4 +389,3 @@ export default class App extends Component {
This code will result in this alert:
<img alt="Alert showing communication from web page to React Native" width="200" src="https://user-images.githubusercontent.com/1479215/53671269-7e822300-3c32-11e9-9937-7ddc34ba8af3.png" />

View File

@ -30,6 +30,7 @@ This document lays out the current public properties and methods for the React N
- [`mixedContentMode`](Reference.md#mixedcontentmode)
- [`thirdPartyCookiesEnabled`](Reference.md#thirdpartycookiesenabled)
- [`userAgent`](Reference.md#useragent)
- [`allowsFullscreenVideo`](Reference.md#allowsfullscreenvideo)
- [`allowsInlineMediaPlayback`](Reference.md#allowsinlinemediaplayback)
- [`bounces`](Reference.md#bounces)
- [`overScrollMode`](Reference.md#overscrollmode)
@ -114,6 +115,22 @@ Set this to provide JavaScript that will be injected into the web page when the
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' }}
injectedJavaScript={INJECTED_JAVASCRIPT}
onMessage={this.onMessage}
/>
```
---
### `mediaPlaybackRequiresUserAction`
@ -369,6 +386,8 @@ title
url
```
Note that this method will not be invoked on hash URL changes (e.g. from `https://example.com/users#list` to `https://example.com/users#help`). There is a workaround for this that is described [in the Guide](Guide.md#intercepting-hash-url-changes).
---
### `originWhitelist`
@ -589,6 +608,16 @@ Sets the user-agent for the `WebView`. This will only work for iOS if you are us
---
### `allowsFullscreenVideo`
Boolean that determines whether videos are allowed to be played in fullscreen. The default value is `false`.
| Type | Required | Platform |
| ---- | -------- | -------- |
| bool | No | Android |
---
### `allowsInlineMediaPlayback`
Boolean that determines whether HTML5 videos play inline or use the native full-screen controller. The default value is `false`.

View File

@ -34,6 +34,7 @@ static NSURLCredential* clientAuthenticationCredential;
@property (nonatomic, copy) RCTDirectEventBlock onLoadingProgress;
@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
@property (nonatomic, copy) RCTDirectEventBlock onMessage;
@property (nonatomic, copy) RCTDirectEventBlock onScroll;
@property (nonatomic, copy) WKWebView *webView;
@end
@ -509,6 +510,30 @@ static NSURLCredential* clientAuthenticationCredential;
if (!_scrollEnabled) {
scrollView.bounds = _webView.bounds;
}
else if (_onScroll != nil) {
NSDictionary *event = @{
@"contentOffset": @{
@"x": @(scrollView.contentOffset.x),
@"y": @(scrollView.contentOffset.y)
},
@"contentInset": @{
@"top": @(scrollView.contentInset.top),
@"left": @(scrollView.contentInset.left),
@"bottom": @(scrollView.contentInset.bottom),
@"right": @(scrollView.contentInset.right)
},
@"contentSize": @{
@"width": @(scrollView.contentSize.width),
@"height": @(scrollView.contentSize.height)
},
@"layoutMeasurement": @{
@"width": @(scrollView.frame.size.width),
@"height": @(scrollView.frame.size.height)
},
@"zoomScale": @(scrollView.zoomScale ?: 1),
};
_onScroll(event);
}
}
- (void)setDirectionalLockEnabled:(BOOL)directionalLockEnabled

View File

@ -56,6 +56,7 @@ RCT_EXPORT_VIEW_PROPERTY(allowsLinkPreview, BOOL)
*/
RCT_EXPORT_VIEW_PROPERTY(messagingEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onMessage, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
RCT_EXPORT_METHOD(postMessage:(nonnull NSNumber *)reactTag message:(NSString *)message)
{

View File

@ -8,7 +8,7 @@
"Thibault Malbranche <malbranche.thibault@gmail.com>"
],
"license": "MIT",
"version": "5.8.1",
"version": "5.8.2",
"homepage": "https://github.com/react-native-community/react-native-webview#readme",
"scripts": {
"ci": "CI=true && yarn lint && yarn test",

View File

@ -48,6 +48,7 @@ class WebView extends React.Component<AndroidWebViewProps, State> {
javaScriptEnabled: true,
thirdPartyCookiesEnabled: true,
scalesPageToFit: true,
allowsFullscreenVideo: false,
allowFileAccess: false,
saveFormDataDisabled: false,
cacheEnabled: true,

View File

@ -382,6 +382,7 @@ class WebView extends React.Component<IOSWebViewProps, State> {
onLoadingProgress={this.onLoadingProgress}
onLoadingStart={this.onLoadingStart}
onMessage={this.onMessage}
onScroll={this.props.onScroll}
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
ref={this.webViewRef}
scalesPageToFit={scalesPageToFit}

View File

@ -7,6 +7,7 @@ import {
NativeMethodsMixin,
Constructor,
UIManagerStatic,
NativeScrollEvent,
} from 'react-native';
export interface WebViewCommands {
@ -213,6 +214,7 @@ export interface CommonNativeWebViewProps extends ViewProps {
injectedJavaScript?: string;
mediaPlaybackRequiresUserAction?: boolean;
messagingEnabled: boolean;
onScroll?: (event: NativeScrollEvent) => void;
onLoadingError: (event: WebViewErrorEvent) => void;
onLoadingFinish: (event: WebViewNavigationEvent) => void;
onLoadingProgress: (event: WebViewProgressEvent) => void;
@ -542,6 +544,11 @@ export interface WebViewSharedProps extends ViewProps {
*/
renderLoading?: () => ReactElement;
/**
* Function that is invoked when the `WebView` scrolls.
*/
onScroll?: (event: NativeScrollEvent) => void;
/**
* Function that is invoked when the `WebView` has finished loading.
*/