@exodus/react-native-webview 11.26.1-exodus.4 → 11.26.1-exodus.6

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.
@@ -54,13 +54,11 @@ UIScrollViewDelegate,
54
54
  #endif // !TARGET_OS_OSX
55
55
  RCTAutoInsetsProtocol>
56
56
 
57
- @property (nonatomic, copy) RCTDirectEventBlock onFileDownload;
58
57
  @property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
59
58
  @property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
60
59
  @property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
61
60
  @property (nonatomic, copy) RCTDirectEventBlock onLoadingProgress;
62
61
  @property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
63
- @property (nonatomic, copy) RCTDirectEventBlock onHttpError;
64
62
  @property (nonatomic, copy) RCTDirectEventBlock onMessage;
65
63
  @property (nonatomic, copy) RCTDirectEventBlock onScroll;
66
64
  @property (nonatomic, copy) RCTDirectEventBlock onContentProcessDidTerminate;
@@ -122,9 +120,7 @@ RCTAutoInsetsProtocol>
122
120
  _savedStatusBarHidden = RCTSharedApplication().statusBarHidden;
123
121
  #endif // !TARGET_OS_OSX
124
122
  _injectedJavaScript = nil;
125
- _injectedJavaScriptForMainFrameOnly = YES;
126
123
  _injectedJavaScriptBeforeContentLoaded = nil;
127
- _injectedJavaScriptBeforeContentLoadedForMainFrameOnly = YES;
128
124
 
129
125
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
130
126
  _savedContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
@@ -139,15 +135,6 @@ RCTAutoInsetsProtocol>
139
135
  }
140
136
 
141
137
  #if !TARGET_OS_OSX
142
- [[NSNotificationCenter defaultCenter]addObserver:self
143
- selector:@selector(appDidBecomeActive)
144
- name:UIApplicationDidBecomeActiveNotification
145
- object:nil];
146
-
147
- [[NSNotificationCenter defaultCenter]addObserver:self
148
- selector:@selector(appWillResignActive)
149
- name:UIApplicationWillResignActiveNotification
150
- object:nil];
151
138
  if (@available(iOS 12.0, *)) {
152
139
  // Workaround for a keyboard dismissal bug present in iOS 12
153
140
  // https://openradar.appspot.com/radar?id=5018321736957952
@@ -306,30 +293,23 @@ RCTAutoInsetsProtocol>
306
293
  {
307
294
  WKWebViewConfiguration *wkWebViewConfig = [WKWebViewConfiguration new];
308
295
  WKPreferences *prefs = [[WKPreferences alloc]init];
309
- BOOL _prefsUsed = YES;
310
296
  if (!_javaScriptEnabled) {
311
297
  prefs.javaScriptEnabled = NO;
312
- _prefsUsed = YES;
313
- }
314
- if (_allowUniversalAccessFromFileURLs) {
315
- [wkWebViewConfig setValue:@TRUE forKey:@"allowUniversalAccessFromFileURLs"];
316
- }
317
- if (_allowFileAccessFromFileURLs) {
318
- [prefs setValue:@TRUE forKey:@"allowFileAccessFromFileURLs"];
319
- _prefsUsed = YES;
320
298
  }
299
+
300
+ // NOTE: defaults, recheck?
301
+ // [wkWebViewConfig setValue:@FALSE forKey:@"allowUniversalAccessFromFileURLs"];
302
+ // [prefs setValue:@FALSE forKey:@"allowFileAccessFromFileURLs"];
303
+
321
304
  [prefs setValue:@FALSE forKey:@"javaScriptCanOpenWindowsAutomatically"];
322
305
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500 /* iOS 14.5 */
323
306
  if (@available(iOS 14.5, *)) {
324
307
  if (!_textInteractionEnabled) {
325
308
  [prefs setValue:@FALSE forKey:@"textInteractionEnabled"];
326
- _prefsUsed = YES;
327
309
  }
328
310
  }
329
311
  #endif
330
- if (_prefsUsed) {
331
- wkWebViewConfig.preferences = prefs;
332
- }
312
+ wkWebViewConfig.preferences = prefs;
333
313
  if (_incognito) {
334
314
  wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
335
315
  } else if (_cacheEnabled) {
@@ -364,7 +344,7 @@ RCTAutoInsetsProtocol>
364
344
  [self resetupScripts:wkWebViewConfig];
365
345
 
366
346
  if(@available(ios 9.0, *)) {
367
- wkWebViewConfig.allowsAirPlayForMediaPlayback = _allowsAirPlayForMediaPlayback;
347
+ wkWebViewConfig.allowsAirPlayForMediaPlayback = NO;
368
348
  }
369
349
 
370
350
  #if !TARGET_OS_OSX
@@ -379,10 +359,6 @@ RCTAutoInsetsProtocol>
379
359
  #endif
380
360
  #endif // !TARGET_OS_OSX
381
361
 
382
- if (_applicationNameForUserAgent) {
383
- wkWebViewConfig.applicationNameForUserAgent = [NSString stringWithFormat:@"%@ %@", wkWebViewConfig.applicationNameForUserAgent, _applicationNameForUserAgent];
384
- }
385
-
386
362
  return wkWebViewConfig;
387
363
  }
388
364
 
@@ -466,10 +442,6 @@ RCTAutoInsetsProtocol>
466
442
  _webView.scrollView.delegate = nil;
467
443
  #endif // !TARGET_OS_OSX
468
444
  _webView = nil;
469
- if (_onContentProcessDidTerminate) {
470
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
471
- _onContentProcessDidTerminate(event);
472
- }
473
445
  }
474
446
 
475
447
  [super removeFromSuperview];
@@ -624,17 +596,6 @@ RCTAutoInsetsProtocol>
624
596
  }
625
597
  }
626
598
 
627
- - (void)setAllowingReadAccessToURL:(NSString *)allowingReadAccessToURL
628
- {
629
- if (![_allowingReadAccessToURL isEqualToString:allowingReadAccessToURL]) {
630
- _allowingReadAccessToURL = [allowingReadAccessToURL copy];
631
-
632
- if (_webView != nil) {
633
- [self visitSource];
634
- }
635
- }
636
- }
637
-
638
599
  #if !TARGET_OS_OSX
639
600
  - (void)setContentInset:(UIEdgeInsets)contentInset
640
601
  {
@@ -682,8 +643,10 @@ RCTAutoInsetsProtocol>
682
643
  [_webView loadRequest:request];
683
644
  }
684
645
  else {
685
- NSURL* readAccessUrl = _allowingReadAccessToURL ? [RCTConvert NSURL:_allowingReadAccessToURL] : request.URL;
686
- [_webView loadFileURL:request.URL allowingReadAccessToURL:readAccessUrl];
646
+ // WARNING: UNREACHABLE, non-host loads (file urls)
647
+ // Clear the webview
648
+ [_webView loadHTMLString:@"" baseURL:nil];
649
+ return;
687
650
  }
688
651
  }];
689
652
  }
@@ -1147,10 +1110,6 @@ RCTAutoInsetsProtocol>
1147
1110
  - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
1148
1111
  {
1149
1112
  RCTLogWarn(@"Webview Process Terminated");
1150
- if (_onContentProcessDidTerminate) {
1151
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1152
- _onContentProcessDidTerminate(event);
1153
- }
1154
1113
  }
1155
1114
 
1156
1115
  /**
@@ -1162,36 +1121,19 @@ RCTAutoInsetsProtocol>
1162
1121
  decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
1163
1122
  {
1164
1123
  WKNavigationResponsePolicy policy = WKNavigationResponsePolicyAllow;
1165
- if (_onHttpError && navigationResponse.forMainFrame) {
1124
+ if (navigationResponse.forMainFrame) {
1166
1125
  if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
1167
1126
  NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
1168
1127
  NSInteger statusCode = response.statusCode;
1169
1128
 
1170
- if (statusCode >= 400) {
1171
- NSMutableDictionary<NSString *, id> *httpErrorEvent = [self baseEvent];
1172
- [httpErrorEvent addEntriesFromDictionary: @{
1173
- @"url": response.URL.absoluteString,
1174
- @"statusCode": @(statusCode)
1175
- }];
1176
-
1177
- _onHttpError(httpErrorEvent);
1178
- }
1179
-
1180
1129
  NSString *disposition = nil;
1181
1130
  if (@available(iOS 13, *)) {
1182
1131
  disposition = [response valueForHTTPHeaderField:@"Content-Disposition"];
1183
1132
  }
1184
1133
  BOOL isAttachment = disposition != nil && [disposition hasPrefix:@"attachment"];
1185
1134
  if (isAttachment || !navigationResponse.canShowMIMEType) {
1186
- if (_onFileDownload) {
1187
- policy = WKNavigationResponsePolicyCancel;
1188
-
1189
- NSMutableDictionary<NSString *, id> *downloadEvent = [self baseEvent];
1190
- [downloadEvent addEntriesFromDictionary: @{
1191
- @"downloadUrl": (response.URL).absoluteString,
1192
- }];
1193
- _onFileDownload(downloadEvent);
1194
- }
1135
+ policy = WKNavigationResponsePolicyCancel;
1136
+ // File downloads are cancelled
1195
1137
  }
1196
1138
  }
1197
1139
  }
@@ -1252,37 +1194,6 @@ RCTAutoInsetsProtocol>
1252
1194
  }];
1253
1195
  }
1254
1196
 
1255
- -(void)forceIgnoreSilentHardwareSwitch:(BOOL)initialSetup
1256
- {
1257
- NSString *mp3Str = @"data:audio/mp3;base64,//tAxAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAAFAAAESAAzMzMzMzMzMzMzMzMzMzMzMzMzZmZmZmZmZmZmZmZmZmZmZmZmZmaZmZmZmZmZmZmZmZmZmZmZmZmZmczMzMzMzMzMzMzMzMzMzMzMzMzM//////////////////////////8AAAA5TEFNRTMuMTAwAZYAAAAAAAAAABQ4JAMGQgAAOAAABEhNIZS0AAAAAAD/+0DEAAPH3Yz0AAR8CPqyIEABp6AxjG/4x/XiInE4lfQDFwIIRE+uBgZoW4RL0OLMDFn6E5v+/u5ehf76bu7/6bu5+gAiIQGAABQIUJ0QolFghEn/9PhZQpcUTpXMjo0OGzRCZXyKxoIQzB2KhCtGobpT9TRVj/3Pmfp+f8X7Pu1B04sTnc3s0XhOlXoGVCMNo9X//9/r6a10TZEY5DsxqvO7mO5qFvpFCmKIjhpSItGsUYcRO//7QsQRgEiljQIAgLFJAbIhNBCa+JmorCbOi5q9nVd2dKnusTMQg4MFUlD6DQ4OFijwGAijRMfLbHG4nLVTjydyPlJTj8pfPflf9/5GD950A5e+jsrmNZSjSirjs1R7hnkia8vr//l/7Nb+crvr9Ok5ZJOylUKRxf/P9Zn0j2P4pJYXyKkeuy5wUYtdmOu6uobEtFqhIJViLEKIjGxchGev/L3Y0O3bwrIOszTBAZ7Ih28EUaSOZf/7QsQfg8fpjQIADN0JHbGgQBAZ8T//y//t/7d/2+f5m7MdCeo/9tdkMtGLbt1tqnabRroO1Qfvh20yEbei8nfDXP7btW7f9/uO9tbe5IvHQbLlxpf3DkAk0ojYcv///5/u3/7PTfGjPEPUvt5D6f+/3Lea4lz4tc4TnM/mFPrmalWbboeNiNyeyr+vufttZuvrVrt/WYv3T74JFo8qEDiJqJrmDTs///v99xDku2xG02jjunrICP/7QsQtA8kpkQAAgNMA/7FgQAGnobgfghgqA+uXwWQ3XFmGimSbe2X3ksY//KzK1a2k6cnNWOPJnPWUsYbKqkh8RJzrVf///P///////4vyhLKHLrCb5nIrYIUss4cthigL1lQ1wwNAc6C1pf1TIKRSkt+a//z+yLVcwlXKSqeSuCVQFLng2h4AFAFgTkH+Z/8jTX/zr//zsJV/5f//5UX/0ZNCNCCaf5lTCTRkaEdhNP//n/KUjf/7QsQ5AEhdiwAAjN7I6jGddBCO+WGTQ1mXrYatSAgaykxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==";
1258
- NSString *scr;
1259
- if (initialSetup) {
1260
- scr = [NSString stringWithFormat:@"var s=new Audio('%@');s.id='wkwebviewAudio';s.controls=false;s.loop=true;s.play();document.body.appendChild(s);true", mp3Str];
1261
- } else {
1262
- scr = [NSString stringWithFormat:@"var s=document.getElementById('wkwebviewAudio');s.src=null;s.parentNode.removeChild(s);s=null;s=new Audio('%@');s.id='wkwebviewAudio';s.controls=false;s.loop=true;s.play();document.body.appendChild(s);true", mp3Str];
1263
- }
1264
- [self evaluateJS: scr thenCall: nil];
1265
- }
1266
-
1267
- -(void)disableIgnoreSilentSwitch
1268
- {
1269
- [self evaluateJS: @"document.getElementById('wkwebviewAudio').src=null;true" thenCall: nil];
1270
- }
1271
-
1272
- -(void)appDidBecomeActive
1273
- {
1274
- if (_ignoreSilentHardwareSwitch) {
1275
- [self forceIgnoreSilentHardwareSwitch:false];
1276
- }
1277
- }
1278
-
1279
- -(void)appWillResignActive
1280
- {
1281
- if (_ignoreSilentHardwareSwitch) {
1282
- [self disableIgnoreSilentSwitch];
1283
- }
1284
- }
1285
-
1286
1197
  /**
1287
1198
  * Called when the navigation is complete.
1288
1199
  * @see https://fburl.com/rtys6jlb
@@ -1290,10 +1201,6 @@ RCTAutoInsetsProtocol>
1290
1201
  - (void)webView:(WKWebView *)webView
1291
1202
  didFinishNavigation:(WKNavigation *)navigation
1292
1203
  {
1293
- if (_ignoreSilentHardwareSwitch) {
1294
- [self forceIgnoreSilentHardwareSwitch:true];
1295
- }
1296
-
1297
1204
  if (_onLoadingFinish) {
1298
1205
  _onLoadingFinish([self baseEvent]);
1299
1206
  }
@@ -1389,7 +1296,7 @@ didFinishNavigation:(WKNavigation *)navigation
1389
1296
 
1390
1297
  self.atEndScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source
1391
1298
  injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
1392
- forMainFrameOnly:_injectedJavaScriptForMainFrameOnly];
1299
+ forMainFrameOnly:YES];
1393
1300
 
1394
1301
  if(_webView != nil){
1395
1302
  [self resetupScripts:_webView.configuration];
@@ -1401,23 +1308,13 @@ didFinishNavigation:(WKNavigation *)navigation
1401
1308
 
1402
1309
  self.atStartScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source
1403
1310
  injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1404
- forMainFrameOnly:_injectedJavaScriptBeforeContentLoadedForMainFrameOnly];
1311
+ forMainFrameOnly:YES];
1405
1312
 
1406
1313
  if(_webView != nil){
1407
1314
  [self resetupScripts:_webView.configuration];
1408
1315
  }
1409
1316
  }
1410
1317
 
1411
- - (void)setInjectedJavaScriptForMainFrameOnly:(BOOL)mainFrameOnly {
1412
- _injectedJavaScriptForMainFrameOnly = mainFrameOnly;
1413
- [self setInjectedJavaScript:_injectedJavaScript];
1414
- }
1415
-
1416
- - (void)setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly:(BOOL)mainFrameOnly {
1417
- _injectedJavaScriptBeforeContentLoadedForMainFrameOnly = mainFrameOnly;
1418
- [self setInjectedJavaScriptBeforeContentLoaded:_injectedJavaScriptBeforeContentLoaded];
1419
- }
1420
-
1421
1318
  - (void)setMessagingEnabled:(BOOL)messagingEnabled {
1422
1319
  _messagingEnabled = messagingEnabled;
1423
1320
 
@@ -1434,9 +1331,6 @@ didFinishNavigation:(WKNavigation *)navigation
1434
1331
  "};", MessageHandlerName, MessageHandlerName
1435
1332
  ]
1436
1333
  injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1437
- /* TODO: For a separate (minor) PR: use logic like this (as react-native-wkwebview does) so that messaging can be used in all frames if desired.
1438
- * I am keeping it as YES for consistency with previous behaviour. */
1439
- // forMainFrameOnly:_messagingEnabledForMainFrameOnly
1440
1334
  forMainFrameOnly:YES
1441
1335
  ] :
1442
1336
  nil;
@@ -54,23 +54,15 @@ RCT_EXPORT_MODULE()
54
54
  }
55
55
 
56
56
  RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
57
- RCT_EXPORT_VIEW_PROPERTY(onFileDownload, RCTDirectEventBlock)
58
57
  RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
59
58
  RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
60
59
  RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
61
60
  RCT_EXPORT_VIEW_PROPERTY(onLoadingProgress, RCTDirectEventBlock)
62
- RCT_EXPORT_VIEW_PROPERTY(onHttpError, RCTDirectEventBlock)
63
61
  RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
64
- RCT_EXPORT_VIEW_PROPERTY(onContentProcessDidTerminate, RCTDirectEventBlock)
65
62
  RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
66
63
  RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptBeforeContentLoaded, NSString)
67
- RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptForMainFrameOnly, BOOL)
68
- RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptBeforeContentLoadedForMainFrameOnly, BOOL)
69
64
  RCT_EXPORT_VIEW_PROPERTY(javaScriptEnabled, BOOL)
70
- RCT_EXPORT_VIEW_PROPERTY(allowFileAccessFromFileURLs, BOOL)
71
- RCT_EXPORT_VIEW_PROPERTY(allowUniversalAccessFromFileURLs, BOOL)
72
65
  RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL)
73
- RCT_EXPORT_VIEW_PROPERTY(allowsAirPlayForMediaPlayback, BOOL)
74
66
  RCT_EXPORT_VIEW_PROPERTY(mediaPlaybackRequiresUserAction, BOOL)
75
67
  #if WEBKIT_IOS_10_APIS_AVAILABLE
76
68
  RCT_EXPORT_VIEW_PROPERTY(dataDetectorTypes, WKDataDetectorTypes)
@@ -82,10 +74,8 @@ RCT_EXPORT_VIEW_PROPERTY(hideKeyboardAccessoryView, BOOL)
82
74
  RCT_EXPORT_VIEW_PROPERTY(allowsBackForwardNavigationGestures, BOOL)
83
75
  RCT_EXPORT_VIEW_PROPERTY(incognito, BOOL)
84
76
  RCT_EXPORT_VIEW_PROPERTY(pagingEnabled, BOOL)
85
- RCT_EXPORT_VIEW_PROPERTY(applicationNameForUserAgent, NSString)
86
77
  RCT_EXPORT_VIEW_PROPERTY(cacheEnabled, BOOL)
87
78
  RCT_EXPORT_VIEW_PROPERTY(allowsLinkPreview, BOOL)
88
- RCT_EXPORT_VIEW_PROPERTY(allowingReadAccessToURL, NSString)
89
79
  RCT_EXPORT_VIEW_PROPERTY(basicAuthCredential, NSDictionary)
90
80
 
91
81
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
package/index.js CHANGED
@@ -1,4 +1,7 @@
1
- import WebView from './lib/WebView';
1
+ import WebView, {
2
+ RNCWebViewUtils,
3
+ getWebViewDefaultUserAgent,
4
+ } from './lib/WebView';
2
5
 
3
- export { WebView };
6
+ export { WebView, RNCWebViewUtils, getWebViewDefaultUserAgent };
4
7
  export default WebView;
@@ -1,12 +1,20 @@
1
- import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
2
- import { View, NativeModules, } from 'react-native';
1
+ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
2
+ import { Text, View, NativeModules, } from 'react-native';
3
3
  import BatchedBridge from 'react-native/Libraries/BatchedBridge/BatchedBridge';
4
4
  // @ts-expect-error react-native doesn't have this type
5
5
  import codegenNativeCommandsUntyped from 'react-native/Libraries/Utilities/codegenNativeCommands';
6
6
  import invariant from 'invariant';
7
7
  import RNCWebView from "./WebViewNativeComponent.android";
8
- import { defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, useWebWiewLogic, } from './WebViewShared';
8
+ import { defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, useWebWiewLogic, versionPasses, } from './WebViewShared';
9
9
  import styles from './WebView.styles';
10
+ const { getWebViewDefaultUserAgent } = NativeModules.RNCWebViewUtils;
11
+ let userAgentPromise;
12
+ async function getUserAgent() {
13
+ if (!userAgentPromise)
14
+ userAgentPromise = getWebViewDefaultUserAgent();
15
+ const userAgent = await userAgentPromise;
16
+ return userAgent || 'unknown';
17
+ }
10
18
  const codegenNativeCommands = codegenNativeCommandsUntyped;
11
19
  const Commands = codegenNativeCommands({
12
20
  supportedCommands: ['goBack', 'goForward', 'reload', 'stopLoading', /* 'injectJavaScript', */ 'requestFocus', 'postMessage', 'clearFormData', 'clearCache', 'clearHistory', 'loadUrl'],
@@ -18,17 +26,13 @@ let uniqueRef = 0;
18
26
  /**
19
27
  * Harcoded default for security.
20
28
  */
21
- const allowFileAccessFromFileURLs = false;
22
- const allowUniversalAccessFromFileURLs = false;
23
- const injectedJavaScriptForMainFrameOnly = true;
24
- const injectedJavaScriptBeforeContentLoadedForMainFrameOnly = true;
25
29
  const mediaPlaybackRequiresUserAction = true;
26
30
  // Android only
27
- const allowsFullscreenVideo = false;
28
- const allowFileAccess = false;
29
31
  const setSupportMultipleWindows = true;
30
32
  const mixedContentMode = 'never';
31
- const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnabled = true, thirdPartyCookiesEnabled = true, scalesPageToFit = true, saveFormDataDisabled = false, cacheEnabled = true, androidHardwareAccelerationDisabled = false, androidLayerType = "none", originWhitelist = defaultOriginWhitelist, setBuiltInZoomControls = true, setDisplayZoomControls = false, nestedScrollEnabled = false, startInLoadingState, onNavigationStateChange, onLoadStart, onError, onLoad, onLoadEnd, onLoadProgress, onHttpError: onHttpErrorProp, onRenderProcessGone: onRenderProcessGoneProp, onMessage: onMessageProp, renderLoading, renderError, style, containerStyle, source, onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, ...otherProps }, ref) => {
33
+ const hardMinimumChromeVersion = '100.0'; // TODO: determinime a good lower bound
34
+ const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnabled = true, thirdPartyCookiesEnabled = true, scalesPageToFit = true, saveFormDataDisabled = false, cacheEnabled = true, androidHardwareAccelerationDisabled = false, androidLayerType = "none", originWhitelist = defaultOriginWhitelist, setBuiltInZoomControls = true, setDisplayZoomControls = false, nestedScrollEnabled = false, startInLoadingState, onLoadStart, onError, onLoad, onLoadEnd, onMessage: onMessageProp, renderLoading, renderError, style, containerStyle, source, onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, validateMeta, validateData, minimumChromeVersion, ...otherProps }, ref) => {
35
+ var _a;
32
36
  const messagingModuleName = useRef(`WebViewMessageHandler${uniqueRef += 1}`).current;
33
37
  const webViewRef = useRef(null);
34
38
  const onShouldStartLoadWithRequestCallback = useCallback((shouldStart, url, lockIdentifier) => {
@@ -39,20 +43,18 @@ const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnab
39
43
  Commands.loadUrl(webViewRef.current, url);
40
44
  }
41
45
  }, []);
42
- const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress, onRenderProcessGone } = useWebWiewLogic({
43
- onNavigationStateChange,
46
+ const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onLoadingError, onLoadingFinish, onLoadingProgress, passesWhitelist } = useWebWiewLogic({
44
47
  onLoad,
45
48
  onError,
46
- onHttpErrorProp,
47
49
  onLoadEnd,
48
- onLoadProgress,
49
50
  onLoadStart,
50
- onRenderProcessGoneProp,
51
51
  onMessageProp,
52
52
  startInLoadingState,
53
53
  originWhitelist,
54
54
  onShouldStartLoadWithRequestProp,
55
55
  onShouldStartLoadWithRequestCallback,
56
+ validateMeta,
57
+ validateData,
56
58
  });
57
59
  useImperativeHandle(ref, () => ({
58
60
  goForward: () => Commands.goForward(webViewRef.current),
@@ -76,6 +78,20 @@ const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnab
76
78
  useEffect(() => {
77
79
  BatchedBridge.registerCallableModule(messagingModuleName, directEventCallbacks);
78
80
  }, [messagingModuleName, directEventCallbacks]);
81
+ const [userAgent, setUserAgent] = useState();
82
+ useEffect(() => {
83
+ getUserAgent().then(setUserAgent);
84
+ }, []);
85
+ if (!userAgent)
86
+ return null; // stop the rendering until userAgent is known
87
+ const version = (_a = userAgent.match(/chrome\/((?:[0-9]+\.)+[0-9]+)/i)) === null || _a === void 0 ? void 0 : _a[1];
88
+ if (!(versionPasses(version, minimumChromeVersion) && versionPasses(version, hardMinimumChromeVersion))) {
89
+ return (<View style={{ alignSelf: 'flex-start' }}>
90
+ <Text style={{ color: 'red' }}>
91
+ Chrome version is outdated and insecure. Update it to continue.
92
+ </Text>
93
+ </View>);
94
+ }
79
95
  let otherView = null;
80
96
  if (viewState === 'LOADING') {
81
97
  otherView = (renderLoading || defaultRenderLoading)();
@@ -97,10 +113,14 @@ const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnab
97
113
  console.warn('WebView: `source.body` is not supported when using GET.');
98
114
  }
99
115
  }
116
+ if (typeof source === "object" && 'uri' in source && !passesWhitelist(source.uri)) {
117
+ // eslint-disable-next-line
118
+ source = { uri: "about:blank" };
119
+ }
100
120
  const NativeWebView = RNCWebView;
101
- const webView = <NativeWebView key="webViewKey" {...otherProps} messagingEnabled={typeof onMessageProp === 'function'} messagingModuleName={messagingModuleName} onLoadingError={onLoadingError} onLoadingFinish={onLoadingFinish} onLoadingProgress={onLoadingProgress} onLoadingStart={onLoadingStart} onHttpError={onHttpError} onRenderProcessGone={onRenderProcessGone} onMessage={onMessage} onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} injectedJavaScriptForMainFrameOnly={injectedJavaScriptForMainFrameOnly} injectedJavaScriptBeforeContentLoadedForMainFrameOnly={injectedJavaScriptBeforeContentLoadedForMainFrameOnly} ref={webViewRef}
121
+ const webView = <NativeWebView key="webViewKey" {...otherProps} messagingEnabled={typeof onMessageProp === 'function'} messagingModuleName={messagingModuleName} onLoadingError={onLoadingError} onLoadingFinish={onLoadingFinish} onLoadingProgress={onLoadingProgress} onLoadingStart={onLoadingStart} onMessage={onMessage} onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} ref={webViewRef}
102
122
  // TODO: find a better way to type this.
103
- source={source} style={webViewStyles} overScrollMode={overScrollMode} javaScriptEnabled={javaScriptEnabled} thirdPartyCookiesEnabled={thirdPartyCookiesEnabled} scalesPageToFit={scalesPageToFit} allowsFullscreenVideo={allowsFullscreenVideo} allowFileAccess={allowFileAccess} allowFileAccessFromFileURLs={allowFileAccessFromFileURLs} allowUniversalAccessFromFileURLs={allowUniversalAccessFromFileURLs} saveFormDataDisabled={saveFormDataDisabled} cacheEnabled={cacheEnabled} androidHardwareAccelerationDisabled={androidHardwareAccelerationDisabled} androidLayerType={androidLayerType} setSupportMultipleWindows={setSupportMultipleWindows} setBuiltInZoomControls={setBuiltInZoomControls} setDisplayZoomControls={setDisplayZoomControls} mixedContentMode={mixedContentMode} nestedScrollEnabled={nestedScrollEnabled} mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction}/>;
123
+ source={source} style={webViewStyles} overScrollMode={overScrollMode} javaScriptEnabled={javaScriptEnabled} thirdPartyCookiesEnabled={thirdPartyCookiesEnabled} scalesPageToFit={scalesPageToFit} saveFormDataDisabled={saveFormDataDisabled} cacheEnabled={cacheEnabled} androidHardwareAccelerationDisabled={androidHardwareAccelerationDisabled} androidLayerType={androidLayerType} setSupportMultipleWindows={setSupportMultipleWindows} setBuiltInZoomControls={setBuiltInZoomControls} setDisplayZoomControls={setDisplayZoomControls} mixedContentMode={mixedContentMode} nestedScrollEnabled={nestedScrollEnabled} mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction}/>;
104
124
  return (<View style={webViewContainerStyle}>
105
125
  {webView}
106
126
  {otherView}
@@ -1,10 +1,10 @@
1
1
  import React, { forwardRef, useCallback, useImperativeHandle, useRef } from 'react';
2
- import { View, NativeModules, } from 'react-native';
2
+ import { Text, View, NativeModules, Platform, } from 'react-native';
3
3
  import invariant from 'invariant';
4
4
  // @ts-expect-error react-native doesn't have this type
5
5
  import codegenNativeCommandsUntyped from 'react-native/Libraries/Utilities/codegenNativeCommands';
6
6
  import RNCWebView from "./WebViewNativeComponent.ios";
7
- import { defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, useWebWiewLogic, } from './WebViewShared';
7
+ import { defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, useWebWiewLogic, versionPasses, } from './WebViewShared';
8
8
  import styles from './WebView.styles';
9
9
  const codegenNativeCommands = codegenNativeCommandsUntyped;
10
10
  const Commands = codegenNativeCommands({
@@ -31,39 +31,32 @@ const useWarnIfChanges = (value, name) => {
31
31
  /**
32
32
  * Harcoded defaults for security.
33
33
  */
34
- const allowFileAccessFromFileURLs = false;
35
- const allowUniversalAccessFromFileURLs = false;
36
- const injectedJavaScriptForMainFrameOnly = true;
37
- const injectedJavaScriptBeforeContentLoadedForMainFrameOnly = true;
38
34
  const mediaPlaybackRequiresUserAction = true;
39
35
  // iOS only configs
40
36
  const allowsInlineMediaPlayback = true;
41
- const allowsAirPlayForMediaPlayback = false;
42
37
  const useSharedProcessPool = false;
43
38
  const sharedCookiesEnabled = false;
44
39
  const enableApplePay = false;
45
- const onFileDownload = () => console.error('tried to download file');
46
40
  const dataDetectorTypes = 'none';
47
- const WebViewComponent = forwardRef(({ javaScriptEnabled = true, cacheEnabled = true, originWhitelist = defaultOriginWhitelist, textInteractionEnabled = true, injectedJavaScript, injectedJavaScriptBeforeContentLoaded, startInLoadingState, onNavigationStateChange, onLoadStart, onError, onLoad, onLoadEnd, onLoadProgress, onContentProcessDidTerminate: onContentProcessDidTerminateProp, onHttpError: onHttpErrorProp, onMessage: onMessageProp, renderLoading, renderError, style, containerStyle, source, incognito, decelerationRate: decelerationRateProp, onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, ...otherProps }, ref) => {
41
+ const hardMinimumIOSVersion = '12.5.6'; // TODO: determinime a good lower bound
42
+ const WebViewComponent = forwardRef(({ javaScriptEnabled = true, cacheEnabled = true, originWhitelist = defaultOriginWhitelist, textInteractionEnabled = true, injectedJavaScript, injectedJavaScriptBeforeContentLoaded, startInLoadingState, onLoadStart, onError, onLoad, onLoadEnd, onMessage: onMessageProp, renderLoading, renderError, style, containerStyle, source, incognito, validateMeta, validateData, decelerationRate: decelerationRateProp, onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, minimumIOSVersion, ...otherProps }, ref) => {
48
43
  const webViewRef = useRef(null);
49
44
  const onShouldStartLoadWithRequestCallback = useCallback((shouldStart, _url, lockIdentifier = 0) => {
50
45
  const viewManager = RNCWebViewManager;
51
46
  viewManager.startLoadWithResult(!!shouldStart, lockIdentifier);
52
47
  }, []);
53
- const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress, onContentProcessDidTerminate } = useWebWiewLogic({
54
- onNavigationStateChange,
48
+ const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onLoadingError, onLoadingFinish, onLoadingProgress } = useWebWiewLogic({
55
49
  onLoad,
56
50
  onError,
57
- onHttpErrorProp,
58
51
  onLoadEnd,
59
- onLoadProgress,
60
52
  onLoadStart,
61
53
  onMessageProp,
62
54
  startInLoadingState,
63
55
  originWhitelist,
64
56
  onShouldStartLoadWithRequestProp,
65
57
  onShouldStartLoadWithRequestCallback,
66
- onContentProcessDidTerminateProp,
58
+ validateMeta,
59
+ validateData,
67
60
  });
68
61
  useImperativeHandle(ref, () => ({
69
62
  goForward: () => Commands.goForward(webViewRef.current),
@@ -78,10 +71,17 @@ const WebViewComponent = forwardRef(({ javaScriptEnabled = true, cacheEnabled =
78
71
  requestFocus: () => Commands.requestFocus(webViewRef.current),
79
72
  }), [setViewState, webViewRef]);
80
73
  useWarnIfChanges(allowsInlineMediaPlayback, 'allowsInlineMediaPlayback');
81
- useWarnIfChanges(allowsAirPlayForMediaPlayback, 'allowsAirPlayForMediaPlayback');
82
74
  useWarnIfChanges(incognito, 'incognito');
83
75
  useWarnIfChanges(mediaPlaybackRequiresUserAction, 'mediaPlaybackRequiresUserAction');
84
76
  useWarnIfChanges(dataDetectorTypes, 'dataDetectorTypes');
77
+ const version = String(Platform.Version);
78
+ if (!(versionPasses(version, minimumIOSVersion) && versionPasses(version, hardMinimumIOSVersion))) {
79
+ return (<View style={{ alignSelf: 'flex-start' }}>
80
+ <Text style={{ color: 'red' }}>
81
+ iOS version is outdated and insecure. Update it to continue.
82
+ </Text>
83
+ </View>);
84
+ }
85
85
  let otherView = null;
86
86
  if (viewState === 'LOADING') {
87
87
  otherView = (renderLoading || defaultRenderLoading)();
@@ -97,7 +97,7 @@ const WebViewComponent = forwardRef(({ javaScriptEnabled = true, cacheEnabled =
97
97
  const webViewContainerStyle = [styles.container, containerStyle];
98
98
  const decelerationRate = processDecelerationRate(decelerationRateProp);
99
99
  const NativeWebView = RNCWebView;
100
- const webView = (<NativeWebView key="webViewKey" {...otherProps} allowFileAccessFromFileURLs={allowFileAccessFromFileURLs} allowUniversalAccessFromFileURLs={allowUniversalAccessFromFileURLs} enableApplePay={enableApplePay} javaScriptEnabled={javaScriptEnabled} cacheEnabled={cacheEnabled} dataDetectorTypes={dataDetectorTypes} useSharedProcessPool={useSharedProcessPool} textInteractionEnabled={textInteractionEnabled} decelerationRate={decelerationRate} messagingEnabled={typeof onMessageProp === 'function'} onLoadingError={onLoadingError} onLoadingFinish={onLoadingFinish} onLoadingProgress={onLoadingProgress} onFileDownload={onFileDownload} onLoadingStart={onLoadingStart} onHttpError={onHttpError} onMessage={onMessage} onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} onContentProcessDidTerminate={onContentProcessDidTerminate} injectedJavaScript={injectedJavaScript} injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} injectedJavaScriptForMainFrameOnly={injectedJavaScriptForMainFrameOnly} injectedJavaScriptBeforeContentLoadedForMainFrameOnly={injectedJavaScriptBeforeContentLoadedForMainFrameOnly} allowsAirPlayForMediaPlayback={allowsAirPlayForMediaPlayback} allowsInlineMediaPlayback={allowsInlineMediaPlayback} incognito={incognito} mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction} ref={webViewRef} sharedCookiesEnabled={sharedCookiesEnabled}
100
+ const webView = (<NativeWebView key="webViewKey" {...otherProps} enableApplePay={enableApplePay} javaScriptEnabled={javaScriptEnabled} cacheEnabled={cacheEnabled} dataDetectorTypes={dataDetectorTypes} useSharedProcessPool={useSharedProcessPool} textInteractionEnabled={textInteractionEnabled} decelerationRate={decelerationRate} messagingEnabled={typeof onMessageProp === 'function'} onLoadingError={onLoadingError} onLoadingFinish={onLoadingFinish} onLoadingProgress={onLoadingProgress} onLoadingStart={onLoadingStart} onMessage={onMessage} onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} injectedJavaScript={injectedJavaScript} injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} allowsInlineMediaPlayback={allowsInlineMediaPlayback} incognito={incognito} mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction} ref={webViewRef} sharedCookiesEnabled={sharedCookiesEnabled}
101
101
  // TODO: find a better way to type this.
102
102
  source={source} style={webViewStyles}/>);
103
103
  return (<View style={webViewContainerStyle}>
@@ -1,37 +1,33 @@
1
1
  import React from 'react';
2
- import { OnShouldStartLoadWithRequest, ShouldStartLoadRequestEvent, WebViewError, WebViewErrorEvent, WebViewHttpErrorEvent, WebViewMessageEvent, WebViewNavigation, WebViewNavigationEvent, WebViewProgressEvent, WebViewRenderProcessGoneEvent, WebViewTerminatedEvent } from './WebViewTypes';
3
- declare const defaultOriginWhitelist: readonly ["http://*", "https://*"];
2
+ import { OnShouldStartLoadWithRequest, ShouldStartLoadRequestEvent, WebViewError, WebViewErrorEvent, WebViewMessageEvent, WebViewMessage, WebViewNavigationEvent, WebViewProgressEvent, WebViewNativeEvent } from './WebViewTypes';
3
+ declare const defaultOriginWhitelist: readonly ["https://*"];
4
4
  declare const createOnShouldStartLoadWithRequest: (loadRequest: (shouldStart: boolean, url: string, lockIdentifier: number) => void, originWhitelist: readonly string[], onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest | undefined) => ({ nativeEvent }: ShouldStartLoadRequestEvent) => void;
5
5
  declare const defaultRenderLoading: () => JSX.Element;
6
6
  declare const defaultRenderError: (errorDomain: string | undefined, errorCode: number, errorDesc: string) => JSX.Element;
7
7
  export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, };
8
- export declare const useWebWiewLogic: ({ startInLoadingState, onNavigationStateChange, onLoadStart, onLoad, onLoadProgress, onLoadEnd, onError, onHttpErrorProp, onMessageProp, onRenderProcessGoneProp, onContentProcessDidTerminateProp, originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, }: {
8
+ export declare const useWebWiewLogic: ({ startInLoadingState, onLoadStart, onLoad, onLoadEnd, onError, onMessageProp, originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, validateMeta, validateData, }: {
9
9
  startInLoadingState?: boolean | undefined;
10
- onNavigationStateChange?: ((event: WebViewNavigation) => void) | undefined;
11
10
  onLoadStart?: ((event: WebViewNavigationEvent) => void) | undefined;
12
11
  onLoad?: ((event: WebViewNavigationEvent) => void) | undefined;
13
- onLoadProgress?: ((event: WebViewProgressEvent) => void) | undefined;
14
12
  onLoadEnd?: ((event: WebViewNavigationEvent | WebViewErrorEvent) => void) | undefined;
15
13
  onError?: ((event: WebViewErrorEvent) => void) | undefined;
16
- onHttpErrorProp?: ((event: WebViewHttpErrorEvent) => void) | undefined;
17
- onMessageProp?: ((event: WebViewMessageEvent) => void) | undefined;
18
- onRenderProcessGoneProp?: ((event: WebViewRenderProcessGoneEvent) => void) | undefined;
19
- onContentProcessDidTerminateProp?: ((event: WebViewTerminatedEvent) => void) | undefined;
14
+ onMessageProp?: ((event: WebViewMessage) => void) | undefined;
20
15
  originWhitelist: readonly string[];
21
16
  onShouldStartLoadWithRequestProp?: OnShouldStartLoadWithRequest | undefined;
22
17
  onShouldStartLoadWithRequestCallback: (shouldStart: boolean, url: string, lockIdentifier?: number | undefined) => void;
18
+ validateMeta: (event: WebViewNativeEvent) => WebViewNativeEvent;
19
+ validateData: (data: object) => object;
23
20
  }) => {
24
21
  onShouldStartLoadWithRequest: ({ nativeEvent }: ShouldStartLoadRequestEvent) => void;
25
22
  onLoadingStart: (event: WebViewNavigationEvent) => void;
26
23
  onLoadingProgress: (event: WebViewProgressEvent) => void;
27
24
  onLoadingError: (event: WebViewErrorEvent) => void;
28
25
  onLoadingFinish: (event: WebViewNavigationEvent) => void;
29
- onHttpError: (event: WebViewHttpErrorEvent) => void;
30
- onRenderProcessGone: (event: WebViewRenderProcessGoneEvent) => void;
31
- onContentProcessDidTerminate: (event: WebViewTerminatedEvent) => void;
32
26
  onMessage: (event: WebViewMessageEvent) => void;
27
+ passesWhitelist: (url: string) => boolean | null;
33
28
  viewState: "IDLE" | "LOADING" | "ERROR";
34
29
  setViewState: React.Dispatch<React.SetStateAction<"IDLE" | "LOADING" | "ERROR">>;
35
30
  lastErrorEvent: WebViewError | null;
36
31
  };
32
+ export declare const versionPasses: (version: string | undefined, minimum: string | undefined) => boolean;
37
33
  //# sourceMappingURL=WebViewShared.d.ts.map