feat(webview props) onLoadProgresss property (#53)

* Added the onLoadProgress property to the iOS wkwebview and Android webview
This commit is contained in:
黎明 2018-10-17 21:08:52 +08:00 committed by Thibault Malbranche
parent 525ebfa06e
commit b5aaf5c800
9 changed files with 150 additions and 30 deletions

View File

@ -37,6 +37,7 @@ class MyWebComponent extends Component {
<WebView
source={{ uri: 'https://infinite.red/react-native' }}
style={{ marginTop: 20 }}
onLoadProgress={e=>console.log(e.nativeEvent.progress)}
/>
);
}

View File

@ -54,6 +54,7 @@ import com.reactnativecommunity.webview.events.TopLoadingErrorEvent;
import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
import com.reactnativecommunity.webview.events.TopLoadingStartEvent;
import com.reactnativecommunity.webview.events.TopMessageEvent;
import com.reactnativecommunity.webview.events.TopLoadingProgressEvent;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
@ -74,7 +75,8 @@ import org.json.JSONObject;
* {@link WebView} instances could emit following direct events:
* - topLoadingFinish
* - topLoadingStart
* - topLoadingError
* - topLoadingStart
* - topLoadingProgress
*
* Each event will carry the following properties:
* - target - view's react tag
@ -409,6 +411,23 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
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);
@ -623,6 +642,13 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
view.setWebViewClient(new RNCWebViewClient());
}
@Override
public Map getExportedCustomDirectEventTypeConstants() {
MapBuilder.Builder builder = MapBuilder.builder();
builder.put("topLoadingProgress", MapBuilder.of("registrationName", "onLoadingProgress"));
return builder.build();
}
@Override
public @Nullable Map<String, Integer> getCommandsMap() {
return MapBuilder.of(

View File

@ -0,0 +1,36 @@
package com.reactnativecommunity.webview.events;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
public class TopLoadingProgressEvent extends Event<TopLoadingProgressEvent> {
public static final String EVENT_NAME = "topLoadingProgress";
private WritableMap mEventData;
public TopLoadingProgressEvent(int viewId, WritableMap eventData) {
super(viewId);
mEventData = eventData;
}
@Override
public String getEventName() {
return EVENT_NAME;
}
@Override
public boolean canCoalesce() {
return false;
}
@Override
public short getCoalescingKey() {
// All events for a given view can be coalesced.
return 0;
}
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
}
}

View File

@ -16,6 +16,7 @@ This document lays out the current public properties and methods for the React N
- [`onLoad`](Reference.md#onload)
- [`onLoadEnd`](Reference.md#onloadend)
- [`onLoadStart`](Reference.md#onloadstart)
- [`onLoadProgress`](Reference.md#onloadprogress)
- [`onMessage`](Reference.md#onmessage)
- [`onNavigationStateChange`](Reference.md#onnavigationstatechange)
- [`originWhitelist`](Reference.md#originwhitelist)
@ -44,11 +45,11 @@ This document lays out the current public properties and methods for the React N
## Methods Index
* [`extraNativeComponentConfig`](Reference.md#extranativecomponentconfig)
* [`goForward`](Reference.md#goforward)
* [`goBack`](Reference.md#goback)
* [`reload`](Reference.md#reload)
* [`stopLoading`](Reference.md#stoploading)
- [`extraNativeComponentConfig`](Reference.md#extranativecomponentconfig)
- [`goForward`](Reference.md#goforward)
- [`goBack`](Reference.md#goback)
- [`reload`](Reference.md#reload)
- [`stopLoading`](Reference.md#stoploading)
---
@ -64,17 +65,17 @@ The object passed to `source` can have either of the following shapes:
**Load uri**
* `uri` (string) - The URI to load in the `WebView`. Can be a local or remote file.
* `method` (string) - The HTTP Method to use. Defaults to GET if not specified. On Android, the only supported methods are GET and POST.
* `headers` (object) - Additional HTTP headers to send with the request. On Android, this can only be used with GET requests.
* `body` (string) - The HTTP body to send with the request. This must be a valid UTF-8 string, and will be sent exactly as specified, with no additional encoding (e.g. URL-escaping or base64) applied. On Android, this can only be used with POST requests.
- `uri` (string) - The URI to load in the `WebView`. Can be a local or remote file.
- `method` (string) - The HTTP Method to use. Defaults to GET if not specified. On Android, the only supported methods are GET and POST.
- `headers` (object) - Additional HTTP headers to send with the request. On Android, this can only be used with GET requests.
- `body` (string) - The HTTP body to send with the request. This must be a valid UTF-8 string, and will be sent exactly as specified, with no additional encoding (e.g. URL-escaping or base64) applied. On Android, this can only be used with POST requests.
**Static HTML**
_Note that using static HTML requires the WebView property [originWhiteList](Reference.md#originWhiteList) to `['*']`._
* `html` (string) - A static HTML page to display in the WebView.
* `baseUrl` (string) - The base URL to be used for any relative links in the HTML.
- `html` (string) - A static HTML page to display in the WebView.
- `baseUrl` (string) - The base URL to be used for any relative links in the HTML.
| Type | Required |
| ------ | -------- |
@ -128,9 +129,9 @@ Override the native component used to render the WebView. Enables a custom nativ
The `nativeConfig` prop expects an object with the following keys:
* `component` (any)
* `props` (object)
* `viewManager` (object)
- `component` (any)
- `props` (object)
- `viewManager` (object)
| Type | Required |
| ------ | -------- |
@ -178,6 +179,21 @@ Function that is invoked when the `WebView` starts loading.
---
### `onLoadProgress`
Function that is invoked when the `WebView` is loading.
> **_Note_**
>
> On iOS, when useWebKit=false, this prop will not work.
> On android, You can't get the url property, meaning that `event.nativeEvent.url` will be null.
| Type | Required |
| -------- | -------- |
| function | No |
---
### `onMessage`
A function that is invoked when the webview calls `window.postMessage`. Setting this property will inject a `postMessage` global into your webview, but will still call pre-existing values of `postMessage`.
@ -266,8 +282,8 @@ Boolean value that forces the `WebView` to show the loading view on the first lo
A floating-point number that determines how quickly the scroll view decelerates after the user lifts their finger. You may also use the string shortcuts `"normal"` and `"fast"` which match the underlying iOS settings for `UIScrollViewDecelerationRateNormal` and `UIScrollViewDecelerationRateFast` respectively:
* normal: 0.998
* fast: 0.99 (the default for iOS web view)
- normal: 0.998
- fast: 0.99 (the default for iOS web view)
| Type | Required | Platform |
| ------ | -------- | -------- |
@ -301,9 +317,9 @@ Specifies the mixed content mode. i.e WebView will allow a secure origin to load
Possible values for `mixedContentMode` are:
* `never` (default) - WebView will not allow a secure origin to load content from an insecure origin.
* `always` - WebView will allow a secure origin to load content from any other origin, even if that origin is insecure.
* `compatibility` - WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
- `never` (default) - WebView will not allow a secure origin to load content from an insecure origin.
- `always` - WebView will allow a secure origin to load content from any other origin, even if that origin is insecure.
- `compatibility` - WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
| Type | Required | Platform |
| ------ | -------- | -------- |
@ -373,18 +389,18 @@ You can provide one type or an array of many types.
Possible values for `dataDetectorTypes` are:
* `phoneNumber`
* `link`
* `address`
* `calendarEvent`
* `none`
* `all`
- `phoneNumber`
- `link`
- `address`
- `calendarEvent`
- `none`
- `all`
With the [new WebKit](Reference.md#usewebkit) implementation, we have three new values:
* `trackingNumber`
* `flightNumber`
* `lookupSuggestion`
- `trackingNumber`
- `flightNumber`
- `lookupSuggestion`
| Type | Required | Platform |
| ---------------- | -------- | -------- |

View File

@ -15,6 +15,7 @@ static NSString *const MessageHanderName = @"ReactNative";
@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
@property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
@property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
@property (nonatomic, copy) RCTDirectEventBlock onLoadingProgress;
@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
@property (nonatomic, copy) RCTDirectEventBlock onMessage;
@property (nonatomic, copy) WKWebView *webView;
@ -27,7 +28,9 @@ static NSString *const MessageHanderName = @"ReactNative";
- (void)dealloc
{
if(_webView){
[_webView removeObserver:self forKeyPath:@"estimatedProgress"];
}
}
/**
@ -85,6 +88,7 @@ static NSString *const MessageHanderName = @"ReactNative";
_webView.navigationDelegate = self;
_webView.scrollView.scrollEnabled = _scrollEnabled;
_webView.scrollView.bounces = _bounces;
[_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
@ -100,6 +104,18 @@ static NSString *const MessageHanderName = @"ReactNative";
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
if(_onLoadingProgress){
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary:@{@"progress":[NSNumber numberWithDouble:self.webView.estimatedProgress]}];
_onLoadingProgress(event);
}
}else{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
_savedBackgroundColor = backgroundColor;

View File

@ -33,6 +33,7 @@ RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadingProgress, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL)

View File

@ -35,6 +35,7 @@ import type {
WebViewNavigationEvent,
WebViewSharedProps,
WebViewSource,
WebViewProgressEvent,
} from './WebViewTypes';
const resolveAssetSource = Image.resolveAssetSource;
@ -152,6 +153,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
onLoadingStart={this.onLoadingStart}
onLoadingFinish={this.onLoadingFinish}
onLoadingError={this.onLoadingError}
onLoadingProgress={this.onLoadingProgress}
testID={this.props.testID}
geolocationEnabled={this.props.geolocationEnabled}
mediaPlaybackRequiresUserAction={
@ -280,6 +282,11 @@ class WebView extends React.Component<WebViewSharedProps, State> {
const { onMessage } = this.props;
onMessage && onMessage(event);
};
onLoadingProgress = (event: WebViewProgressEvent) => {
const { onLoadProgress} = this.props;
onLoadProgress && onLoadProgress(event);
}
}
const RNCWebView = requireNativeComponent('RNCWebView');

View File

@ -34,6 +34,7 @@ import type {
WebViewNavigationEvent,
WebViewSharedProps,
WebViewSource,
WebViewProgressEvent,
} from './WebViewTypes';
const resolveAssetSource = Image.resolveAssetSource;
@ -263,6 +264,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
onLoadingStart={this._onLoadingStart}
onLoadingFinish={this._onLoadingFinish}
onLoadingError={this._onLoadingError}
onLoadingProgress={this._onLoadingProgress}
messagingEnabled={messagingEnabled}
onMessage={this._onMessage}
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
@ -420,6 +422,11 @@ class WebView extends React.Component<WebViewSharedProps, State> {
onMessage && onMessage(event);
};
_onLoadingProgress = (event: WebViewProgressEvent) => {
const {onLoadProgress} = this.props;
onLoadProgress && onLoadProgress(event);
}
componentDidUpdate(prevProps: WebViewSharedProps) {
if (!(prevProps.useWebKit && this.props.useWebKit)) {
return;

View File

@ -25,6 +25,11 @@ export type WebViewNativeEvent = $ReadOnly<{|
canGoForward: boolean,
|}>;
export type WebViewProgressEvent = $ReadOnly<{|
...WebViewNativeEvent,
progress: number,
|}>
export type WebViewNavigation = $ReadOnly<{|
...WebViewNativeEvent,
navigationType:
@ -365,6 +370,11 @@ export type WebViewSharedProps = $ReadOnly<{|
*/
onMessage?: (event: WebViewMessageEvent) => mixed,
/**
* Function that is invoked when the `WebView` is loading.
*/
onLoadProgress?: (event: WebViewProgressEvent) => mixed,
/**
* Boolean value that forces the `WebView` to show the loading view
* on the first load.