浏览代码

feat(webview props) onLoadProgresss property (#53)

* Added the onLoadProgress property to the iOS wkwebview and Android webview
黎明 5 年前
父节点
当前提交
b5aaf5c800

+ 1
- 0
README.md 查看文件

37
       <WebView
37
       <WebView
38
         source={{ uri: 'https://infinite.red/react-native' }}
38
         source={{ uri: 'https://infinite.red/react-native' }}
39
         style={{ marginTop: 20 }}
39
         style={{ marginTop: 20 }}
40
+        onLoadProgress={e=>console.log(e.nativeEvent.progress)}
40
       />
41
       />
41
     );
42
     );
42
   }
43
   }

+ 27
- 1
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java 查看文件

54
 import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
54
 import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
55
 import com.reactnativecommunity.webview.events.TopLoadingStartEvent;
55
 import com.reactnativecommunity.webview.events.TopLoadingStartEvent;
56
 import com.reactnativecommunity.webview.events.TopMessageEvent;
56
 import com.reactnativecommunity.webview.events.TopMessageEvent;
57
+import com.reactnativecommunity.webview.events.TopLoadingProgressEvent;
57
 import java.io.UnsupportedEncodingException;
58
 import java.io.UnsupportedEncodingException;
58
 import java.util.ArrayList;
59
 import java.util.ArrayList;
59
 import java.util.HashMap;
60
 import java.util.HashMap;
74
  * {@link WebView} instances could emit following direct events:
75
  * {@link WebView} instances could emit following direct events:
75
  *  - topLoadingFinish
76
  *  - topLoadingFinish
76
  *  - topLoadingStart
77
  *  - topLoadingStart
77
- *  - topLoadingError
78
+ *  - topLoadingStart
79
+ *  - topLoadingProgress
78
  *
80
  *
79
  * Each event will carry the following properties:
81
  * Each event will carry the following properties:
80
  *  - target - view's react tag
82
  *  - target - view's react tag
409
         return true;
411
         return true;
410
       }
412
       }
411
 
413
 
414
+
415
+    @Override
416
+    public void onProgressChanged(WebView webView, int newProgress) {
417
+        super.onProgressChanged(webView, newProgress);
418
+        WritableMap event = Arguments.createMap();
419
+        event.putDouble("target", webView.getId());
420
+        event.putString("title", webView.getTitle());
421
+        event.putBoolean("canGoBack", webView.canGoBack());
422
+        event.putBoolean("canGoForward", webView.canGoForward());
423
+        event.putDouble("progress", (float)newProgress/100);
424
+        dispatchEvent(
425
+                  webView,
426
+                  new TopLoadingProgressEvent(
427
+                      webView.getId(),
428
+                      event));
429
+    }
430
+
412
       @Override
431
       @Override
413
       public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
432
       public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
414
         callback.invoke(origin, true, false);
433
         callback.invoke(origin, true, false);
623
     view.setWebViewClient(new RNCWebViewClient());
642
     view.setWebViewClient(new RNCWebViewClient());
624
   }
643
   }
625
 
644
 
645
+  @Override
646
+  public Map getExportedCustomDirectEventTypeConstants() {
647
+    MapBuilder.Builder builder = MapBuilder.builder();
648
+    builder.put("topLoadingProgress", MapBuilder.of("registrationName", "onLoadingProgress"));
649
+    return builder.build();
650
+  }
651
+
626
   @Override
652
   @Override
627
   public @Nullable Map<String, Integer> getCommandsMap() {
653
   public @Nullable Map<String, Integer> getCommandsMap() {
628
     return MapBuilder.of(
654
     return MapBuilder.of(

+ 36
- 0
android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingProgressEvent.java 查看文件

1
+package com.reactnativecommunity.webview.events;
2
+
3
+import com.facebook.react.bridge.WritableMap;
4
+import com.facebook.react.uimanager.events.Event;
5
+import com.facebook.react.uimanager.events.RCTEventEmitter;
6
+
7
+public class TopLoadingProgressEvent extends Event<TopLoadingProgressEvent> {
8
+    public static final String EVENT_NAME = "topLoadingProgress";
9
+    private WritableMap mEventData;
10
+
11
+    public TopLoadingProgressEvent(int viewId, WritableMap eventData) {
12
+        super(viewId);
13
+        mEventData = eventData;
14
+    }
15
+
16
+    @Override
17
+    public String getEventName() {
18
+        return EVENT_NAME;
19
+    }
20
+
21
+    @Override
22
+    public boolean canCoalesce() {
23
+        return false;
24
+    }
25
+
26
+    @Override
27
+    public short getCoalescingKey() {
28
+        // All events for a given view can be coalesced.
29
+        return 0;
30
+    }
31
+
32
+    @Override
33
+    public void dispatch(RCTEventEmitter rctEventEmitter) {
34
+        rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
35
+    }
36
+}

+ 44
- 28
docs/Reference.md 查看文件

16
 - [`onLoad`](Reference.md#onload)
16
 - [`onLoad`](Reference.md#onload)
17
 - [`onLoadEnd`](Reference.md#onloadend)
17
 - [`onLoadEnd`](Reference.md#onloadend)
18
 - [`onLoadStart`](Reference.md#onloadstart)
18
 - [`onLoadStart`](Reference.md#onloadstart)
19
+- [`onLoadProgress`](Reference.md#onloadprogress)
19
 - [`onMessage`](Reference.md#onmessage)
20
 - [`onMessage`](Reference.md#onmessage)
20
 - [`onNavigationStateChange`](Reference.md#onnavigationstatechange)
21
 - [`onNavigationStateChange`](Reference.md#onnavigationstatechange)
21
 - [`originWhitelist`](Reference.md#originwhitelist)
22
 - [`originWhitelist`](Reference.md#originwhitelist)
44
 
45
 
45
 ## Methods Index
46
 ## Methods Index
46
 
47
 
47
-* [`extraNativeComponentConfig`](Reference.md#extranativecomponentconfig)
48
-* [`goForward`](Reference.md#goforward)
49
-* [`goBack`](Reference.md#goback)
50
-* [`reload`](Reference.md#reload)
51
-* [`stopLoading`](Reference.md#stoploading)
48
+- [`extraNativeComponentConfig`](Reference.md#extranativecomponentconfig)
49
+- [`goForward`](Reference.md#goforward)
50
+- [`goBack`](Reference.md#goback)
51
+- [`reload`](Reference.md#reload)
52
+- [`stopLoading`](Reference.md#stoploading)
52
 
53
 
53
 ---
54
 ---
54
 
55
 
64
 
65
 
65
 **Load uri**
66
 **Load uri**
66
 
67
 
67
-* `uri` (string) - The URI to load in the `WebView`. Can be a local or remote file.
68
-* `method` (string) - The HTTP Method to use. Defaults to GET if not specified. On Android, the only supported methods are GET and POST.
69
-* `headers` (object) - Additional HTTP headers to send with the request. On Android, this can only be used with GET requests.
70
-* `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.
68
+- `uri` (string) - The URI to load in the `WebView`. Can be a local or remote file.
69
+- `method` (string) - The HTTP Method to use. Defaults to GET if not specified. On Android, the only supported methods are GET and POST.
70
+- `headers` (object) - Additional HTTP headers to send with the request. On Android, this can only be used with GET requests.
71
+- `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.
71
 
72
 
72
 **Static HTML**
73
 **Static HTML**
73
 
74
 
74
 _Note that using static HTML requires the WebView property [originWhiteList](Reference.md#originWhiteList) to `['*']`._
75
 _Note that using static HTML requires the WebView property [originWhiteList](Reference.md#originWhiteList) to `['*']`._
75
 
76
 
76
-* `html` (string) - A static HTML page to display in the WebView.
77
-* `baseUrl` (string) - The base URL to be used for any relative links in the HTML.
77
+- `html` (string) - A static HTML page to display in the WebView.
78
+- `baseUrl` (string) - The base URL to be used for any relative links in the HTML.
78
 
79
 
79
 | Type   | Required |
80
 | Type   | Required |
80
 | ------ | -------- |
81
 | ------ | -------- |
128
 
129
 
129
 The `nativeConfig` prop expects an object with the following keys:
130
 The `nativeConfig` prop expects an object with the following keys:
130
 
131
 
131
-* `component` (any)
132
-* `props` (object)
133
-* `viewManager` (object)
132
+- `component` (any)
133
+- `props` (object)
134
+- `viewManager` (object)
134
 
135
 
135
 | Type   | Required |
136
 | Type   | Required |
136
 | ------ | -------- |
137
 | ------ | -------- |
178
 
179
 
179
 ---
180
 ---
180
 
181
 
182
+### `onLoadProgress`
183
+
184
+Function that is invoked when the `WebView` is loading.
185
+
186
+> **_Note_**
187
+>
188
+> On iOS, when useWebKit=false, this prop will not work.
189
+> On android, You can't get the url property, meaning that `event.nativeEvent.url` will be null.
190
+
191
+| Type     | Required |
192
+| -------- | -------- |
193
+| function | No       |
194
+
195
+---
196
+
181
 ### `onMessage`
197
 ### `onMessage`
182
 
198
 
183
 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`.
199
 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
 
282
 
267
 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:
283
 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:
268
 
284
 
269
-* normal: 0.998
270
-* fast: 0.99 (the default for iOS web view)
285
+- normal: 0.998
286
+- fast: 0.99 (the default for iOS web view)
271
 
287
 
272
 | Type   | Required | Platform |
288
 | Type   | Required | Platform |
273
 | ------ | -------- | -------- |
289
 | ------ | -------- | -------- |
301
 
317
 
302
 Possible values for `mixedContentMode` are:
318
 Possible values for `mixedContentMode` are:
303
 
319
 
304
-* `never` (default) - WebView will not allow a secure origin to load content from an insecure origin.
305
-* `always` - WebView will allow a secure origin to load content from any other origin, even if that origin is insecure.
306
-* `compatibility` - WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
320
+- `never` (default) - WebView will not allow a secure origin to load content from an insecure origin.
321
+- `always` - WebView will allow a secure origin to load content from any other origin, even if that origin is insecure.
322
+- `compatibility` - WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
307
 
323
 
308
 | Type   | Required | Platform |
324
 | Type   | Required | Platform |
309
 | ------ | -------- | -------- |
325
 | ------ | -------- | -------- |
373
 
389
 
374
 Possible values for `dataDetectorTypes` are:
390
 Possible values for `dataDetectorTypes` are:
375
 
391
 
376
-* `phoneNumber`
377
-* `link`
378
-* `address`
379
-* `calendarEvent`
380
-* `none`
381
-* `all`
392
+- `phoneNumber`
393
+- `link`
394
+- `address`
395
+- `calendarEvent`
396
+- `none`
397
+- `all`
382
 
398
 
383
 With the [new WebKit](Reference.md#usewebkit) implementation, we have three new values:
399
 With the [new WebKit](Reference.md#usewebkit) implementation, we have three new values:
384
 
400
 
385
-* `trackingNumber`
386
-* `flightNumber`
387
-* `lookupSuggestion`
401
+- `trackingNumber`
402
+- `flightNumber`
403
+- `lookupSuggestion`
388
 
404
 
389
 | Type             | Required | Platform |
405
 | Type             | Required | Platform |
390
 | ---------------- | -------- | -------- |
406
 | ---------------- | -------- | -------- |

+ 17
- 1
ios/RNCWKWebView.m 查看文件

15
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
15
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
16
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
16
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
17
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
17
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
18
+@property (nonatomic, copy) RCTDirectEventBlock onLoadingProgress;
18
 @property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
19
 @property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
19
 @property (nonatomic, copy) RCTDirectEventBlock onMessage;
20
 @property (nonatomic, copy) RCTDirectEventBlock onMessage;
20
 @property (nonatomic, copy) WKWebView *webView;
21
 @property (nonatomic, copy) WKWebView *webView;
27
 
28
 
28
 - (void)dealloc
29
 - (void)dealloc
29
 {
30
 {
30
-
31
+    if(_webView){
32
+        [_webView removeObserver:self forKeyPath:@"estimatedProgress"];
33
+    }
31
 }
34
 }
32
 
35
 
33
 /**
36
 /**
85
     _webView.navigationDelegate = self;
88
     _webView.navigationDelegate = self;
86
     _webView.scrollView.scrollEnabled = _scrollEnabled;
89
     _webView.scrollView.scrollEnabled = _scrollEnabled;
87
     _webView.scrollView.bounces = _bounces;
90
     _webView.scrollView.bounces = _bounces;
91
+    [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
88
 
92
 
89
 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
93
 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
90
     if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
94
     if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
100
   }
104
   }
101
 }
105
 }
102
 
106
 
107
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
108
+    if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
109
+        if(_onLoadingProgress){
110
+             NSMutableDictionary<NSString *, id> *event = [self baseEvent];
111
+            [event addEntriesFromDictionary:@{@"progress":[NSNumber numberWithDouble:self.webView.estimatedProgress]}];
112
+            _onLoadingProgress(event);
113
+        }
114
+    }else{
115
+        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
116
+    }
117
+}
118
+
103
 - (void)setBackgroundColor:(UIColor *)backgroundColor
119
 - (void)setBackgroundColor:(UIColor *)backgroundColor
104
 {
120
 {
105
   _savedBackgroundColor = backgroundColor;
121
   _savedBackgroundColor = backgroundColor;

+ 1
- 0
ios/RNCWKWebViewManager.m 查看文件

33
 RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
33
 RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
34
 RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
34
 RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
35
 RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
35
 RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
36
+RCT_EXPORT_VIEW_PROPERTY(onLoadingProgress, RCTDirectEventBlock)
36
 RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
37
 RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
37
 RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
38
 RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
38
 RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL)
39
 RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL)

+ 7
- 0
js/WebView.android.js 查看文件

35
   WebViewNavigationEvent,
35
   WebViewNavigationEvent,
36
   WebViewSharedProps,
36
   WebViewSharedProps,
37
   WebViewSource,
37
   WebViewSource,
38
+  WebViewProgressEvent,
38
 } from './WebViewTypes';
39
 } from './WebViewTypes';
39
 
40
 
40
 const resolveAssetSource = Image.resolveAssetSource;
41
 const resolveAssetSource = Image.resolveAssetSource;
152
         onLoadingStart={this.onLoadingStart}
153
         onLoadingStart={this.onLoadingStart}
153
         onLoadingFinish={this.onLoadingFinish}
154
         onLoadingFinish={this.onLoadingFinish}
154
         onLoadingError={this.onLoadingError}
155
         onLoadingError={this.onLoadingError}
156
+        onLoadingProgress={this.onLoadingProgress}
155
         testID={this.props.testID}
157
         testID={this.props.testID}
156
         geolocationEnabled={this.props.geolocationEnabled}
158
         geolocationEnabled={this.props.geolocationEnabled}
157
         mediaPlaybackRequiresUserAction={
159
         mediaPlaybackRequiresUserAction={
280
     const { onMessage } = this.props;
282
     const { onMessage } = this.props;
281
     onMessage && onMessage(event);
283
     onMessage && onMessage(event);
282
   };
284
   };
285
+  
286
+  onLoadingProgress = (event: WebViewProgressEvent) => {
287
+    const { onLoadProgress} = this.props;
288
+    onLoadProgress && onLoadProgress(event);
289
+  }
283
 }
290
 }
284
 
291
 
285
 const RNCWebView = requireNativeComponent('RNCWebView');
292
 const RNCWebView = requireNativeComponent('RNCWebView');

+ 7
- 0
js/WebView.ios.js 查看文件

34
   WebViewNavigationEvent,
34
   WebViewNavigationEvent,
35
   WebViewSharedProps,
35
   WebViewSharedProps,
36
   WebViewSource,
36
   WebViewSource,
37
+  WebViewProgressEvent,
37
 } from './WebViewTypes';
38
 } from './WebViewTypes';
38
 
39
 
39
 const resolveAssetSource = Image.resolveAssetSource;
40
 const resolveAssetSource = Image.resolveAssetSource;
263
         onLoadingStart={this._onLoadingStart}
264
         onLoadingStart={this._onLoadingStart}
264
         onLoadingFinish={this._onLoadingFinish}
265
         onLoadingFinish={this._onLoadingFinish}
265
         onLoadingError={this._onLoadingError}
266
         onLoadingError={this._onLoadingError}
267
+        onLoadingProgress={this._onLoadingProgress}
266
         messagingEnabled={messagingEnabled}
268
         messagingEnabled={messagingEnabled}
267
         onMessage={this._onMessage}
269
         onMessage={this._onMessage}
268
         onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
270
         onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
420
     onMessage && onMessage(event);
422
     onMessage && onMessage(event);
421
   };
423
   };
422
 
424
 
425
+  _onLoadingProgress = (event: WebViewProgressEvent) => {
426
+    const {onLoadProgress} = this.props;
427
+    onLoadProgress && onLoadProgress(event);
428
+  }
429
+
423
   componentDidUpdate(prevProps: WebViewSharedProps) {
430
   componentDidUpdate(prevProps: WebViewSharedProps) {
424
     if (!(prevProps.useWebKit && this.props.useWebKit)) {
431
     if (!(prevProps.useWebKit && this.props.useWebKit)) {
425
       return;
432
       return;

+ 10
- 0
js/WebViewTypes.js 查看文件

25
   canGoForward: boolean,
25
   canGoForward: boolean,
26
 |}>;
26
 |}>;
27
 
27
 
28
+export type WebViewProgressEvent = $ReadOnly<{|
29
+    ...WebViewNativeEvent,
30
+    progress: number,
31
+|}>
32
+
28
 export type WebViewNavigation = $ReadOnly<{|
33
 export type WebViewNavigation = $ReadOnly<{|
29
   ...WebViewNativeEvent,
34
   ...WebViewNativeEvent,
30
   navigationType:
35
   navigationType:
365
    */
370
    */
366
   onMessage?: (event: WebViewMessageEvent) => mixed,
371
   onMessage?: (event: WebViewMessageEvent) => mixed,
367
 
372
 
373
+  /**
374
+   * Function that is invoked when the `WebView` is loading.
375
+   */
376
+  onLoadProgress?: (event: WebViewProgressEvent) => mixed,
377
+
368
   /**
378
   /**
369
    * Boolean value that forces the `WebView` to show the loading view
379
    * Boolean value that forces the `WebView` to show the loading view
370
    * on the first load.
380
    * on the first load.