@exodus/react-native-webview 11.26.1-exodus.3 → 11.26.1-exodus.31

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.
@@ -5,12 +5,12 @@ import com.facebook.react.uimanager.events.Event
5
5
  import com.facebook.react.uimanager.events.RCTEventEmitter
6
6
 
7
7
  /**
8
- * Event emitted when a http error is received from the server.
8
+ * Event emitted when the WebView opens a new Window (i.e: target=_blank)
9
9
  */
10
- class TopHttpErrorEvent(viewId: Int, private val mEventData: WritableMap) :
11
- Event<TopHttpErrorEvent>(viewId) {
10
+ class TopOpenWindowEvent(viewId: Int, private val mEventData: WritableMap) :
11
+ Event<TopOpenWindowEvent>(viewId) {
12
12
  companion object {
13
- const val EVENT_NAME = "topHttpError"
13
+ const val EVENT_NAME = "topOpenWindow"
14
14
  }
15
15
 
16
16
  override fun getEventName(): String = EVENT_NAME
@@ -22,4 +22,4 @@ class TopHttpErrorEvent(viewId: Int, private val mEventData: WritableMap) :
22
22
  override fun dispatch(rctEventEmitter: RCTEventEmitter) =
23
23
  rctEventEmitter.receiveEvent(viewTag, eventName, mEventData)
24
24
 
25
- }
25
+ }
@@ -42,15 +42,13 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *_Nonnull)request
42
42
  @property (nonatomic, assign) BOOL messagingEnabled;
43
43
  @property (nonatomic, copy) NSString * _Nullable injectedJavaScript;
44
44
  @property (nonatomic, copy) NSString * _Nullable injectedJavaScriptBeforeContentLoaded;
45
- @property (nonatomic, assign) BOOL injectedJavaScriptForMainFrameOnly;
46
- @property (nonatomic, assign) BOOL injectedJavaScriptBeforeContentLoadedForMainFrameOnly;
47
45
  @property (nonatomic, assign) BOOL scrollEnabled;
48
46
  @property (nonatomic, assign) BOOL sharedCookiesEnabled;
49
47
  @property (nonatomic, assign) BOOL autoManageStatusBarEnabled;
50
48
  @property (nonatomic, assign) BOOL pagingEnabled;
51
49
  @property (nonatomic, assign) CGFloat decelerationRate;
52
50
  @property (nonatomic, assign) BOOL allowsInlineMediaPlayback;
53
- @property (nonatomic, assign) BOOL allowsAirPlayForMediaPlayback;
51
+ @property (nonatomic, assign) BOOL webviewDebuggingEnabled;
54
52
  @property (nonatomic, assign) BOOL bounces;
55
53
  @property (nonatomic, assign) BOOL mediaPlaybackRequiresUserAction;
56
54
  #if WEBKIT_IOS_10_APIS_AVAILABLE
@@ -64,17 +62,12 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *_Nonnull)request
64
62
  @property (nonatomic, assign) BOOL incognito;
65
63
  @property (nonatomic, assign) BOOL useSharedProcessPool;
66
64
  @property (nonatomic, copy) NSString * _Nullable userAgent;
67
- @property (nonatomic, copy) NSString * _Nullable applicationNameForUserAgent;
68
65
  @property (nonatomic, assign) BOOL cacheEnabled;
69
66
  @property (nonatomic, assign) BOOL javaScriptEnabled;
70
- @property (nonatomic, assign) BOOL allowFileAccessFromFileURLs;
71
- @property (nonatomic, assign) BOOL allowUniversalAccessFromFileURLs;
72
67
  @property (nonatomic, assign) BOOL allowsLinkPreview;
73
68
  @property (nonatomic, assign) BOOL showsHorizontalScrollIndicator;
74
69
  @property (nonatomic, assign) BOOL showsVerticalScrollIndicator;
75
70
  @property (nonatomic, assign) BOOL directionalLockEnabled;
76
- @property (nonatomic, assign) BOOL ignoreSilentHardwareSwitch;
77
- @property (nonatomic, copy) NSString * _Nullable allowingReadAccessToURL;
78
71
  @property (nonatomic, copy) NSDictionary * _Nullable basicAuthCredential;
79
72
  @property (nonatomic, assign) BOOL pullToRefreshEnabled;
80
73
  @property (nonatomic, assign) BOOL enableApplePay;
@@ -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
 
@@ -430,6 +406,13 @@ RCTAutoInsetsProtocol>
430
406
  }
431
407
  #endif
432
408
 
409
+ #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130300 || \
410
+ __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400 || \
411
+ __TV_OS_VERSION_MAX_ALLOWED >= 160400
412
+ if (@available(macOS 13.3, iOS 16.4, tvOS 16.4, *))
413
+ _webView.inspectable = _webviewDebuggingEnabled;
414
+ #endif
415
+
433
416
  [self addSubview:_webView];
434
417
  [self setHideKeyboardAccessoryView: _savedHideKeyboardAccessoryView];
435
418
  [self setKeyboardDisplayRequiresUserAction: _savedKeyboardDisplayRequiresUserAction];
@@ -455,6 +438,16 @@ RCTAutoInsetsProtocol>
455
438
  _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures;
456
439
  }
457
440
 
441
+ #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130300 || \
442
+ __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400 || \
443
+ __TV_OS_VERSION_MAX_ALLOWED >= 160400
444
+ - (void)setWebviewDebuggingEnabled:(BOOL)webviewDebuggingEnabled {
445
+ _webviewDebuggingEnabled = webviewDebuggingEnabled;
446
+ if (@available(macOS 13.3, iOS 16.4, tvOS 16.4, *))
447
+ _webView.inspectable = _webviewDebuggingEnabled;
448
+ }
449
+ #endif
450
+
458
451
  - (void)removeFromSuperview
459
452
  {
460
453
  if (_webView) {
@@ -466,10 +459,6 @@ RCTAutoInsetsProtocol>
466
459
  _webView.scrollView.delegate = nil;
467
460
  #endif // !TARGET_OS_OSX
468
461
  _webView = nil;
469
- if (_onContentProcessDidTerminate) {
470
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
471
- _onContentProcessDidTerminate(event);
472
- }
473
462
  }
474
463
 
475
464
  [super removeFromSuperview];
@@ -591,6 +580,19 @@ RCTAutoInsetsProtocol>
591
580
  }
592
581
  }
593
582
  #endif
583
+
584
+ - (NSMutableDictionary<NSString *, id> *)baseEventWithScriptMessage:(WKScriptMessage *)message {
585
+ WKSecurityOrigin *securityOrigin = message.frameInfo.securityOrigin;
586
+ NSString *protocol = securityOrigin.protocol;
587
+ NSString *host = securityOrigin.host;
588
+
589
+ NSString *messageOriginURL = [NSString stringWithFormat:@"%@://%@", protocol, host];
590
+
591
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
592
+ event[@"url"] = messageOriginURL;
593
+ return event;
594
+ }
595
+
594
596
  /**
595
597
  * This method is called whenever JavaScript running within the web view calls:
596
598
  * - window.webkit.messageHandlers[MessageHandlerName].postMessage
@@ -600,13 +602,13 @@ RCTAutoInsetsProtocol>
600
602
  {
601
603
  if ([message.name isEqualToString:HistoryShimName]) {
602
604
  if (_onLoadingFinish) {
603
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
605
+ NSMutableDictionary<NSString *, id> *event = [self baseEventWithScriptMessage:message];
604
606
  [event addEntriesFromDictionary: @{@"navigationType": message.body}];
605
607
  _onLoadingFinish(event);
606
608
  }
607
609
  } else if ([message.name isEqualToString:MessageHandlerName]) {
608
610
  if (_onMessage) {
609
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
611
+ NSMutableDictionary<NSString *, id> *event = [self baseEventWithScriptMessage:message];
610
612
  [event addEntriesFromDictionary: @{@"data": message.body}];
611
613
  _onMessage(event);
612
614
  }
@@ -624,17 +626,6 @@ RCTAutoInsetsProtocol>
624
626
  }
625
627
  }
626
628
 
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
629
  #if !TARGET_OS_OSX
639
630
  - (void)setContentInset:(UIEdgeInsets)contentInset
640
631
  {
@@ -682,8 +673,10 @@ RCTAutoInsetsProtocol>
682
673
  [_webView loadRequest:request];
683
674
  }
684
675
  else {
685
- NSURL* readAccessUrl = _allowingReadAccessToURL ? [RCTConvert NSURL:_allowingReadAccessToURL] : request.URL;
686
- [_webView loadFileURL:request.URL allowingReadAccessToURL:readAccessUrl];
676
+ // WARNING: UNREACHABLE, non-host loads (file urls)
677
+ // Clear the webview
678
+ [_webView loadHTMLString:@"" baseURL:nil];
679
+ return;
687
680
  }
688
681
  }];
689
682
  }
@@ -872,7 +865,7 @@ RCTAutoInsetsProtocol>
872
865
  {
873
866
  NSDictionary *eventInitDict = @{@"data": message};
874
867
  NSString *source = [NSString
875
- stringWithFormat:@"window.dispatchEvent(new MessageEvent('message', %@));",
868
+ stringWithFormat:@"document.dispatchEvent(new MessageEvent('message', %@));",
876
869
  RCTJSONStringify(eventInitDict, NULL)
877
870
  ];
878
871
  [self injectJavaScript: source];
@@ -1147,10 +1140,6 @@ RCTAutoInsetsProtocol>
1147
1140
  - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
1148
1141
  {
1149
1142
  RCTLogWarn(@"Webview Process Terminated");
1150
- if (_onContentProcessDidTerminate) {
1151
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1152
- _onContentProcessDidTerminate(event);
1153
- }
1154
1143
  }
1155
1144
 
1156
1145
  /**
@@ -1162,36 +1151,19 @@ RCTAutoInsetsProtocol>
1162
1151
  decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
1163
1152
  {
1164
1153
  WKNavigationResponsePolicy policy = WKNavigationResponsePolicyAllow;
1165
- if (_onHttpError && navigationResponse.forMainFrame) {
1154
+ if (navigationResponse.forMainFrame) {
1166
1155
  if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
1167
1156
  NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
1168
1157
  NSInteger statusCode = response.statusCode;
1169
1158
 
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
1159
  NSString *disposition = nil;
1181
1160
  if (@available(iOS 13, *)) {
1182
1161
  disposition = [response valueForHTTPHeaderField:@"Content-Disposition"];
1183
1162
  }
1184
1163
  BOOL isAttachment = disposition != nil && [disposition hasPrefix:@"attachment"];
1185
1164
  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
- }
1165
+ policy = WKNavigationResponsePolicyCancel;
1166
+ // File downloads are cancelled
1195
1167
  }
1196
1168
  }
1197
1169
  }
@@ -1252,37 +1224,6 @@ RCTAutoInsetsProtocol>
1252
1224
  }];
1253
1225
  }
1254
1226
 
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
1227
  /**
1287
1228
  * Called when the navigation is complete.
1288
1229
  * @see https://fburl.com/rtys6jlb
@@ -1290,10 +1231,6 @@ RCTAutoInsetsProtocol>
1290
1231
  - (void)webView:(WKWebView *)webView
1291
1232
  didFinishNavigation:(WKNavigation *)navigation
1292
1233
  {
1293
- if (_ignoreSilentHardwareSwitch) {
1294
- [self forceIgnoreSilentHardwareSwitch:true];
1295
- }
1296
-
1297
1234
  if (_onLoadingFinish) {
1298
1235
  _onLoadingFinish([self baseEvent]);
1299
1236
  }
@@ -1389,7 +1326,7 @@ didFinishNavigation:(WKNavigation *)navigation
1389
1326
 
1390
1327
  self.atEndScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source
1391
1328
  injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
1392
- forMainFrameOnly:_injectedJavaScriptForMainFrameOnly];
1329
+ forMainFrameOnly:YES];
1393
1330
 
1394
1331
  if(_webView != nil){
1395
1332
  [self resetupScripts:_webView.configuration];
@@ -1401,23 +1338,13 @@ didFinishNavigation:(WKNavigation *)navigation
1401
1338
 
1402
1339
  self.atStartScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source
1403
1340
  injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1404
- forMainFrameOnly:_injectedJavaScriptBeforeContentLoadedForMainFrameOnly];
1341
+ forMainFrameOnly:YES];
1405
1342
 
1406
1343
  if(_webView != nil){
1407
1344
  [self resetupScripts:_webView.configuration];
1408
1345
  }
1409
1346
  }
1410
1347
 
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
1348
  - (void)setMessagingEnabled:(BOOL)messagingEnabled {
1422
1349
  _messagingEnabled = messagingEnabled;
1423
1350
 
@@ -1434,9 +1361,6 @@ didFinishNavigation:(WKNavigation *)navigation
1434
1361
  "};", MessageHandlerName, MessageHandlerName
1435
1362
  ]
1436
1363
  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
1364
  forMainFrameOnly:YES
1441
1365
  ] :
1442
1366
  nil;
@@ -54,23 +54,16 @@ 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)
66
+ RCT_EXPORT_VIEW_PROPERTY(webviewDebuggingEnabled, BOOL)
74
67
  RCT_EXPORT_VIEW_PROPERTY(mediaPlaybackRequiresUserAction, BOOL)
75
68
  #if WEBKIT_IOS_10_APIS_AVAILABLE
76
69
  RCT_EXPORT_VIEW_PROPERTY(dataDetectorTypes, WKDataDetectorTypes)
@@ -82,10 +75,8 @@ RCT_EXPORT_VIEW_PROPERTY(hideKeyboardAccessoryView, BOOL)
82
75
  RCT_EXPORT_VIEW_PROPERTY(allowsBackForwardNavigationGestures, BOOL)
83
76
  RCT_EXPORT_VIEW_PROPERTY(incognito, BOOL)
84
77
  RCT_EXPORT_VIEW_PROPERTY(pagingEnabled, BOOL)
85
- RCT_EXPORT_VIEW_PROPERTY(applicationNameForUserAgent, NSString)
86
78
  RCT_EXPORT_VIEW_PROPERTY(cacheEnabled, BOOL)
87
79
  RCT_EXPORT_VIEW_PROPERTY(allowsLinkPreview, BOOL)
88
- RCT_EXPORT_VIEW_PROPERTY(allowingReadAccessToURL, NSString)
89
80
  RCT_EXPORT_VIEW_PROPERTY(basicAuthCredential, NSDictionary)
90
81
 
91
82
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
@@ -269,8 +260,8 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
269
260
  _shouldStartLoadLock = nil;
270
261
  return returnValue;
271
262
  } else {
272
- RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES");
273
- return YES;
263
+ RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to NO");
264
+ return NO;
274
265
  }
275
266
  }
276
267
 
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, defaultDeeplinkWhitelist, 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, deeplinkWhitelist = defaultDeeplinkWhitelist, setBuiltInZoomControls = true, setDisplayZoomControls = false, nestedScrollEnabled = false, startInLoadingState, onLoadStart, onError, onLoad, onLoadEnd, onMessage: onMessageProp, onOpenWindow: onOpenWindowProp, renderLoading, renderError, style, containerStyle, source, onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, validateMeta, validateData, minimumChromeVersion, unsupportedVersionComponent: UnsupportedVersionComponent, ...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,35 +43,37 @@ 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, onOpenWindow, passesWhitelist } = useWebWiewLogic({
44
47
  onLoad,
45
48
  onError,
46
- onHttpErrorProp,
47
49
  onLoadEnd,
48
- onLoadProgress,
49
50
  onLoadStart,
50
- onRenderProcessGoneProp,
51
51
  onMessageProp,
52
+ onOpenWindowProp,
52
53
  startInLoadingState,
53
54
  originWhitelist,
55
+ deeplinkWhitelist,
54
56
  onShouldStartLoadWithRequestProp,
55
57
  onShouldStartLoadWithRequestCallback,
58
+ validateMeta,
59
+ validateData,
56
60
  });
57
61
  useImperativeHandle(ref, () => ({
58
- goForward: () => Commands.goForward(webViewRef.current),
59
- goBack: () => Commands.goBack(webViewRef.current),
62
+ goForward: () => webViewRef.current && Commands.goForward(webViewRef.current),
63
+ goBack: () => webViewRef.current && Commands.goBack(webViewRef.current),
60
64
  reload: () => {
61
65
  setViewState('LOADING');
62
- Commands.reload(webViewRef.current);
66
+ if (webViewRef.current) {
67
+ Commands.reload(webViewRef.current);
68
+ }
63
69
  },
64
- stopLoading: () => Commands.stopLoading(webViewRef.current),
65
- postMessage: (data) => Commands.postMessage(webViewRef.current, data),
70
+ stopLoading: () => webViewRef.current && Commands.stopLoading(webViewRef.current),
71
+ postMessage: (data) => webViewRef.current && Commands.postMessage(webViewRef.current, data),
66
72
  // injectJavaScript: (data: string) => Commands.injectJavaScript(webViewRef.current, data),
67
- requestFocus: () => Commands.requestFocus(webViewRef.current),
68
- clearFormData: () => Commands.clearFormData(webViewRef.current),
69
- clearCache: (includeDiskFiles) => Commands.clearCache(webViewRef.current, includeDiskFiles),
70
- clearHistory: () => Commands.clearHistory(webViewRef.current),
73
+ requestFocus: () => webViewRef.current && Commands.requestFocus(webViewRef.current),
74
+ clearFormData: () => webViewRef.current && Commands.clearFormData(webViewRef.current),
75
+ clearCache: (includeDiskFiles) => webViewRef.current && Commands.clearCache(webViewRef.current, includeDiskFiles),
76
+ clearHistory: () => webViewRef.current && Commands.clearHistory(webViewRef.current),
71
77
  }), [setViewState, webViewRef]);
72
78
  const directEventCallbacks = useMemo(() => ({
73
79
  onShouldStartLoadWithRequest,
@@ -76,6 +82,23 @@ const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnab
76
82
  useEffect(() => {
77
83
  BatchedBridge.registerCallableModule(messagingModuleName, directEventCallbacks);
78
84
  }, [messagingModuleName, directEventCallbacks]);
85
+ const [userAgent, setUserAgent] = useState();
86
+ useEffect(() => {
87
+ getUserAgent().then(setUserAgent);
88
+ }, []);
89
+ if (!userAgent)
90
+ return null; // stop the rendering until userAgent is known
91
+ const version = (_a = userAgent.match(/chrome\/((?:[0-9]+\.)+[0-9]+)/i)) === null || _a === void 0 ? void 0 : _a[1];
92
+ if (!(versionPasses(version, minimumChromeVersion) && versionPasses(version, hardMinimumChromeVersion))) {
93
+ if (UnsupportedVersionComponent) {
94
+ return <UnsupportedVersionComponent />;
95
+ }
96
+ return (<View style={{ alignSelf: 'flex-start' }}>
97
+ <Text style={{ color: 'red' }}>
98
+ Chrome version is outdated and insecure. Update it to continue.
99
+ </Text>
100
+ </View>);
101
+ }
79
102
  let otherView = null;
80
103
  if (viewState === 'LOADING') {
81
104
  otherView = (renderLoading || defaultRenderLoading)();
@@ -97,10 +120,14 @@ const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnab
97
120
  console.warn('WebView: `source.body` is not supported when using GET.');
98
121
  }
99
122
  }
123
+ if (typeof source === "object" && 'uri' in source && !passesWhitelist(source.uri)) {
124
+ // eslint-disable-next-line
125
+ source = { uri: "about:blank" };
126
+ }
100
127
  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}
128
+ const webView = <NativeWebView key="webViewKey" {...otherProps} messagingEnabled={typeof onMessageProp === 'function'} messagingModuleName={messagingModuleName} onLoadingError={onLoadingError} onLoadingFinish={onLoadingFinish} onLoadingProgress={onLoadingProgress} onLoadingStart={onLoadingStart} onMessage={onMessage} onOpenWindow={onOpenWindow} onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} ref={webViewRef}
102
129
  // 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}/>;
130
+ 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
131
  return (<View style={webViewContainerStyle}>
105
132
  {webView}
106
133
  {otherView}