@exodus/react-native-webview 13.16.0-exodus.2 → 13.16.0-exodus.4

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 (39) hide show
  1. package/android/build.gradle +11 -7
  2. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java +15 -18
  3. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +0 -21
  4. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt +5 -50
  5. package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +0 -58
  6. package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java +0 -40
  7. package/apple/RNCWebView.mm +0 -8
  8. package/apple/RNCWebViewDecisionManager.m +17 -0
  9. package/apple/RNCWebViewImpl.h +0 -10
  10. package/apple/RNCWebViewImpl.m +24 -72
  11. package/apple/RNCWebViewManager.mm +0 -8
  12. package/lib/RNCWebViewNativeComponent.d.ts +0 -26
  13. package/lib/RNCWebViewNativeComponent.js +1 -1
  14. package/lib/WebView.android.js +1 -1
  15. package/lib/WebView.d.ts +2 -2
  16. package/lib/WebView.ios.js +1 -1
  17. package/lib/WebViewShared.d.ts +5 -5
  18. package/lib/WebViewShared.js +1 -1
  19. package/lib/WebViewTypes.d.ts +5 -358
  20. package/lib/WebViewTypes.js +1 -1
  21. package/package.json +4 -11
  22. package/react-native-webview.podspec +1 -1
  23. package/src/RNCWebViewNativeComponent.ts +0 -37
  24. package/src/WebView.android.tsx +293 -284
  25. package/src/WebView.ios.tsx +223 -256
  26. package/src/WebView.tsx +2 -8
  27. package/src/WebViewShared.tsx +2 -11
  28. package/src/WebViewTypes.ts +2 -396
  29. package/src/__tests__/WebViewShared-test.js +40 -62
  30. package/src/__tests__/__snapshots__/WebViewShared-test.js.snap +0 -1
  31. package/android/src/main/java/com/reactnativecommunity/webview/events/TopHttpErrorEvent.kt +0 -25
  32. package/lib/WebView.windows.d.ts +0 -17
  33. package/lib/WebView.windows.js +0 -1
  34. package/lib/WebViewNativeComponent.windows.d.ts +0 -3
  35. package/lib/WebViewNativeComponent.windows.js +0 -1
  36. package/src/WebView.macos.tsx +0 -252
  37. package/src/WebView.windows.tsx +0 -217
  38. package/src/WebViewNativeComponent.macos.ts +0 -7
  39. package/src/WebViewNativeComponent.windows.ts +0 -8
@@ -4,6 +4,7 @@ import React, {
4
4
  useCallback,
5
5
  useEffect,
6
6
  useImperativeHandle,
7
+ useMemo,
7
8
  useRef,
8
9
  useState,
9
10
  } from 'react';
@@ -31,6 +32,8 @@ import {
31
32
  defaultRenderLoading,
32
33
  useWebViewLogic,
33
34
  versionPasses,
35
+ passesWhitelist,
36
+ compileWhitelist,
34
37
  } from './WebViewShared';
35
38
  import {
36
39
  AndroidWebViewProps,
@@ -39,6 +42,7 @@ import {
39
42
  type ShouldStartLoadRequestEvent,
40
43
  } from './WebViewTypes';
41
44
 
45
+ import validateProps from './validation';
42
46
  import styles from './WebView.styles';
43
47
 
44
48
  const { resolveAssetSource } = Image;
@@ -92,315 +96,320 @@ const securityMixedContentMode = 'never' as const;
92
96
  */
93
97
  let uniqueRef = 0;
94
98
 
95
- const WebViewComponent = forwardRef<{}, AndroidWebViewProps>(
96
- (
97
- {
98
- overScrollMode = 'always',
99
- javaScriptEnabled = true,
100
- thirdPartyCookiesEnabled = true,
101
- scalesPageToFit = true,
102
- allowsFullscreenVideo = false,
103
- allowFileAccess = false,
104
- saveFormDataDisabled = false,
105
- cacheEnabled = true,
106
- androidLayerType = 'none',
107
- originWhitelist = defaultOriginWhitelist,
108
- deeplinkWhitelist = defaultDeeplinkWhitelist,
109
- setBuiltInZoomControls = true,
110
- setDisplayZoomControls = false,
111
- nestedScrollEnabled = false,
112
- startInLoadingState,
113
- onNavigationStateChange,
114
- onLoadStart,
115
- onError,
116
- onLoad,
117
- onLoadEnd,
118
- onLoadSubResourceError,
119
- onLoadProgress,
120
- onHttpError: onHttpErrorProp,
121
- onRenderProcessGone: onRenderProcessGoneProp,
122
- onMessage: onMessageProp,
123
- onOpenWindow: onOpenWindowProp,
124
- renderLoading,
125
- renderError,
126
- style,
127
- containerStyle,
128
- source,
129
- nativeConfig,
130
- onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp,
131
- injectedJavaScriptObject,
132
- validateMeta,
133
- validateData,
134
- minimumChromeVersion,
135
- unsupportedVersionComponent: UnsupportedVersionComponent,
136
- ...otherProps
99
+ const WebViewComponent = forwardRef<{}, AndroidWebViewProps>((props, ref) => {
100
+ // Exodus: Validate props at runtime
101
+ validateProps(props);
102
+
103
+ const {
104
+ overScrollMode = 'always',
105
+ javaScriptEnabled = true,
106
+ thirdPartyCookiesEnabled = true,
107
+ scalesPageToFit = true,
108
+ allowsFullscreenVideo = false,
109
+ saveFormDataDisabled = false,
110
+ cacheEnabled = true,
111
+ androidLayerType = 'none',
112
+ originWhitelist = defaultOriginWhitelist,
113
+ deeplinkWhitelist = defaultDeeplinkWhitelist,
114
+ setBuiltInZoomControls = true,
115
+ setDisplayZoomControls = false,
116
+ nestedScrollEnabled = false,
117
+ startInLoadingState,
118
+ onNavigationStateChange,
119
+ onLoadStart,
120
+ onError,
121
+ onLoad,
122
+ onLoadEnd,
123
+ onLoadSubResourceError,
124
+ onLoadProgress,
125
+ onRenderProcessGone: onRenderProcessGoneProp,
126
+ onMessage: onMessageProp,
127
+ onOpenWindow: onOpenWindowProp,
128
+ renderLoading,
129
+ renderError,
130
+ style,
131
+ containerStyle,
132
+ source,
133
+ onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp,
134
+ injectedJavaScriptObject,
135
+ validateMeta,
136
+ validateData,
137
+ minimumChromeVersion,
138
+ unsupportedVersionComponent: UnsupportedVersionComponent,
139
+ ...otherProps
140
+ } = props;
141
+
142
+ const messagingModuleName = useRef<string>(
143
+ `WebViewMessageHandler${(uniqueRef += 1)}`
144
+ ).current;
145
+ const webViewRef = useRef<React.ComponentRef<
146
+ HostComponent<NativeProps>
147
+ > | null>(null);
148
+
149
+ const [userAgent, setUserAgent] = useState<string>();
150
+
151
+ useEffect(() => {
152
+ getUserAgent().then(setUserAgent);
153
+ }, []);
154
+
155
+ const onShouldStartLoadWithRequestCallback = useCallback(
156
+ (shouldStart: boolean, url: string, lockIdentifier?: number) => {
157
+ if (lockIdentifier) {
158
+ RNCWebViewModule.shouldStartLoadWithLockIdentifier(
159
+ shouldStart,
160
+ lockIdentifier
161
+ );
162
+ } else if (shouldStart && webViewRef.current) {
163
+ Commands.loadUrl(webViewRef.current, url);
164
+ }
137
165
  },
138
- ref
139
- ) => {
140
- const messagingModuleName = useRef<string>(
141
- `WebViewMessageHandler${(uniqueRef += 1)}`
142
- ).current;
143
- const webViewRef = useRef<React.ComponentRef<
144
- HostComponent<NativeProps>
145
- > | null>(null);
146
-
147
- const [userAgent, setUserAgent] = useState<string>();
148
-
149
- useEffect(() => {
150
- getUserAgent().then(setUserAgent);
151
- }, []);
152
-
153
- const onShouldStartLoadWithRequestCallback = useCallback(
154
- (shouldStart: boolean, url: string, lockIdentifier?: number) => {
155
- if (lockIdentifier) {
156
- RNCWebViewModule.shouldStartLoadWithLockIdentifier(
157
- shouldStart,
158
- lockIdentifier
159
- );
160
- } else if (shouldStart && webViewRef.current) {
161
- Commands.loadUrl(webViewRef.current, url);
166
+ []
167
+ );
168
+
169
+ const {
170
+ onLoadingStart,
171
+ onShouldStartLoadWithRequest,
172
+ onMessage,
173
+ viewState,
174
+ setViewState,
175
+ lastErrorEvent,
176
+ onLoadingError,
177
+ onLoadingSubResourceError,
178
+ onLoadingFinish,
179
+ onLoadingProgress,
180
+ onOpenWindow,
181
+ onRenderProcessGone,
182
+ } = useWebViewLogic({
183
+ onNavigationStateChange,
184
+ onLoad,
185
+ onError,
186
+ onLoadSubResourceError,
187
+ onLoadEnd,
188
+ onLoadProgress,
189
+ onLoadStart,
190
+ onRenderProcessGoneProp,
191
+ onMessageProp,
192
+ onOpenWindowProp,
193
+ startInLoadingState,
194
+ originWhitelist,
195
+ deeplinkWhitelist,
196
+ onShouldStartLoadWithRequestProp,
197
+ onShouldStartLoadWithRequestCallback,
198
+ validateMeta,
199
+ validateData,
200
+ });
201
+
202
+ useImperativeHandle(
203
+ ref,
204
+ () => ({
205
+ goForward: () =>
206
+ webViewRef.current && Commands.goForward(webViewRef.current),
207
+ goBack: () => webViewRef.current && Commands.goBack(webViewRef.current),
208
+ reload: () => {
209
+ setViewState('LOADING');
210
+ if (webViewRef.current) {
211
+ Commands.reload(webViewRef.current);
162
212
  }
163
213
  },
164
- []
165
- );
166
-
167
- const {
168
- onLoadingStart,
169
- onShouldStartLoadWithRequest,
170
- onMessage,
171
- viewState,
172
- setViewState,
173
- lastErrorEvent,
174
- onHttpError,
175
- onLoadingError,
176
- onLoadingSubResourceError,
177
- onLoadingFinish,
178
- onLoadingProgress,
179
- onOpenWindow,
180
- onRenderProcessGone,
181
- } = useWebViewLogic({
182
- onNavigationStateChange,
183
- onLoad,
184
- onError,
185
- onHttpErrorProp,
186
- onLoadSubResourceError,
187
- onLoadEnd,
188
- onLoadProgress,
189
- onLoadStart,
190
- onRenderProcessGoneProp,
191
- onMessageProp,
192
- onOpenWindowProp,
193
- startInLoadingState,
194
- originWhitelist,
195
- deeplinkWhitelist,
196
- onShouldStartLoadWithRequestProp,
197
- onShouldStartLoadWithRequestCallback,
198
- validateMeta,
199
- validateData,
200
- });
201
-
202
- useImperativeHandle(
203
- ref,
204
- () => ({
205
- goForward: () =>
206
- webViewRef.current && Commands.goForward(webViewRef.current),
207
- goBack: () => webViewRef.current && Commands.goBack(webViewRef.current),
208
- reload: () => {
209
- setViewState('LOADING');
210
- if (webViewRef.current) {
211
- Commands.reload(webViewRef.current);
214
+ stopLoading: () =>
215
+ webViewRef.current && Commands.stopLoading(webViewRef.current),
216
+ postMessage: (data: string) =>
217
+ webViewRef.current && Commands.postMessage(webViewRef.current, data),
218
+ requestFocus: () =>
219
+ webViewRef.current && Commands.requestFocus(webViewRef.current),
220
+ clearFormData: () =>
221
+ webViewRef.current && Commands.clearFormData(webViewRef.current),
222
+ clearCache: (includeDiskFiles: boolean) =>
223
+ webViewRef.current &&
224
+ Commands.clearCache(webViewRef.current, includeDiskFiles),
225
+ clearHistory: () =>
226
+ webViewRef.current && Commands.clearHistory(webViewRef.current),
227
+ }),
228
+ [setViewState, webViewRef]
229
+ );
230
+
231
+ useEffect(() => {
232
+ const onShouldStartLoadWithRequestSubscription =
233
+ directEventEmitter.addListener(
234
+ 'onShouldStartLoadWithRequest',
235
+ (
236
+ event: ShouldStartLoadRequestEvent & {
237
+ messagingModuleName?: string;
212
238
  }
213
- },
214
- stopLoading: () =>
215
- webViewRef.current && Commands.stopLoading(webViewRef.current),
216
- postMessage: (data: string) =>
217
- webViewRef.current && Commands.postMessage(webViewRef.current, data),
218
- injectJavaScript: (data: string) =>
219
- webViewRef.current &&
220
- Commands.injectJavaScript(webViewRef.current, data),
221
- requestFocus: () =>
222
- webViewRef.current && Commands.requestFocus(webViewRef.current),
223
- clearFormData: () =>
224
- webViewRef.current && Commands.clearFormData(webViewRef.current),
225
- clearCache: (includeDiskFiles: boolean) =>
226
- webViewRef.current &&
227
- Commands.clearCache(webViewRef.current, includeDiskFiles),
228
- clearHistory: () =>
229
- webViewRef.current && Commands.clearHistory(webViewRef.current),
230
- }),
231
- [setViewState, webViewRef]
232
- );
233
-
234
- useEffect(() => {
235
- const onShouldStartLoadWithRequestSubscription =
236
- directEventEmitter.addListener(
237
- 'onShouldStartLoadWithRequest',
238
- (
239
- event: ShouldStartLoadRequestEvent & {
240
- messagingModuleName?: string;
241
- }
242
- ) => {
243
- if (event.messagingModuleName === messagingModuleName) {
244
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
245
- const { messagingModuleName: _, ...rest } = event;
246
- onShouldStartLoadWithRequest(rest);
247
- }
248
- }
249
- );
250
-
251
- const onMessageSubscription = directEventEmitter.addListener(
252
- 'onMessage',
253
- (event: WebViewMessageEvent & { messagingModuleName?: string }) => {
239
+ ) => {
254
240
  if (event.messagingModuleName === messagingModuleName) {
255
241
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
256
242
  const { messagingModuleName: _, ...rest } = event;
257
- onMessage(rest);
243
+ onShouldStartLoadWithRequest(rest);
258
244
  }
259
245
  }
260
246
  );
261
247
 
262
- return () => {
263
- onShouldStartLoadWithRequestSubscription.remove();
264
- onMessageSubscription.remove();
265
- };
266
- }, [messagingModuleName, onMessage, onShouldStartLoadWithRequest]);
248
+ const onMessageSubscription = directEventEmitter.addListener(
249
+ 'onMessage',
250
+ (event: WebViewMessageEvent & { messagingModuleName?: string }) => {
251
+ if (event.messagingModuleName === messagingModuleName) {
252
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
253
+ const { messagingModuleName: _, ...rest } = event;
254
+ onMessage(rest);
255
+ }
256
+ }
257
+ );
267
258
 
268
- // Stop the rendering until userAgent is known
269
- if (!userAgent) return null;
259
+ return () => {
260
+ onShouldStartLoadWithRequestSubscription.remove();
261
+ onMessageSubscription.remove();
262
+ };
263
+ }, [messagingModuleName, onMessage, onShouldStartLoadWithRequest]);
270
264
 
271
- const chromeVersion = userAgent.match(
272
- /chrome\/((?:[0-9]+\.)+[0-9]+)/i
273
- )?.[1];
265
+ // Exodus: Compile origin whitelist for initial-load guard
266
+ const compiledWhitelist = useMemo(
267
+ () => compileWhitelist(originWhitelist),
268
+ [originWhitelist]
269
+ );
274
270
 
271
+ // Exodus: Guard initial source against origin whitelist (H-02)
272
+ const safeSource = useMemo(() => {
275
273
  if (
276
- !(
277
- versionPasses(chromeVersion, minimumChromeVersion) &&
278
- versionPasses(chromeVersion, hardMinimumChromeVersion)
279
- )
274
+ source &&
275
+ typeof source === 'object' &&
276
+ 'uri' in source &&
277
+ typeof source.uri === 'string'
280
278
  ) {
281
- if (UnsupportedVersionComponent) {
282
- return <UnsupportedVersionComponent />;
279
+ if (!passesWhitelist(compiledWhitelist, source.uri)) {
280
+ console.warn(
281
+ `WebView: source.uri "${source.uri}" does not pass the origin whitelist. Loading about:blank instead.`
282
+ );
283
+ return { uri: 'about:blank' };
283
284
  }
284
- return (
285
- <View style={{ alignSelf: 'flex-start' }}>
286
- <Text style={{ color: 'red' }}>
287
- Chrome version is outdated and insecure. Update it to continue.
288
- </Text>
289
- </View>
290
- );
291
285
  }
286
+ return source;
287
+ }, [source, compiledWhitelist]);
288
+
289
+ // Stop the rendering until userAgent is known
290
+ if (!userAgent) return null;
291
+
292
+ const chromeVersion = userAgent.match(/chrome\/((?:[0-9]+\.)+[0-9]+)/i)?.[1];
293
+
294
+ if (
295
+ !(
296
+ versionPasses(chromeVersion, minimumChromeVersion) &&
297
+ versionPasses(chromeVersion, hardMinimumChromeVersion)
298
+ )
299
+ ) {
300
+ if (UnsupportedVersionComponent) {
301
+ return <UnsupportedVersionComponent />;
302
+ }
303
+ return (
304
+ <View style={{ alignSelf: 'flex-start' }}>
305
+ <Text style={{ color: 'red' }}>
306
+ Chrome version is outdated and insecure. Update it to continue.
307
+ </Text>
308
+ </View>
309
+ );
310
+ }
292
311
 
293
- let otherView: ReactElement | undefined;
294
- if (viewState === 'LOADING') {
295
- otherView = (renderLoading || defaultRenderLoading)();
296
- } else if (viewState === 'ERROR') {
297
- invariant(
298
- lastErrorEvent != null,
299
- 'lastErrorEvent expected to be non-null'
312
+ let otherView: ReactElement | undefined;
313
+ if (viewState === 'LOADING') {
314
+ otherView = (renderLoading || defaultRenderLoading)();
315
+ } else if (viewState === 'ERROR') {
316
+ invariant(lastErrorEvent != null, 'lastErrorEvent expected to be non-null');
317
+ if (lastErrorEvent) {
318
+ otherView = (renderError || defaultRenderError)(
319
+ lastErrorEvent.domain,
320
+ lastErrorEvent.code,
321
+ lastErrorEvent.description
300
322
  );
301
- if (lastErrorEvent) {
302
- otherView = (renderError || defaultRenderError)(
303
- lastErrorEvent.domain,
304
- lastErrorEvent.code,
305
- lastErrorEvent.description
306
- );
307
- }
308
- } else if (viewState !== 'IDLE') {
309
- console.error(`RNCWebView invalid state encountered: ${viewState}`);
310
323
  }
324
+ } else if (viewState !== 'IDLE') {
325
+ console.error(`RNCWebView invalid state encountered: ${viewState}`);
326
+ }
311
327
 
312
- const webViewStyles = [styles.container, styles.webView, style];
313
- const webViewContainerStyle = [styles.container, containerStyle];
328
+ const webViewStyles = [styles.container, styles.webView, style];
329
+ const webViewContainerStyle = [styles.container, containerStyle];
314
330
 
315
- if (typeof source !== 'number' && source && 'method' in source) {
316
- if (source.method === 'POST' && source.headers) {
317
- console.warn(
318
- 'WebView: `source.headers` is not supported when using POST.'
319
- );
320
- } else if (source.method === 'GET' && source.body) {
321
- console.warn('WebView: `source.body` is not supported when using GET.');
322
- }
331
+ if (typeof safeSource !== 'number' && safeSource && 'method' in safeSource) {
332
+ if (safeSource.method === 'POST' && safeSource.headers) {
333
+ console.warn(
334
+ 'WebView: `source.headers` is not supported when using POST.'
335
+ );
336
+ } else if (safeSource.method === 'GET' && safeSource.body) {
337
+ console.warn('WebView: `source.body` is not supported when using GET.');
323
338
  }
324
-
325
- const NativeWebView =
326
- (nativeConfig?.component as typeof RNCWebView | undefined) || RNCWebView;
327
-
328
- const sourceResolved = resolveAssetSource(source as ImageSourcePropType);
329
- const newSource =
330
- typeof sourceResolved === 'object'
331
- ? Object.entries(sourceResolved as WebViewSourceUri).reduce(
332
- (prev, [currKey, currValue]) => {
333
- return {
334
- ...prev,
335
- [currKey]:
336
- currKey === 'headers' &&
337
- currValue &&
338
- typeof currValue === 'object'
339
- ? Object.entries(currValue).map(([key, value]) => {
340
- return {
341
- name: key,
342
- value,
343
- };
344
- })
345
- : currValue,
346
- };
347
- },
348
- {}
349
- )
350
- : sourceResolved;
351
-
352
- const webView = (
353
- <NativeWebView
354
- key="webViewKey"
355
- {...otherProps}
356
- messagingEnabled={typeof onMessageProp === 'function'}
357
- messagingModuleName={messagingModuleName}
358
- hasOnScroll={!!otherProps.onScroll}
359
- onLoadingError={onLoadingError}
360
- onLoadingSubResourceError={onLoadingSubResourceError}
361
- onLoadingFinish={onLoadingFinish}
362
- onLoadingProgress={onLoadingProgress}
363
- onLoadingStart={onLoadingStart}
364
- onHttpError={onHttpError}
365
- onRenderProcessGone={onRenderProcessGone}
366
- onMessage={onMessage}
367
- onOpenWindow={onOpenWindow}
368
- hasOnOpenWindowEvent={onOpenWindowProp !== undefined}
369
- onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
370
- ref={webViewRef}
371
- // TODO: find a better way to type this.
372
- // @ts-expect-error source is old arch
373
- source={sourceResolved}
374
- newSource={newSource}
375
- style={webViewStyles}
376
- overScrollMode={overScrollMode}
377
- javaScriptEnabled={javaScriptEnabled}
378
- thirdPartyCookiesEnabled={thirdPartyCookiesEnabled}
379
- scalesPageToFit={scalesPageToFit}
380
- allowsFullscreenVideo={allowsFullscreenVideo}
381
- allowFileAccess={allowFileAccess}
382
- saveFormDataDisabled={saveFormDataDisabled}
383
- cacheEnabled={cacheEnabled}
384
- androidLayerType={androidLayerType}
385
- setSupportMultipleWindows={securitySupportMultipleWindows}
386
- setBuiltInZoomControls={setBuiltInZoomControls}
387
- setDisplayZoomControls={setDisplayZoomControls}
388
- nestedScrollEnabled={nestedScrollEnabled}
389
- mixedContentMode={securityMixedContentMode}
390
- mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction}
391
- injectedJavaScriptObject={JSON.stringify(injectedJavaScriptObject)}
392
- {...nativeConfig?.props}
393
- />
394
- );
395
-
396
- return (
397
- <View style={webViewContainerStyle}>
398
- {webView}
399
- {otherView}
400
- </View>
401
- );
402
339
  }
403
- );
340
+
341
+ const sourceResolved = resolveAssetSource(safeSource as ImageSourcePropType);
342
+ const newSource =
343
+ typeof sourceResolved === 'object'
344
+ ? Object.entries(sourceResolved as WebViewSourceUri).reduce(
345
+ (prev, [currKey, currValue]) => {
346
+ return {
347
+ ...prev,
348
+ [currKey]:
349
+ currKey === 'headers' &&
350
+ currValue &&
351
+ typeof currValue === 'object'
352
+ ? Object.entries(currValue).map(([key, value]) => {
353
+ return {
354
+ name: key,
355
+ value,
356
+ };
357
+ })
358
+ : currValue,
359
+ };
360
+ },
361
+ {}
362
+ )
363
+ : sourceResolved;
364
+
365
+ const webView = (
366
+ <RNCWebView
367
+ key="webViewKey"
368
+ {...otherProps}
369
+ messagingEnabled={typeof onMessageProp === 'function'}
370
+ messagingModuleName={messagingModuleName}
371
+ hasOnScroll={!!otherProps.onScroll}
372
+ onLoadingError={onLoadingError}
373
+ onLoadingSubResourceError={onLoadingSubResourceError}
374
+ onLoadingFinish={onLoadingFinish}
375
+ onLoadingProgress={onLoadingProgress}
376
+ onLoadingStart={onLoadingStart}
377
+ onRenderProcessGone={onRenderProcessGone}
378
+ onMessage={onMessage}
379
+ onOpenWindow={onOpenWindow}
380
+ hasOnOpenWindowEvent={onOpenWindowProp !== undefined}
381
+ onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
382
+ ref={webViewRef}
383
+ // TODO: find a better way to type this.
384
+ // @ts-expect-error source is old arch
385
+ source={sourceResolved}
386
+ newSource={newSource}
387
+ style={webViewStyles}
388
+ overScrollMode={overScrollMode}
389
+ javaScriptEnabled={javaScriptEnabled}
390
+ thirdPartyCookiesEnabled={thirdPartyCookiesEnabled}
391
+ scalesPageToFit={scalesPageToFit}
392
+ allowsFullscreenVideo={allowsFullscreenVideo}
393
+ saveFormDataDisabled={saveFormDataDisabled}
394
+ cacheEnabled={cacheEnabled}
395
+ androidLayerType={androidLayerType}
396
+ setSupportMultipleWindows={securitySupportMultipleWindows}
397
+ setBuiltInZoomControls={setBuiltInZoomControls}
398
+ setDisplayZoomControls={setDisplayZoomControls}
399
+ nestedScrollEnabled={nestedScrollEnabled}
400
+ mixedContentMode={securityMixedContentMode}
401
+ mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction}
402
+ injectedJavaScriptObject={JSON.stringify(injectedJavaScriptObject)}
403
+ />
404
+ );
405
+
406
+ return (
407
+ <View style={webViewContainerStyle}>
408
+ {webView}
409
+ {otherView}
410
+ </View>
411
+ );
412
+ });
404
413
 
405
414
  // native implementation should return "true" only for Android 5+
406
415
  const { isFileUploadSupported } = RNCWebViewModule;