feat(new prop): onHttpError callback (#885)
This commit is contained in:
parent
33f1ee384f
commit
552472c414
|
@ -32,6 +32,7 @@ import android.webkit.URLUtil;
|
|||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
@ -58,6 +59,7 @@ import com.facebook.react.uimanager.events.ContentSizeChangeEvent;
|
|||
import com.facebook.react.uimanager.events.Event;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.reactnativecommunity.webview.events.TopLoadingErrorEvent;
|
||||
import com.reactnativecommunity.webview.events.TopHttpErrorEvent;
|
||||
import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
|
||||
import com.reactnativecommunity.webview.events.TopLoadingProgressEvent;
|
||||
import com.reactnativecommunity.webview.events.TopLoadingStartEvent;
|
||||
|
@ -512,6 +514,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.getJSEventName(ScrollEventType.SCROLL), MapBuilder.of("registrationName", "onScroll"));
|
||||
export.put(TopHttpErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onHttpError"));
|
||||
return export;
|
||||
}
|
||||
|
||||
|
@ -725,6 +728,25 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
|
|||
new TopLoadingErrorEvent(webView.getId(), eventData));
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@Override
|
||||
public void onReceivedHttpError(
|
||||
WebView webView,
|
||||
WebResourceRequest request,
|
||||
WebResourceResponse errorResponse) {
|
||||
super.onReceivedHttpError(webView, request, errorResponse);
|
||||
|
||||
if (request.isForMainFrame()) {
|
||||
WritableMap eventData = createWebViewEvent(webView, request.getUrl().toString());
|
||||
eventData.putInt("statusCode", errorResponse.getStatusCode());
|
||||
eventData.putString("description", errorResponse.getReasonPhrase());
|
||||
|
||||
dispatchEvent(
|
||||
webView,
|
||||
new TopHttpErrorEvent(webView.getId(), eventData));
|
||||
}
|
||||
}
|
||||
|
||||
protected void emitFinishEvent(WebView webView, String url) {
|
||||
dispatchEvent(
|
||||
webView,
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
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
|
||||
|
||||
/**
|
||||
* Event emitted when a http error is received from the server.
|
||||
*/
|
||||
class TopHttpErrorEvent(viewId: Int, private val mEventData: WritableMap) :
|
||||
Event<TopHttpErrorEvent>(viewId) {
|
||||
companion object {
|
||||
const val EVENT_NAME = "topHttpError"
|
||||
}
|
||||
|
||||
override fun getEventName(): String = EVENT_NAME
|
||||
|
||||
override fun canCoalesce(): Boolean = false
|
||||
|
||||
override fun getCoalescingKey(): Short = 0
|
||||
|
||||
override fun dispatch(rctEventEmitter: RCTEventEmitter) =
|
||||
rctEventEmitter.receiveEvent(viewTag, eventName, mEventData)
|
||||
|
||||
}
|
|
@ -14,6 +14,7 @@ This document lays out the current public properties and methods for the React N
|
|||
- [`onLoadEnd`](Reference.md#onloadend)
|
||||
- [`onLoadStart`](Reference.md#onloadstart)
|
||||
- [`onLoadProgress`](Reference.md#onloadprogress)
|
||||
- [`onHttpError`](Reference.md#onhttperror)
|
||||
- [`onMessage`](Reference.md#onmessage)
|
||||
- [`onNavigationStateChange`](Reference.md#onnavigationstatechange)
|
||||
- [`originWhitelist`](Reference.md#originwhitelist)
|
||||
|
@ -342,6 +343,46 @@ url
|
|||
|
||||
---
|
||||
|
||||
### `onHttpError`
|
||||
|
||||
Function that is invoked when the `WebView` receives an http error.
|
||||
> **_Note_**
|
||||
> Android API minimum level 23.
|
||||
|
||||
| Type | Required |
|
||||
| -------- | -------- |
|
||||
| function | No |
|
||||
|
||||
Example:
|
||||
|
||||
```jsx
|
||||
<WebView
|
||||
source={{ uri: 'https://facebook.github.io/react-native' }}
|
||||
onHttpError={syntheticEvent => {
|
||||
const { nativeEvent } = syntheticEvent;
|
||||
console.warn('WebView received error status code: ', nativeEvent.statusCode);
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
Function passed to `onHttpError` is called with a SyntheticEvent wrapping a nativeEvent with these properties:
|
||||
|
||||
```
|
||||
canGoBack
|
||||
canGoForward
|
||||
description
|
||||
loading
|
||||
statusCode
|
||||
target
|
||||
title
|
||||
url
|
||||
```
|
||||
|
||||
> **_Note_**
|
||||
> Description is only used on Android
|
||||
|
||||
---
|
||||
|
||||
### `onMessage`
|
||||
|
||||
Function that is invoked when the webview calls `window.ReactNativeWebView.postMessage`. Setting this property will inject this global into your webview.
|
||||
|
|
|
@ -33,6 +33,7 @@ static NSURLCredential* clientAuthenticationCredential;
|
|||
@property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onLoadingProgress;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onHttpError;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onMessage;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onScroll;
|
||||
@property (nonatomic, copy) WKWebView *webView;
|
||||
|
@ -806,6 +807,34 @@ static NSURLCredential* clientAuthenticationCredential;
|
|||
decisionHandler(WKNavigationResponsePolicyAllow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides whether to allow or cancel a navigation after its response is known.
|
||||
* @see https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview?language=objc
|
||||
*/
|
||||
- (void) webView:(WKWebView *)webView
|
||||
decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
|
||||
decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
|
||||
{
|
||||
if (_onHttpError && navigationResponse.forMainFrame) {
|
||||
if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
|
||||
NSInteger statusCode = response.statusCode;
|
||||
|
||||
if (statusCode >= 400) {
|
||||
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
|
||||
[event addEntriesFromDictionary: @{
|
||||
@"url": response.URL.absoluteString,
|
||||
@"statusCode": @(statusCode)
|
||||
}];
|
||||
|
||||
_onHttpError(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decisionHandler(WKNavigationResponsePolicyAllow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an error occurs while the web view is loading content.
|
||||
* @see https://fburl.com/km6vqenw
|
||||
|
|
|
@ -47,6 +47,7 @@ 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(onHttpError, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(javaScriptEnabled, BOOL)
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
} from './WebViewShared';
|
||||
import {
|
||||
WebViewErrorEvent,
|
||||
WebViewHttpErrorEvent,
|
||||
WebViewMessageEvent,
|
||||
WebViewNavigationEvent,
|
||||
WebViewProgressEvent,
|
||||
|
@ -178,6 +179,13 @@ class WebView extends React.Component<AndroidWebViewProps, State> {
|
|||
});
|
||||
};
|
||||
|
||||
onHttpError = (event: WebViewHttpErrorEvent) => {
|
||||
const { onHttpError } = this.props;
|
||||
if (onHttpError) {
|
||||
onHttpError(event);
|
||||
}
|
||||
}
|
||||
|
||||
onLoadingFinish = (event: WebViewNavigationEvent) => {
|
||||
const { onLoad, onLoadEnd } = this.props;
|
||||
if (onLoad) {
|
||||
|
@ -281,6 +289,7 @@ class WebView extends React.Component<AndroidWebViewProps, State> {
|
|||
onLoadingFinish={this.onLoadingFinish}
|
||||
onLoadingProgress={this.onLoadingProgress}
|
||||
onLoadingStart={this.onLoadingStart}
|
||||
onHttpError={this.onHttpError}
|
||||
onMessage={this.onMessage}
|
||||
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
||||
ref={this.webViewRef}
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
} from './WebViewShared';
|
||||
import {
|
||||
WebViewErrorEvent,
|
||||
WebViewHttpErrorEvent,
|
||||
WebViewMessageEvent,
|
||||
WebViewNavigationEvent,
|
||||
WebViewProgressEvent,
|
||||
|
@ -207,6 +208,13 @@ class WebView extends React.Component<IOSWebViewProps, State> {
|
|||
});
|
||||
};
|
||||
|
||||
onHttpError = (event: WebViewHttpErrorEvent) => {
|
||||
const { onHttpError } = this.props;
|
||||
if (onHttpError) {
|
||||
onHttpError(event);
|
||||
}
|
||||
}
|
||||
|
||||
onLoadingFinish = (event: WebViewNavigationEvent) => {
|
||||
const { onLoad, onLoadEnd } = this.props;
|
||||
if (onLoad) {
|
||||
|
@ -321,6 +329,7 @@ class WebView extends React.Component<IOSWebViewProps, State> {
|
|||
onLoadingFinish={this.onLoadingFinish}
|
||||
onLoadingProgress={this.onLoadingProgress}
|
||||
onLoadingStart={this.onLoadingStart}
|
||||
onHttpError={this.onHttpError}
|
||||
onMessage={this.onMessage}
|
||||
onScroll={this.props.onScroll}
|
||||
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
||||
|
|
|
@ -109,6 +109,11 @@ export interface WebViewError extends WebViewNativeEvent {
|
|||
description: string;
|
||||
}
|
||||
|
||||
export interface WebViewHttpError extends WebViewNativeEvent {
|
||||
description: string;
|
||||
statusCode: number;
|
||||
}
|
||||
|
||||
export type WebViewEvent = NativeSyntheticEvent<WebViewNativeEvent>;
|
||||
|
||||
export type WebViewProgressEvent = NativeSyntheticEvent<
|
||||
|
@ -121,6 +126,8 @@ export type WebViewMessageEvent = NativeSyntheticEvent<WebViewMessage>;
|
|||
|
||||
export type WebViewErrorEvent = NativeSyntheticEvent<WebViewError>;
|
||||
|
||||
export type WebViewHttpErrorEvent = NativeSyntheticEvent<WebViewHttpError>;
|
||||
|
||||
export type DataDetectorTypes =
|
||||
| 'phoneNumber'
|
||||
| 'link'
|
||||
|
@ -210,6 +217,7 @@ export interface CommonNativeWebViewProps extends ViewProps {
|
|||
onLoadingFinish: (event: WebViewNavigationEvent) => void;
|
||||
onLoadingProgress: (event: WebViewProgressEvent) => void;
|
||||
onLoadingStart: (event: WebViewNavigationEvent) => void;
|
||||
onHttpError: (event: WebViewHttpErrorEvent) => void;
|
||||
onMessage: (event: WebViewMessageEvent) => void;
|
||||
onShouldStartLoadWithRequest: (event: WebViewNavigationEvent) => void;
|
||||
showsHorizontalScrollIndicator?: boolean;
|
||||
|
@ -598,6 +606,12 @@ export interface WebViewSharedProps extends ViewProps {
|
|||
*/
|
||||
onError?: (event: WebViewErrorEvent) => void;
|
||||
|
||||
/**
|
||||
* Function that is invoked when the `WebView` receives an error status code.
|
||||
* Works on iOS and Android (minimum API level 23).
|
||||
*/
|
||||
onHttpError?: (event: WebViewHttpErrorEvent) => void;
|
||||
|
||||
/**
|
||||
* Function that is invoked when the `WebView` loading starts or ends.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue