@javascriptcommon/react-native-webview 13.12.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -0
  3. package/android/build.gradle +110 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +15 -0
  6. package/android/src/main/AndroidManifestNew.xml +13 -0
  7. package/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java +11 -0
  8. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java +372 -0
  9. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java +450 -0
  10. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +328 -0
  11. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewConfig.java +11 -0
  12. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java +14 -0
  13. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt +720 -0
  14. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMessagingModule.kt +19 -0
  15. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java +554 -0
  16. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java +56 -0
  17. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewWrapper.kt +39 -0
  18. package/android/src/main/java/com/reactnativecommunity/webview/URLUtil.java +179 -0
  19. package/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt +24 -0
  20. package/android/src/main/java/com/reactnativecommunity/webview/events/TopHttpErrorEvent.kt +25 -0
  21. package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingErrorEvent.kt +25 -0
  22. package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingFinishEvent.kt +24 -0
  23. package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingProgressEvent.kt +24 -0
  24. package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingStartEvent.kt +25 -0
  25. package/android/src/main/java/com/reactnativecommunity/webview/events/TopMessageEvent.kt +24 -0
  26. package/android/src/main/java/com/reactnativecommunity/webview/events/TopNewWindowEvent.kt +25 -0
  27. package/android/src/main/java/com/reactnativecommunity/webview/events/TopRenderProcessGoneEvent.kt +26 -0
  28. package/android/src/main/java/com/reactnativecommunity/webview/events/TopShouldStartLoadWithRequestEvent.kt +29 -0
  29. package/android/src/main/res/xml/file_provider_paths.xml +6 -0
  30. package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +553 -0
  31. package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java +63 -0
  32. package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java +328 -0
  33. package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java +59 -0
  34. package/apple/RCTConvert+WKDataDetectorTypes.h +11 -0
  35. package/apple/RCTConvert+WKDataDetectorTypes.m +27 -0
  36. package/apple/RNCWKProcessPoolManager.h +15 -0
  37. package/apple/RNCWKProcessPoolManager.m +36 -0
  38. package/apple/RNCWebView.h +35 -0
  39. package/apple/RNCWebView.mm +546 -0
  40. package/apple/RNCWebViewDecisionManager.h +20 -0
  41. package/apple/RNCWebViewDecisionManager.m +47 -0
  42. package/apple/RNCWebViewImpl.h +161 -0
  43. package/apple/RNCWebViewImpl.m +1979 -0
  44. package/apple/RNCWebViewManager.h +9 -0
  45. package/apple/RNCWebViewManager.mm +215 -0
  46. package/apple/RNCWebViewModule.h +23 -0
  47. package/apple/RNCWebViewModule.mm +34 -0
  48. package/index.d.ts +65 -0
  49. package/index.js +4 -0
  50. package/ios/RNCWebView.xcodeproj/project.pbxproj +273 -0
  51. package/lib/NativeRNCWebViewModule.d.ts +10 -0
  52. package/lib/NativeRNCWebViewModule.js +1 -0
  53. package/lib/RNCWebViewNativeComponent.d.ts +242 -0
  54. package/lib/RNCWebViewNativeComponent.js +1 -0
  55. package/lib/WebView.android.d.ts +6 -0
  56. package/lib/WebView.android.js +1 -0
  57. package/lib/WebView.d.ts +6 -0
  58. package/lib/WebView.ios.d.ts +6 -0
  59. package/lib/WebView.ios.js +1 -0
  60. package/lib/WebView.js +1 -0
  61. package/lib/WebView.macos.d.ts +6 -0
  62. package/lib/WebView.macos.js +1 -0
  63. package/lib/WebView.styles.d.ts +38 -0
  64. package/lib/WebView.styles.js +1 -0
  65. package/lib/WebView.windows.d.ts +17 -0
  66. package/lib/WebView.windows.js +1 -0
  67. package/lib/WebViewNativeComponent.macos.d.ts +3 -0
  68. package/lib/WebViewNativeComponent.macos.js +1 -0
  69. package/lib/WebViewNativeComponent.windows.d.ts +3 -0
  70. package/lib/WebViewNativeComponent.windows.js +1 -0
  71. package/lib/WebViewShared.d.ts +38 -0
  72. package/lib/WebViewShared.js +1 -0
  73. package/lib/WebViewTypes.d.ts +1093 -0
  74. package/lib/WebViewTypes.js +1 -0
  75. package/lib/index.d.ts +3 -0
  76. package/lib/index.js +1 -0
  77. package/macos/RNCWebView.xcodeproj/project.pbxproj +363 -0
  78. package/package.json +101 -0
  79. package/react-native-webview.podspec +46 -0
  80. package/react-native.config.js +44 -0
  81. package/src/NativeRNCWebViewModule.ts +15 -0
  82. package/src/RNCWebViewNativeComponent.ts +342 -0
  83. package/src/WebView.android.tsx +317 -0
  84. package/src/WebView.ios.tsx +299 -0
  85. package/src/WebView.macos.tsx +245 -0
  86. package/src/WebView.styles.ts +41 -0
  87. package/src/WebView.tsx +25 -0
  88. package/src/WebView.windows.tsx +210 -0
  89. package/src/WebViewNativeComponent.macos.ts +7 -0
  90. package/src/WebViewNativeComponent.windows.ts +8 -0
  91. package/src/WebViewShared.tsx +283 -0
  92. package/src/WebViewTypes.ts +1332 -0
  93. package/src/__tests__/WebViewShared-test.js +323 -0
  94. package/src/__tests__/__snapshots__/WebViewShared-test.js.snap +8 -0
  95. package/src/index.ts +4 -0
  96. package/windows/ExperimentalFeatures.props +11 -0
  97. package/windows/ReactNativeWebView/PropertySheet.props +16 -0
  98. package/windows/ReactNativeWebView/ReactNativeWebView.def +3 -0
  99. package/windows/ReactNativeWebView/ReactNativeWebView.filters +33 -0
  100. package/windows/ReactNativeWebView/ReactNativeWebView.vcxproj +189 -0
  101. package/windows/ReactNativeWebView/ReactPackageProvider.cpp +26 -0
  102. package/windows/ReactNativeWebView/ReactPackageProvider.h +20 -0
  103. package/windows/ReactNativeWebView/ReactPackageProvider.idl +7 -0
  104. package/windows/ReactNativeWebView/ReactWebView.cpp +242 -0
  105. package/windows/ReactNativeWebView/ReactWebView.h +56 -0
  106. package/windows/ReactNativeWebView/ReactWebView.idl +31 -0
  107. package/windows/ReactNativeWebView/ReactWebView2.cpp +473 -0
  108. package/windows/ReactNativeWebView/ReactWebView2.h +91 -0
  109. package/windows/ReactNativeWebView/ReactWebView2Manager.cpp +205 -0
  110. package/windows/ReactNativeWebView/ReactWebView2Manager.h +57 -0
  111. package/windows/ReactNativeWebView/ReactWebViewHelpers.cpp +70 -0
  112. package/windows/ReactNativeWebView/ReactWebViewHelpers.h +16 -0
  113. package/windows/ReactNativeWebView/ReactWebViewManager.cpp +224 -0
  114. package/windows/ReactNativeWebView/ReactWebViewManager.h +58 -0
  115. package/windows/ReactNativeWebView/WebBridge.cpp +19 -0
  116. package/windows/ReactNativeWebView/WebBridge.h +24 -0
  117. package/windows/ReactNativeWebView/WebBridge.idl +11 -0
  118. package/windows/ReactNativeWebView/pch.cpp +1 -0
  119. package/windows/ReactNativeWebView/pch.h +37 -0
  120. package/windows/ReactNativeWebView.sln +185 -0
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * Portions copyright for react-native-windows:
8
+ *
9
+ * Copyright (c) Microsoft Corporation. All rights reserved.
10
+ * Licensed under the MIT License.
11
+ */
12
+
13
+ import React, {
14
+ forwardRef,
15
+ useCallback,
16
+ useImperativeHandle,
17
+ useRef,
18
+ } from 'react';
19
+ import { View, Image, ImageSourcePropType, NativeModules } from 'react-native';
20
+ import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
21
+ import invariant from 'invariant';
22
+ import { RCTWebView, RCTWebView2 } from './WebViewNativeComponent.windows';
23
+ import {
24
+ useWebViewLogic,
25
+ defaultOriginWhitelist,
26
+ defaultRenderError,
27
+ defaultRenderLoading,
28
+ } from './WebViewShared';
29
+ import { NativeWebViewWindows, WindowsWebViewProps } from './WebViewTypes';
30
+
31
+ import styles from './WebView.styles';
32
+
33
+ const Commands = codegenNativeCommands({
34
+ supportedCommands: [
35
+ 'goBack',
36
+ 'goForward',
37
+ 'reload',
38
+ 'stopLoading',
39
+ 'injectJavaScript',
40
+ 'requestFocus',
41
+ 'clearCache',
42
+ 'postMessage',
43
+ 'loadUrl',
44
+ ],
45
+ });
46
+ const { resolveAssetSource } = Image;
47
+
48
+ const WebViewComponent = forwardRef<{}, WindowsWebViewProps>(
49
+ (
50
+ {
51
+ cacheEnabled = true,
52
+ originWhitelist = defaultOriginWhitelist,
53
+ startInLoadingState,
54
+ onNavigationStateChange,
55
+ onLoadStart,
56
+ onError,
57
+ onLoad,
58
+ onLoadEnd,
59
+ onLoadProgress,
60
+ onOpenWindow: onOpenWindowProp,
61
+ onSourceChanged,
62
+ onHttpError: onHttpErrorProp,
63
+ onMessage: onMessageProp,
64
+ renderLoading,
65
+ renderError,
66
+ style,
67
+ containerStyle,
68
+ source,
69
+ nativeConfig,
70
+ onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp,
71
+ useWebView2,
72
+ ...otherProps
73
+ },
74
+ ref
75
+ ) => {
76
+ const webViewRef = useRef<NativeWebViewWindows | null>(null);
77
+
78
+ const RCTWebViewString = useWebView2 ? 'RCTWebView2' : 'RCTWebView';
79
+
80
+ const onShouldStartLoadWithRequestCallback = useCallback(
81
+ (shouldStart: boolean, url: string, lockIdentifier?: number) => {
82
+ if (lockIdentifier) {
83
+ if (RCTWebViewString === 'RCTWebView') {
84
+ NativeModules.RCTWebView.onShouldStartLoadWithRequestCallback(
85
+ shouldStart,
86
+ lockIdentifier
87
+ );
88
+ } else {
89
+ NativeModules.RCTWebView2.onShouldStartLoadWithRequestCallback(
90
+ shouldStart,
91
+ lockIdentifier
92
+ );
93
+ }
94
+ } else if (shouldStart) {
95
+ Commands.loadUrl(webViewRef, url);
96
+ }
97
+ },
98
+ [RCTWebViewString]
99
+ );
100
+
101
+ const {
102
+ onLoadingStart,
103
+ onShouldStartLoadWithRequest,
104
+ onMessage,
105
+ viewState,
106
+ setViewState,
107
+ lastErrorEvent,
108
+ onHttpError,
109
+ onLoadingError,
110
+ onLoadingFinish,
111
+ onLoadingProgress,
112
+ onOpenWindow,
113
+ } = useWebViewLogic({
114
+ onNavigationStateChange,
115
+ onLoad,
116
+ onError,
117
+ onHttpErrorProp,
118
+ onLoadEnd,
119
+ onLoadProgress,
120
+ onLoadStart,
121
+ onMessageProp,
122
+ startInLoadingState,
123
+ originWhitelist,
124
+ onShouldStartLoadWithRequestProp,
125
+ onShouldStartLoadWithRequestCallback,
126
+ onOpenWindowProp,
127
+ });
128
+
129
+ useImperativeHandle(
130
+ ref,
131
+ () => ({
132
+ goForward: () => Commands.goForward(webViewRef.current),
133
+ goBack: () => Commands.goBack(webViewRef.current),
134
+ reload: () => {
135
+ setViewState('LOADING');
136
+ Commands.reload(webViewRef.current);
137
+ },
138
+ stopLoading: () => Commands.stopLoading(webViewRef.current),
139
+ postMessage: (data: string) =>
140
+ Commands.postMessage(webViewRef.current, data),
141
+ injectJavaScript: (data: string) =>
142
+ Commands.injectJavaScript(webViewRef.current, data),
143
+ requestFocus: () => Commands.requestFocus(webViewRef.current),
144
+ clearCache: () => Commands.clearCache(webViewRef.current),
145
+ loadUrl: (url: string) => Commands.loadUrl(webViewRef.current, url),
146
+ }),
147
+ [setViewState, webViewRef]
148
+ );
149
+
150
+ let otherView = null;
151
+ if (viewState === 'LOADING') {
152
+ otherView = (renderLoading || defaultRenderLoading)();
153
+ } else if (viewState === 'ERROR') {
154
+ invariant(
155
+ lastErrorEvent != null,
156
+ 'lastErrorEvent expected to be non-null'
157
+ );
158
+ otherView = (renderError || defaultRenderError)(
159
+ lastErrorEvent.domain,
160
+ lastErrorEvent.code,
161
+ lastErrorEvent.description
162
+ );
163
+ } else if (viewState !== 'IDLE') {
164
+ console.error(`RNCWebView invalid state encountered: ${viewState}`);
165
+ }
166
+
167
+ const webViewStyles = [styles.container, styles.webView, style];
168
+ const webViewContainerStyle = [styles.container, containerStyle];
169
+
170
+ const NativeWebView = useWebView2 ? RCTWebView2 : RCTWebView;
171
+
172
+ const webView = (
173
+ <NativeWebView
174
+ key="webViewKey"
175
+ {...otherProps}
176
+ messagingEnabled={typeof onMessageProp === 'function'}
177
+ linkHandlingEnabled={typeof onOpenWindowProp === 'function'}
178
+ onLoadingError={onLoadingError}
179
+ onLoadingFinish={onLoadingFinish}
180
+ onLoadingProgress={onLoadingProgress}
181
+ onLoadingStart={onLoadingStart}
182
+ onHttpError={onHttpError}
183
+ onMessage={onMessage}
184
+ onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
185
+ onOpenWindow={onOpenWindow}
186
+ onSourceChanged={onSourceChanged}
187
+ ref={webViewRef}
188
+ // TODO: find a better way to type this.
189
+ source={resolveAssetSource(source as ImageSourcePropType)}
190
+ style={webViewStyles}
191
+ cacheEnabled={cacheEnabled}
192
+ {...nativeConfig?.props}
193
+ />
194
+ );
195
+
196
+ return (
197
+ <View style={webViewContainerStyle}>
198
+ {webView}
199
+ {otherView}
200
+ </View>
201
+ );
202
+ }
203
+ );
204
+
205
+ // native implementation should return "true" only for Android 5+
206
+ const isFileUploadSupported: () => Promise<boolean> = async () => false;
207
+
208
+ const WebView = Object.assign(WebViewComponent, { isFileUploadSupported });
209
+
210
+ export default WebView;
@@ -0,0 +1,7 @@
1
+ import { requireNativeComponent } from 'react-native';
2
+ import type { NativeWebViewMacOS } from './WebViewTypes';
3
+
4
+ const RNCWebView: typeof NativeWebViewMacOS =
5
+ requireNativeComponent('RNCWebView');
6
+
7
+ export default RNCWebView;
@@ -0,0 +1,8 @@
1
+ import { requireNativeComponent } from 'react-native';
2
+ import type { NativeWebViewWindows } from './WebViewTypes';
3
+
4
+ export const RCTWebView: typeof NativeWebViewWindows =
5
+ requireNativeComponent('RCTWebView');
6
+
7
+ export const RCTWebView2: typeof NativeWebViewWindows =
8
+ requireNativeComponent('RCTWebView2');
@@ -0,0 +1,283 @@
1
+ import escapeStringRegexp from 'escape-string-regexp';
2
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
3
+ import { Linking, View, ActivityIndicator, Text, Platform } from 'react-native';
4
+ import {
5
+ OnShouldStartLoadWithRequest,
6
+ ShouldStartLoadRequestEvent,
7
+ WebViewError,
8
+ WebViewErrorEvent,
9
+ WebViewHttpErrorEvent,
10
+ WebViewMessageEvent,
11
+ WebViewNavigation,
12
+ WebViewNavigationEvent,
13
+ WebViewOpenWindowEvent,
14
+ WebViewProgressEvent,
15
+ WebViewRenderProcessGoneEvent,
16
+ WebViewTerminatedEvent,
17
+ } from './WebViewTypes';
18
+ import styles from './WebView.styles';
19
+
20
+ const defaultOriginWhitelist = ['http://*', 'https://*'] as const;
21
+
22
+ const extractOrigin = (url: string): string => {
23
+ const result = /^[A-Za-z][A-Za-z0-9+\-.]+:(\/\/)?[^/]*/.exec(url);
24
+ return result === null ? '' : result[0];
25
+ };
26
+
27
+ const originWhitelistToRegex = (originWhitelist: string): string =>
28
+ `^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}`;
29
+
30
+ const passesWhitelist = (compiledWhitelist: readonly string[], url: string) => {
31
+ const origin = extractOrigin(url);
32
+ return compiledWhitelist.some((x) => new RegExp(x).test(origin));
33
+ };
34
+
35
+ const compileWhitelist = (
36
+ originWhitelist: readonly string[]
37
+ ): readonly string[] =>
38
+ ['about:blank', ...(originWhitelist || [])].map(originWhitelistToRegex);
39
+
40
+ const createOnShouldStartLoadWithRequest = (
41
+ loadRequest: (
42
+ shouldStart: boolean,
43
+ url: string,
44
+ lockIdentifier: number
45
+ ) => void,
46
+ originWhitelist: readonly string[],
47
+ onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest
48
+ ) => {
49
+ return ({ nativeEvent }: ShouldStartLoadRequestEvent) => {
50
+ let shouldStart = true;
51
+ const { url, lockIdentifier } = nativeEvent;
52
+
53
+ if (!passesWhitelist(compileWhitelist(originWhitelist), url)) {
54
+ Linking.canOpenURL(url)
55
+ .then((supported) => {
56
+ if (supported) {
57
+ return Linking.openURL(url);
58
+ }
59
+ console.warn(`Can't open url: ${url}`);
60
+ return undefined;
61
+ })
62
+ .catch((e) => {
63
+ console.warn('Error opening URL: ', e);
64
+ });
65
+ shouldStart = false;
66
+ } else if (onShouldStartLoadWithRequest) {
67
+ shouldStart = onShouldStartLoadWithRequest(nativeEvent);
68
+ }
69
+
70
+ loadRequest(shouldStart, url, lockIdentifier);
71
+ };
72
+ };
73
+
74
+ const defaultRenderLoading = () => (
75
+ <View style={styles.loadingOrErrorView}>
76
+ <ActivityIndicator />
77
+ </View>
78
+ );
79
+ const defaultRenderError = (
80
+ errorDomain: string | undefined,
81
+ errorCode: number,
82
+ errorDesc: string
83
+ ) => (
84
+ <View style={styles.loadingOrErrorView}>
85
+ <Text style={styles.errorTextTitle}>Error loading page</Text>
86
+ <Text style={styles.errorText}>{`Domain: ${errorDomain}`}</Text>
87
+ <Text style={styles.errorText}>{`Error Code: ${errorCode}`}</Text>
88
+ <Text style={styles.errorText}>{`Description: ${errorDesc}`}</Text>
89
+ </View>
90
+ );
91
+
92
+ export {
93
+ defaultOriginWhitelist,
94
+ createOnShouldStartLoadWithRequest,
95
+ defaultRenderLoading,
96
+ defaultRenderError,
97
+ };
98
+
99
+ export const useWebViewLogic = ({
100
+ startInLoadingState,
101
+ onNavigationStateChange,
102
+ onLoadStart,
103
+ onLoad,
104
+ onLoadProgress,
105
+ onLoadEnd,
106
+ onError,
107
+ onHttpErrorProp,
108
+ onMessageProp,
109
+ onOpenWindowProp,
110
+ onRenderProcessGoneProp,
111
+ onContentProcessDidTerminateProp,
112
+ originWhitelist,
113
+ onShouldStartLoadWithRequestProp,
114
+ onShouldStartLoadWithRequestCallback,
115
+ }: {
116
+ startInLoadingState?: boolean;
117
+ onNavigationStateChange?: (event: WebViewNavigation) => void;
118
+ onLoadStart?: (event: WebViewNavigationEvent) => void;
119
+ onLoad?: (event: WebViewNavigationEvent) => void;
120
+ onLoadProgress?: (event: WebViewProgressEvent) => void;
121
+ onLoadEnd?: (event: WebViewNavigationEvent | WebViewErrorEvent) => void;
122
+ onError?: (event: WebViewErrorEvent) => void;
123
+ onHttpErrorProp?: (event: WebViewHttpErrorEvent) => void;
124
+ onMessageProp?: (event: WebViewMessageEvent) => void;
125
+ onOpenWindowProp?: (event: WebViewOpenWindowEvent) => void;
126
+ onRenderProcessGoneProp?: (event: WebViewRenderProcessGoneEvent) => void;
127
+ onContentProcessDidTerminateProp?: (event: WebViewTerminatedEvent) => void;
128
+ originWhitelist: readonly string[];
129
+ onShouldStartLoadWithRequestProp?: OnShouldStartLoadWithRequest;
130
+ onShouldStartLoadWithRequestCallback: (
131
+ shouldStart: boolean,
132
+ url: string,
133
+ lockIdentifier?: number | undefined
134
+ ) => void;
135
+ }) => {
136
+ const [viewState, setViewState] = useState<'IDLE' | 'LOADING' | 'ERROR'>(
137
+ startInLoadingState ? 'LOADING' : 'IDLE'
138
+ );
139
+ const [lastErrorEvent, setLastErrorEvent] = useState<WebViewError | null>(
140
+ null
141
+ );
142
+ const startUrl = useRef<string | null>(null);
143
+
144
+ const updateNavigationState = useCallback(
145
+ (event: WebViewNavigationEvent) => {
146
+ onNavigationStateChange?.(event.nativeEvent);
147
+ },
148
+ [onNavigationStateChange]
149
+ );
150
+
151
+ const onLoadingStart = useCallback(
152
+ (event: WebViewNavigationEvent) => {
153
+ // Needed for android
154
+ startUrl.current = event.nativeEvent.url;
155
+ // !Needed for android
156
+
157
+ onLoadStart?.(event);
158
+ updateNavigationState(event);
159
+ },
160
+ [onLoadStart, updateNavigationState]
161
+ );
162
+
163
+ const onLoadingError = useCallback(
164
+ (event: WebViewErrorEvent) => {
165
+ event.persist();
166
+ if (onError) {
167
+ onError(event);
168
+ } else {
169
+ console.warn('Encountered an error loading page', event.nativeEvent);
170
+ }
171
+ onLoadEnd?.(event);
172
+ if (event.isDefaultPrevented()) {
173
+ return;
174
+ }
175
+ setViewState('ERROR');
176
+ setLastErrorEvent(event.nativeEvent);
177
+ },
178
+ [onError, onLoadEnd]
179
+ );
180
+
181
+ const onHttpError = useCallback(
182
+ (event: WebViewHttpErrorEvent) => {
183
+ onHttpErrorProp?.(event);
184
+ },
185
+ [onHttpErrorProp]
186
+ );
187
+
188
+ // Android Only
189
+ const onRenderProcessGone = useCallback(
190
+ (event: WebViewRenderProcessGoneEvent) => {
191
+ onRenderProcessGoneProp?.(event);
192
+ },
193
+ [onRenderProcessGoneProp]
194
+ );
195
+ // !Android Only
196
+
197
+ // iOS Only
198
+ const onContentProcessDidTerminate = useCallback(
199
+ (event: WebViewTerminatedEvent) => {
200
+ onContentProcessDidTerminateProp?.(event);
201
+ },
202
+ [onContentProcessDidTerminateProp]
203
+ );
204
+ // !iOS Only
205
+
206
+ const onLoadingFinish = useCallback(
207
+ (event: WebViewNavigationEvent) => {
208
+ onLoad?.(event);
209
+ onLoadEnd?.(event);
210
+ const {
211
+ nativeEvent: { url },
212
+ } = event;
213
+ // on Android, only if url === startUrl
214
+ if (Platform.OS !== 'android' || url === startUrl.current) {
215
+ setViewState('IDLE');
216
+ }
217
+ // !on Android, only if url === startUrl
218
+ updateNavigationState(event);
219
+ },
220
+ [onLoad, onLoadEnd, updateNavigationState]
221
+ );
222
+
223
+ const onMessage = useCallback(
224
+ (event: WebViewMessageEvent) => {
225
+ onMessageProp?.(event);
226
+ },
227
+ [onMessageProp]
228
+ );
229
+
230
+ const onLoadingProgress = useCallback(
231
+ (event: WebViewProgressEvent) => {
232
+ const {
233
+ nativeEvent: { progress },
234
+ } = event;
235
+ // patch for Android only
236
+ if (Platform.OS === 'android' && progress === 1) {
237
+ setViewState((prevViewState) =>
238
+ prevViewState === 'LOADING' ? 'IDLE' : prevViewState
239
+ );
240
+ }
241
+ // !patch for Android only
242
+ onLoadProgress?.(event);
243
+ },
244
+ [onLoadProgress]
245
+ );
246
+
247
+ const onShouldStartLoadWithRequest = useMemo(
248
+ () =>
249
+ createOnShouldStartLoadWithRequest(
250
+ onShouldStartLoadWithRequestCallback,
251
+ originWhitelist,
252
+ onShouldStartLoadWithRequestProp
253
+ ),
254
+ [
255
+ originWhitelist,
256
+ onShouldStartLoadWithRequestProp,
257
+ onShouldStartLoadWithRequestCallback,
258
+ ]
259
+ );
260
+
261
+ const onOpenWindow = useCallback(
262
+ (event: WebViewOpenWindowEvent) => {
263
+ onOpenWindowProp?.(event);
264
+ },
265
+ [onOpenWindowProp]
266
+ );
267
+
268
+ return {
269
+ onShouldStartLoadWithRequest,
270
+ onLoadingStart,
271
+ onLoadingProgress,
272
+ onLoadingError,
273
+ onLoadingFinish,
274
+ onHttpError,
275
+ onRenderProcessGone,
276
+ onContentProcessDidTerminate,
277
+ onMessage,
278
+ onOpenWindow,
279
+ viewState,
280
+ setViewState,
281
+ lastErrorEvent,
282
+ };
283
+ };