@exodus/react-native-webview 11.26.1-exodus.9 → 13.16.0-exodus.1

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 (94) hide show
  1. package/README.md +36 -63
  2. package/android/build.gradle +83 -110
  3. package/android/gradle.properties +3 -4
  4. package/android/src/main/AndroidManifest.xml +12 -0
  5. package/android/src/main/AndroidManifestNew.xml +26 -0
  6. package/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java +11 -0
  7. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java +407 -0
  8. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java +468 -0
  9. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +330 -0
  10. package/android/src/main/java/com/reactnativecommunity/webview/{WebViewConfig.java → RNCWebViewConfig.java} +3 -4
  11. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java +1 -1
  12. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt +746 -0
  13. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMessagingModule.kt +9 -0
  14. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java +554 -0
  15. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java +57 -12
  16. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewWrapper.kt +39 -0
  17. package/android/src/main/java/com/reactnativecommunity/webview/events/SubResourceErrorEvent.kt +25 -0
  18. package/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt +24 -0
  19. package/android/src/main/java/com/reactnativecommunity/webview/events/TopHttpErrorEvent.kt +25 -0
  20. package/android/src/main/java/com/reactnativecommunity/webview/events/TopNewWindowEvent.kt +25 -0
  21. package/android/src/main/java/com/reactnativecommunity/webview/events/TopRenderProcessGoneEvent.kt +25 -0
  22. package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +570 -0
  23. package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java +57 -0
  24. package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java +341 -0
  25. package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java +59 -0
  26. package/apple/RCTConvert+WKDataDetectorTypes.h +11 -0
  27. package/apple/RCTConvert+WKDataDetectorTypes.m +27 -0
  28. package/apple/RNCWebView.h +26 -100
  29. package/apple/RNCWebView.mm +555 -0
  30. package/apple/RNCWebViewDecisionManager.h +20 -0
  31. package/apple/RNCWebViewDecisionManager.m +47 -0
  32. package/apple/RNCWebViewImpl.h +164 -0
  33. package/apple/{RNCWebView.m → RNCWebViewImpl.m} +802 -225
  34. package/apple/RNCWebViewManager.h +4 -8
  35. package/apple/RNCWebViewManager.mm +221 -0
  36. package/apple/RNCWebViewModule.h +23 -0
  37. package/apple/RNCWebViewModule.mm +34 -0
  38. package/index.d.ts +2 -3
  39. package/lib/NativeRNCWebViewModule.d.ts +8 -0
  40. package/lib/NativeRNCWebViewModule.js +1 -0
  41. package/lib/RNCWebViewNativeComponent.d.ts +245 -0
  42. package/lib/RNCWebViewNativeComponent.js +1 -0
  43. package/lib/WebView.android.d.ts +0 -1
  44. package/lib/WebView.android.js +1 -135
  45. package/lib/WebView.d.ts +2 -3
  46. package/lib/WebView.ios.d.ts +0 -1
  47. package/lib/WebView.ios.js +1 -114
  48. package/lib/WebView.js +1 -11
  49. package/lib/WebView.macos.d.ts +6 -0
  50. package/lib/WebView.macos.js +1 -0
  51. package/lib/WebView.styles.d.ts +37 -11
  52. package/lib/WebView.styles.js +1 -33
  53. package/lib/WebView.windows.d.ts +17 -0
  54. package/lib/WebView.windows.js +1 -0
  55. package/lib/WebViewNativeComponent.macos.d.ts +3 -0
  56. package/lib/WebViewNativeComponent.macos.js +1 -0
  57. package/lib/WebViewNativeComponent.windows.d.ts +3 -0
  58. package/lib/WebViewNativeComponent.windows.js +1 -0
  59. package/lib/WebViewShared.d.ts +30 -9
  60. package/lib/WebViewShared.js +1 -174
  61. package/lib/WebViewTypes.d.ts +514 -98
  62. package/lib/WebViewTypes.js +1 -6
  63. package/lib/index.d.ts +0 -1
  64. package/lib/index.js +1 -3
  65. package/lib/validation.d.ts +3 -0
  66. package/lib/validation.js +1 -0
  67. package/package.json +57 -33
  68. package/react-native-webview.podspec +32 -5
  69. package/react-native.config.js +22 -18
  70. package/src/NativeRNCWebViewModule.ts +13 -0
  71. package/src/RNCWebViewNativeComponent.ts +348 -0
  72. package/src/WebView.android.tsx +345 -0
  73. package/src/WebView.ios.tsx +341 -0
  74. package/src/WebView.macos.tsx +252 -0
  75. package/src/WebView.styles.ts +41 -0
  76. package/src/WebView.tsx +25 -0
  77. package/src/WebView.windows.tsx +217 -0
  78. package/src/WebViewNativeComponent.macos.ts +7 -0
  79. package/src/WebViewNativeComponent.windows.ts +8 -0
  80. package/src/WebViewShared.tsx +476 -0
  81. package/src/WebViewTypes.ts +1402 -0
  82. package/src/__tests__/WebViewShared-test.js +323 -0
  83. package/src/__tests__/__snapshots__/WebViewShared-test.js.snap +8 -0
  84. package/src/__tests__/validation-test.js +38 -0
  85. package/src/index.ts +4 -0
  86. package/src/validation.ts +20 -0
  87. package/android/.editorconfig +0 -6
  88. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +0 -1408
  89. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java +0 -506
  90. package/apple/RNCWebViewManager.m +0 -278
  91. package/lib/WebViewNativeComponent.android.d.ts +0 -4
  92. package/lib/WebViewNativeComponent.android.js +0 -3
  93. package/lib/WebViewNativeComponent.ios.d.ts +0 -4
  94. package/lib/WebViewNativeComponent.ios.js +0 -3
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- #import "RNCWebView.h"
8
+ #import "RNCWebViewImpl.h"
9
9
  #import <React/RCTConvert.h>
10
10
  #import <React/RCTAutoInsetsProtocol.h>
11
11
  #import "RNCWKProcessPoolManager.h"
@@ -22,22 +22,24 @@ static NSString *const HistoryShimName = @"ReactNativeHistoryShim";
22
22
  static NSString *const MessageHandlerName = @"ReactNativeWebView";
23
23
  static NSURLCredential* clientAuthenticationCredential;
24
24
  static NSDictionary* customCertificatesForHost;
25
+ // Exodus: Camera permission whitelist for security
26
+ static NSSet *cameraPermissionOriginWhitelist;
25
27
 
26
28
  NSString *const CUSTOM_SELECTOR = @"_CUSTOM_SELECTOR_";
27
29
 
28
- #if !TARGET_OS_OSX
30
+ #if TARGET_OS_IOS
29
31
  // runtime trick to remove WKWebView keyboard default toolbar
30
32
  // see: http://stackoverflow.com/questions/19033292/ios-7-uiwebview-keyboard-issue/19042279#19042279
31
- @interface __SwizzleHelperWK : UIView
33
+ @interface _SwizzleHelperWK : UIView
32
34
  @property (nonatomic, copy) WKWebView *webView;
33
35
  @end
34
- @implementation __SwizzleHelperWK
36
+ @implementation _SwizzleHelperWK
35
37
  -(id)inputAccessoryView
36
38
  {
37
39
  if (_webView == nil) {
38
40
  return nil;
39
41
  }
40
-
42
+
41
43
  if ([_webView respondsToSelector:@selector(inputAssistantItem)]) {
42
44
  UITextInputAssistantItem *inputAssistantItem = [_webView inputAssistantItem];
43
45
  inputAssistantItem.leadingBarButtonGroups = @[];
@@ -46,33 +48,91 @@ NSString *const CUSTOM_SELECTOR = @"_CUSTOM_SELECTOR_";
46
48
  return nil;
47
49
  }
48
50
  @end
51
+ #endif // TARGET_OS_IOS
52
+
53
+ @interface RNCWKWebView : WKWebView
54
+ #if !TARGET_OS_OSX
55
+ @property (nonatomic, copy) NSArray<NSDictionary *> * _Nullable menuItems;
56
+ @property (nonatomic, copy) NSArray<NSString *> * _Nullable suppressMenuItems;
49
57
  #endif // !TARGET_OS_OSX
58
+ @end
59
+ @implementation RNCWKWebView
60
+ #if !TARGET_OS_OSX
61
+ - (NSString *)stringFromAction:(SEL) action {
62
+ NSString *sel = NSStringFromSelector(action);
63
+
64
+ NSDictionary *map = @{
65
+ @"cut:": @"cut",
66
+ @"copy:": @"copy",
67
+ @"paste:": @"paste",
68
+ @"delete:": @"delete",
69
+ @"select:": @"select",
70
+ @"selectAll:": @"selectAll",
71
+ @"_promptForReplace:": @"replace",
72
+ @"_define:": @"lookup",
73
+ @"_translate:": @"translate",
74
+ @"toggleBoldface:": @"bold",
75
+ @"toggleItalics:": @"italic",
76
+ @"toggleUnderline:": @"underline",
77
+ @"_share:": @"share",
78
+ };
79
+
80
+ return map[sel] ?: sel;
81
+ }
50
82
 
51
- @interface RNCWebView () <WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, WKHTTPCookieStoreObserver,
83
+ - (BOOL)canPerformAction:(SEL)action
84
+ withSender:(id)sender{
85
+ if(self.suppressMenuItems) {
86
+ NSString * sel = [self stringFromAction:action];
87
+ if ([self.suppressMenuItems containsObject: sel]) {
88
+ return NO;
89
+ }
90
+ }
91
+
92
+ if (!self.menuItems) {
93
+ return [super canPerformAction:action withSender:sender];
94
+ }
95
+
96
+ return NO;
97
+ }
98
+ - (void)buildMenuWithBuilder:(id<UIMenuBuilder>)builder API_AVAILABLE(ios(13.0)) {
99
+ if (@available(iOS 16.0, *)) {
100
+ if(self.menuItems){
101
+ [builder removeMenuForIdentifier:UIMenuLookup];
102
+ }
103
+ }
104
+ [super buildMenuWithBuilder:builder];
105
+ }
106
+ #else // TARGET_OS_OSX
107
+ - (void)scrollWheel:(NSEvent *)theEvent {
108
+ RNCWebViewImpl *rncWebView = (RNCWebViewImpl *)[self superview];
109
+ RCTAssert([rncWebView isKindOfClass:[rncWebView class]], @"superview must be an RNCWebViewImpl");
110
+ if (![rncWebView scrollEnabled]) {
111
+ [[self nextResponder] scrollWheel:theEvent];
112
+ return;
113
+ }
114
+ [super scrollWheel:theEvent];
115
+ }
116
+ #endif // TARGET_OS_OSX
117
+ @end
118
+
119
+ @interface RNCWebViewImpl () <WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, WKHTTPCookieStoreObserver,
52
120
  #if !TARGET_OS_OSX
53
121
  UIScrollViewDelegate,
122
+ UIGestureRecognizerDelegate,
54
123
  #endif // !TARGET_OS_OSX
55
124
  RCTAutoInsetsProtocol>
56
125
 
57
- @property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
58
- @property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
59
- @property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
60
- @property (nonatomic, copy) RCTDirectEventBlock onLoadingProgress;
61
- @property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
62
- @property (nonatomic, copy) RCTDirectEventBlock onMessage;
63
- @property (nonatomic, copy) RCTDirectEventBlock onScroll;
64
- @property (nonatomic, copy) RCTDirectEventBlock onContentProcessDidTerminate;
65
- #if !TARGET_OS_OSX
66
- @property (nonatomic, copy) WKWebView *webView;
67
- #else
68
126
  @property (nonatomic, copy) RNCWKWebView *webView;
69
- #endif // !TARGET_OS_OSX
70
127
  @property (nonatomic, strong) WKUserScript *postMessageScript;
128
+ @property (nonatomic, strong) WKUserScript *injectedObjectJsonScript;
71
129
  @property (nonatomic, strong) WKUserScript *atStartScript;
72
130
  @property (nonatomic, strong) WKUserScript *atEndScript;
131
+ // Exodus: Camera permission whitelist for security
132
+ @property (nonatomic, strong) NSArray<NSString *> *cameraPermissionOriginWhitelist;
73
133
  @end
74
134
 
75
- @implementation RNCWebView
135
+ @implementation RNCWebViewImpl
76
136
  {
77
137
  #if !TARGET_OS_OSX
78
138
  UIColor * _savedBackgroundColor;
@@ -81,7 +141,7 @@ RCTAutoInsetsProtocol>
81
141
  #endif // !TARGET_OS_OSX
82
142
  BOOL _savedHideKeyboardAccessoryView;
83
143
  BOOL _savedKeyboardDisplayRequiresUserAction;
84
-
144
+
85
145
  // Workaround for StatusBar appearance bug for iOS 12
86
146
  // https://github.com/react-native-webview/react-native-webview/issues/62
87
147
  BOOL _isFullScreenVideoOpen;
@@ -89,7 +149,7 @@ RCTAutoInsetsProtocol>
89
149
  UIStatusBarStyle _savedStatusBarStyle;
90
150
  #endif // !TARGET_OS_OSX
91
151
  BOOL _savedStatusBarHidden;
92
-
152
+
93
153
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
94
154
  UIScrollViewContentInsetAdjustmentBehavior _savedContentInsetAdjustmentBehavior;
95
155
  #endif
@@ -109,32 +169,57 @@ RCTAutoInsetsProtocol>
109
169
  _bounces = YES;
110
170
  _scrollEnabled = YES;
111
171
  _showsHorizontalScrollIndicator = YES;
172
+ _javaScriptEnabled = YES;
173
+ _allowsLinkPreview = YES;
112
174
  _showsVerticalScrollIndicator = YES;
113
175
  _directionalLockEnabled = YES;
176
+ _useSharedProcessPool = YES;
177
+ _cacheEnabled = YES;
178
+ _mediaPlaybackRequiresUserAction = YES;
114
179
  _automaticallyAdjustContentInsets = YES;
115
180
  _autoManageStatusBarEnabled = YES;
116
181
  _contentInset = UIEdgeInsetsZero;
117
182
  _savedKeyboardDisplayRequiresUserAction = YES;
118
- #if !TARGET_OS_OSX
119
- _savedStatusBarStyle = RCTSharedApplication().statusBarStyle;
120
- _savedStatusBarHidden = RCTSharedApplication().statusBarHidden;
121
- #endif // !TARGET_OS_OSX
122
183
  _injectedJavaScript = nil;
184
+ _injectedJavaScriptForMainFrameOnly = YES;
123
185
  _injectedJavaScriptBeforeContentLoaded = nil;
124
-
186
+ _injectedJavaScriptBeforeContentLoadedForMainFrameOnly = YES;
187
+ _enableApplePay = NO;
188
+ #if TARGET_OS_IOS
189
+ _savedStatusBarStyle = RCTSharedApplication().statusBarStyle;
190
+ _savedStatusBarHidden = RCTSharedApplication().statusBarHidden;
191
+ #endif // TARGET_OS_IOS
125
192
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
126
193
  _savedContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
127
194
  #endif
128
195
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* __IPHONE_13_0 */
129
196
  _savedAutomaticallyAdjustsScrollIndicatorInsets = NO;
197
+ _fraudulentWebsiteWarningEnabled = YES;
198
+ #endif
199
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500 /* __IPHONE_13_0 */
200
+ _textInteractionEnabled = YES;
130
201
  #endif
131
- _enableApplePay = NO;
132
202
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 /* iOS 15 */
133
203
  _mediaCapturePermissionGrantType = RNCWebViewPermissionGrantType_Prompt;
204
+ #endif
205
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000 /* iOS 15 */
206
+ if (@available(iOS 16.0, *)) {
207
+ _editMenuInteraction = [[UIEditMenuInteraction alloc] initWithDelegate:self];
208
+ [self addInteraction:_editMenuInteraction];
209
+ }
134
210
  #endif
135
211
  }
136
-
137
- #if !TARGET_OS_OSX
212
+
213
+ #if TARGET_OS_IOS
214
+ [[NSNotificationCenter defaultCenter]addObserver:self
215
+ selector:@selector(appDidBecomeActive)
216
+ name:UIApplicationDidBecomeActiveNotification
217
+ object:nil];
218
+
219
+ [[NSNotificationCenter defaultCenter]addObserver:self
220
+ selector:@selector(appWillResignActive)
221
+ name:UIApplicationWillResignActiveNotification
222
+ object:nil];
138
223
  if (@available(iOS 12.0, *)) {
139
224
  // Workaround for a keyboard dismissal bug present in iOS 12
140
225
  // https://openradar.appspot.com/radar?id=5018321736957952
@@ -146,21 +231,21 @@ RCTAutoInsetsProtocol>
146
231
  addObserver:self
147
232
  selector:@selector(keyboardWillShow)
148
233
  name:UIKeyboardWillShowNotification object:nil];
149
-
234
+
150
235
  // Workaround for StatusBar appearance bug for iOS 12
151
236
  // https://github.com/react-native-webview/react-native-webview/issues/62
152
237
  [[NSNotificationCenter defaultCenter] addObserver:self
153
238
  selector:@selector(showFullScreenVideoStatusBars)
154
239
  name:UIWindowDidBecomeVisibleNotification
155
240
  object:nil];
156
-
241
+
157
242
  [[NSNotificationCenter defaultCenter] addObserver:self
158
243
  selector:@selector(hideFullScreenVideoStatusBars)
159
244
  name:UIWindowDidBecomeHiddenNotification
160
245
  object:nil];
161
-
246
+
162
247
  }
163
- #endif // !TARGET_OS_OSX
248
+ #endif // TARGET_OS_IOS
164
249
  return self;
165
250
  }
166
251
 
@@ -177,29 +262,54 @@ RCTAutoInsetsProtocol>
177
262
  // Listener for long presses
178
263
  - (void)startLongPress:(UILongPressGestureRecognizer *)pressSender
179
264
  {
180
- // When a long press ends, bring up our custom UIMenu
181
- if(pressSender.state == UIGestureRecognizerStateEnded) {
182
- if (!self.menuItems || self.menuItems.count == 0) {
183
- return;
265
+ if (pressSender.state != UIGestureRecognizerStateEnded || !self.menuItems) {
266
+ return;
184
267
  }
185
- UIMenuController *menuController = [UIMenuController sharedMenuController];
186
- NSMutableArray *menuControllerItems = [NSMutableArray arrayWithCapacity:self.menuItems.count];
187
-
188
- for(NSDictionary *menuItem in self.menuItems) {
189
- NSString *menuItemLabel = [RCTConvert NSString:menuItem[@"label"]];
190
- NSString *menuItemKey = [RCTConvert NSString:menuItem[@"key"]];
191
- NSString *sel = [NSString stringWithFormat:@"%@%@", CUSTOM_SELECTOR, menuItemKey];
192
- UIMenuItem *item = [[UIMenuItem alloc] initWithTitle: menuItemLabel
193
- action: NSSelectorFromString(sel)];
194
-
195
- [menuControllerItems addObject: item];
268
+ if (@available(iOS 16.0, *)) {
269
+ CGPoint location = [pressSender locationInView:self];
270
+ UIEditMenuConfiguration *config = [UIEditMenuConfiguration configurationWithIdentifier:nil sourcePoint:location];
271
+ [_editMenuInteraction presentEditMenuWithConfiguration:config];
272
+ } else {
273
+ // When a long press ends, bring up our custom UIMenu if defined
274
+ if (self.menuItems.count == 0) {
275
+ UIMenuController *menuController = [UIMenuController sharedMenuController];
276
+ menuController.menuItems = nil;
277
+ [menuController showMenuFromView:self rect:self.bounds];
278
+ return;
279
+ }
280
+
281
+ UIMenuController *menuController = [UIMenuController sharedMenuController];
282
+ NSMutableArray *menuControllerItems = [NSMutableArray arrayWithCapacity:self.menuItems.count];
283
+
284
+ for(NSDictionary *menuItem in self.menuItems) {
285
+ NSString *menuItemLabel = [RCTConvert NSString:menuItem[@"label"]];
286
+ NSString *menuItemKey = [RCTConvert NSString:menuItem[@"key"]];
287
+ NSString *sel = [NSString stringWithFormat:@"%@%@", CUSTOM_SELECTOR, menuItemKey];
288
+ UIMenuItem *item = [[UIMenuItem alloc] initWithTitle: menuItemLabel
289
+ action: NSSelectorFromString(sel)];
290
+ [menuControllerItems addObject: item];
291
+ }
292
+ menuController.menuItems = menuControllerItems;
293
+ [menuController showMenuFromView:self rect:self.bounds];
196
294
  }
197
-
198
- menuController.menuItems = menuControllerItems;
199
- [menuController setMenuVisible:YES animated:YES];
200
- }
201
295
  }
202
296
 
297
+ - (UIMenu *)editMenuInteraction:(UIEditMenuInteraction *)interaction menuForConfiguration:(UIEditMenuConfiguration *)configuration suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0))
298
+ {
299
+ NSMutableArray<UICommand *> *menuItems = [NSMutableArray new];
300
+ for(NSDictionary *menuItem in self.menuItems) {
301
+ NSString *menuItemLabel = [RCTConvert NSString:menuItem[@"label"]];
302
+ NSString *menuItemKey = [RCTConvert NSString:menuItem[@"key"]];
303
+ NSString *sel = [NSString stringWithFormat:@"%@%@", CUSTOM_SELECTOR, menuItemKey];
304
+ UICommand *command = [UICommand commandWithTitle:menuItemLabel
305
+ image:nil
306
+ action:NSSelectorFromString(sel)
307
+ propertyList:nil];
308
+ [menuItems addObject:command];
309
+ }
310
+ UIMenu *menu = [UIMenu menuWithChildren:menuItems];
311
+ return menu;
312
+ }
203
313
  #endif // !TARGET_OS_OSX
204
314
 
205
315
  - (void)dealloc
@@ -271,7 +381,7 @@ RCTAutoInsetsProtocol>
271
381
  NSString *sel = NSStringFromSelector(action);
272
382
  // Do any of them have our custom keys?
273
383
  NSRange match = [sel rangeOfString:CUSTOM_SELECTOR];
274
-
384
+
275
385
  if (match.location == 0) {
276
386
  return YES;
277
387
  }
@@ -284,32 +394,75 @@ RCTAutoInsetsProtocol>
284
394
  - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
285
395
  {
286
396
  if (!navigationAction.targetFrame.isMainFrame) {
287
- [webView loadRequest:navigationAction.request];
397
+ NSURL *url = navigationAction.request.URL;
398
+
399
+ if (_onOpenWindow) {
400
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
401
+ [event addEntriesFromDictionary: @{@"targetUrl": url.absoluteString}];
402
+ _onOpenWindow(event);
403
+ } else {
404
+ [webView loadRequest:navigationAction.request];
405
+ }
288
406
  }
289
407
  return nil;
290
408
  }
291
409
 
410
+ /**
411
+ * Enables file input on macos, see https://developer.apple.com/documentation/webkit/wkuidelegate/1641952-webview
412
+ */
413
+ #if TARGET_OS_OSX
414
+ - (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> *URLs))completionHandler
415
+ {
416
+ NSOpenPanel *openPanel = [NSOpenPanel openPanel];
417
+ openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection;
418
+ [openPanel beginSheetModalForWindow:webView.window completionHandler:^(NSInteger result) {
419
+ if (result == NSModalResponseOK)
420
+ completionHandler(openPanel.URLs);
421
+ else
422
+ completionHandler(nil);
423
+ }];
424
+ }
425
+ #endif //Target_OS_OSX
426
+
292
427
  - (WKWebViewConfiguration *)setUpWkWebViewConfig
293
428
  {
294
429
  WKWebViewConfiguration *wkWebViewConfig = [WKWebViewConfiguration new];
295
430
  WKPreferences *prefs = [[WKPreferences alloc]init];
431
+ BOOL _prefsUsed = NO;
296
432
  if (!_javaScriptEnabled) {
297
433
  prefs.javaScriptEnabled = NO;
434
+ _prefsUsed = YES;
435
+ }
436
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */
437
+ if (@available(iOS 13.0, *)) {
438
+ if (!_fraudulentWebsiteWarningEnabled) {
439
+ prefs.fraudulentWebsiteWarningEnabled = NO;
440
+ _prefsUsed = YES;
441
+ }
442
+ }
443
+ #endif
444
+ if (_allowUniversalAccessFromFileURLs) {
445
+ [wkWebViewConfig setValue:@TRUE forKey:@"allowUniversalAccessFromFileURLs"];
446
+ }
447
+ if (_allowFileAccessFromFileURLs) {
448
+ [prefs setValue:@TRUE forKey:@"allowFileAccessFromFileURLs"];
449
+ _prefsUsed = YES;
450
+ }
451
+ if (_javaScriptCanOpenWindowsAutomatically) {
452
+ [prefs setValue:@TRUE forKey:@"javaScriptCanOpenWindowsAutomatically"];
453
+ _prefsUsed = YES;
298
454
  }
299
-
300
- // NOTE: defaults, recheck?
301
- // [wkWebViewConfig setValue:@FALSE forKey:@"allowUniversalAccessFromFileURLs"];
302
- // [prefs setValue:@FALSE forKey:@"allowFileAccessFromFileURLs"];
303
-
304
- [prefs setValue:@FALSE forKey:@"javaScriptCanOpenWindowsAutomatically"];
305
455
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500 /* iOS 14.5 */
306
456
  if (@available(iOS 14.5, *)) {
307
457
  if (!_textInteractionEnabled) {
308
458
  [prefs setValue:@FALSE forKey:@"textInteractionEnabled"];
459
+ _prefsUsed = YES;
309
460
  }
310
461
  }
311
462
  #endif
312
- wkWebViewConfig.preferences = prefs;
463
+ if (_prefsUsed) {
464
+ wkWebViewConfig.preferences = prefs;
465
+ }
313
466
  if (_incognito) {
314
467
  wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
315
468
  } else if (_cacheEnabled) {
@@ -319,7 +472,7 @@ RCTAutoInsetsProtocol>
319
472
  wkWebViewConfig.processPool = [[RNCWKProcessPoolManager sharedManager] sharedProcessPool];
320
473
  }
321
474
  wkWebViewConfig.userContentController = [WKUserContentController new];
322
-
475
+
323
476
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */
324
477
  if (@available(iOS 13.0, *)) {
325
478
  WKWebpagePreferences *pagePrefs = [[WKWebpagePreferences alloc]init];
@@ -327,7 +480,7 @@ RCTAutoInsetsProtocol>
327
480
  wkWebViewConfig.defaultWebpagePreferences = pagePrefs;
328
481
  }
329
482
  #endif
330
-
483
+
331
484
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 /* iOS 14 */
332
485
  if (@available(iOS 14.0, *)) {
333
486
  if ([wkWebViewConfig respondsToSelector:@selector(limitsNavigationsToAppBoundDomains)]) {
@@ -337,28 +490,29 @@ RCTAutoInsetsProtocol>
337
490
  }
338
491
  }
339
492
  #endif
340
-
493
+
341
494
  // Shim the HTML5 history API:
342
495
  [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self]
343
496
  name:HistoryShimName];
344
497
  [self resetupScripts:wkWebViewConfig];
345
-
346
- if(@available(ios 9.0, *)) {
347
- wkWebViewConfig.allowsAirPlayForMediaPlayback = NO;
498
+
499
+ if(@available(macos 10.11, ios 9.0, *)) {
500
+ wkWebViewConfig.allowsAirPlayForMediaPlayback = _allowsAirPlayForMediaPlayback;
348
501
  }
349
-
502
+
350
503
  #if !TARGET_OS_OSX
351
504
  wkWebViewConfig.allowsInlineMediaPlayback = _allowsInlineMediaPlayback;
352
- #if WEBKIT_IOS_10_APIS_AVAILABLE
505
+ wkWebViewConfig.allowsPictureInPictureMediaPlayback = _allowsPictureInPictureMediaPlayback;
353
506
  wkWebViewConfig.mediaTypesRequiringUserActionForPlayback = _mediaPlaybackRequiresUserAction
354
507
  ? WKAudiovisualMediaTypeAll
355
508
  : WKAudiovisualMediaTypeNone;
356
509
  wkWebViewConfig.dataDetectorTypes = _dataDetectorTypes;
357
- #else
358
- wkWebViewConfig.mediaPlaybackRequiresUserAction = _mediaPlaybackRequiresUserAction;
359
- #endif
360
510
  #endif // !TARGET_OS_OSX
361
-
511
+
512
+ if (_applicationNameForUserAgent) {
513
+ wkWebViewConfig.applicationNameForUserAgent = [NSString stringWithFormat:@"%@ %@", wkWebViewConfig.applicationNameForUserAgent, _applicationNameForUserAgent];
514
+ }
515
+
362
516
  return wkWebViewConfig;
363
517
  }
364
518
 
@@ -366,14 +520,11 @@ RCTAutoInsetsProtocol>
366
520
  {
367
521
  if (self.window != nil && _webView == nil) {
368
522
  WKWebViewConfiguration *wkWebViewConfig = [self setUpWkWebViewConfig];
369
- #if !TARGET_OS_OSX
370
- _webView = [[WKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
371
- #else
372
523
  _webView = [[RNCWKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
373
- #endif // !TARGET_OS_OSX
374
-
375
524
  [self setBackgroundColor: _savedBackgroundColor];
376
525
  #if !TARGET_OS_OSX
526
+ _webView.menuItems = _menuItems;
527
+ _webView.suppressMenuItems = _suppressMenuItems;
377
528
  _webView.scrollView.delegate = self;
378
529
  #endif // !TARGET_OS_OSX
379
530
  _webView.UIDelegate = self;
@@ -388,35 +539,54 @@ RCTAutoInsetsProtocol>
388
539
  _webView.scrollView.bounces = _pullToRefreshEnabled || _bounces;
389
540
  _webView.scrollView.showsHorizontalScrollIndicator = _showsHorizontalScrollIndicator;
390
541
  _webView.scrollView.showsVerticalScrollIndicator = _showsVerticalScrollIndicator;
542
+
543
+ if ([_indicatorStyle isEqualToString:@"black"]) {
544
+ _webView.scrollView.indicatorStyle = UIScrollViewIndicatorStyleBlack;
545
+ } else if ([_indicatorStyle isEqualToString:@"white"]) {
546
+ _webView.scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
547
+ } else {
548
+ _webView.scrollView.indicatorStyle = UIScrollViewIndicatorStyleDefault;
549
+ }
550
+
391
551
  _webView.scrollView.directionalLockEnabled = _directionalLockEnabled;
392
552
  #endif // !TARGET_OS_OSX
393
553
  _webView.allowsLinkPreview = _allowsLinkPreview;
394
554
  [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
395
555
  _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures;
396
-
556
+
397
557
  _webView.customUserAgent = _userAgent;
398
- #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
558
+
559
+ #if !TARGET_OS_OSX
399
560
  if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
400
561
  _webView.scrollView.contentInsetAdjustmentBehavior = _savedContentInsetAdjustmentBehavior;
401
562
  }
402
- #endif
563
+ #endif // !TARGET_OS_OSX
564
+
403
565
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* __IPHONE_13_0 */
404
566
  if (@available(iOS 13.0, *)) {
405
567
  _webView.scrollView.automaticallyAdjustsScrollIndicatorInsets = _savedAutomaticallyAdjustsScrollIndicatorInsets;
406
568
  }
407
569
  #endif
408
-
570
+
571
+ #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130300 || \
572
+ __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400 || \
573
+ __TV_OS_VERSION_MAX_ALLOWED >= 160400
574
+ if (@available(macOS 13.3, iOS 16.4, tvOS 16.4, *))
575
+ _webView.inspectable = _webviewDebuggingEnabled;
576
+ #endif
577
+
409
578
  [self addSubview:_webView];
410
579
  [self setHideKeyboardAccessoryView: _savedHideKeyboardAccessoryView];
411
580
  [self setKeyboardDisplayRequiresUserAction: _savedKeyboardDisplayRequiresUserAction];
412
581
  [self visitSource];
413
582
  }
583
+
414
584
  #if !TARGET_OS_OSX
415
585
  // Allow this object to recognize gestures
416
586
  if (self.menuItems != nil) {
417
587
  UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(startLongPress:)];
418
588
  longPress.delegate = self;
419
-
589
+
420
590
  longPress.minimumPressDuration = 0.4f;
421
591
  longPress.numberOfTouchesRequired = 1;
422
592
  longPress.cancelsTouchesInView = YES;
@@ -431,30 +601,59 @@ RCTAutoInsetsProtocol>
431
601
  _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures;
432
602
  }
433
603
 
604
+ #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130300 || \
605
+ __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400 || \
606
+ __TV_OS_VERSION_MAX_ALLOWED >= 160400
607
+ - (void)setWebviewDebuggingEnabled:(BOOL)webviewDebuggingEnabled {
608
+ _webviewDebuggingEnabled = webviewDebuggingEnabled;
609
+ if (@available(macOS 13.3, iOS 16.4, tvOS 16.4, *))
610
+ _webView.inspectable = _webviewDebuggingEnabled;
611
+ }
612
+ #endif
613
+
614
+ #ifdef RCT_NEW_ARCH_ENABLED
615
+ - (void)destroyWebView
616
+ #else
434
617
  - (void)removeFromSuperview
618
+ #endif
435
619
  {
436
620
  if (_webView) {
437
621
  [_webView.configuration.userContentController removeScriptMessageHandlerForName:HistoryShimName];
438
622
  [_webView.configuration.userContentController removeScriptMessageHandlerForName:MessageHandlerName];
439
623
  [_webView removeObserver:self forKeyPath:@"estimatedProgress"];
440
624
  [_webView removeFromSuperview];
625
+ if (@available(iOS 15.0, macOS 12.0, *)) {
626
+ [_webView pauseAllMediaPlaybackWithCompletionHandler:nil];
627
+ } else if (@available(iOS 14.5, macOS 11.3, *)) {
628
+ [_webView suspendAllMediaPlayback:nil];
629
+ }
441
630
  #if !TARGET_OS_OSX
442
631
  _webView.scrollView.delegate = nil;
632
+ if (_menuItems) {
633
+ UIMenuController *menuController = [UIMenuController sharedMenuController];
634
+ menuController.menuItems = nil;
635
+ }
443
636
  #endif // !TARGET_OS_OSX
444
637
  _webView = nil;
638
+ if (_onContentProcessDidTerminate) {
639
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
640
+ _onContentProcessDidTerminate(event);
641
+ }
445
642
  }
446
-
643
+
644
+ #ifndef RCT_NEW_ARCH_ENABLED
447
645
  [super removeFromSuperview];
646
+ #endif
448
647
  }
449
648
 
450
- #if !TARGET_OS_OSX
649
+ #if TARGET_OS_IOS
451
650
  -(void)showFullScreenVideoStatusBars
452
651
  {
453
652
  #pragma clang diagnostic ignored "-Wdeprecated-declarations"
454
653
  if (!_autoManageStatusBarEnabled) {
455
654
  return;
456
655
  }
457
-
656
+
458
657
  _isFullScreenVideoOpen = YES;
459
658
  RCTUnsafeExecuteOnMainQueueSync(^{
460
659
  [RCTSharedApplication() setStatusBarStyle:self->_savedStatusBarStyle animated:YES];
@@ -468,7 +667,7 @@ RCTAutoInsetsProtocol>
468
667
  if (!_autoManageStatusBarEnabled) {
469
668
  return;
470
669
  }
471
-
670
+
472
671
  _isFullScreenVideoOpen = NO;
473
672
  RCTUnsafeExecuteOnMainQueueSync(^{
474
673
  [RCTSharedApplication() setStatusBarHidden:self->_savedStatusBarHidden animated:YES];
@@ -503,7 +702,7 @@ RCTAutoInsetsProtocol>
503
702
  }];
504
703
  }
505
704
  }
506
- #endif // !TARGET_OS_OSX
705
+ #endif // TARGET_OS_IOS
507
706
 
508
707
  - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
509
708
  if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
@@ -527,31 +726,40 @@ RCTAutoInsetsProtocol>
527
726
  if (_webView == nil) {
528
727
  return;
529
728
  }
530
-
729
+
531
730
  CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
532
731
  BOOL opaque = (alpha == 1.0);
533
732
  #if !TARGET_OS_OSX
534
733
  self.opaque = _webView.opaque = opaque;
535
734
  _webView.scrollView.backgroundColor = backgroundColor;
536
735
  _webView.backgroundColor = backgroundColor;
537
- #endif
736
+ #else
737
+ // https://stackoverflow.com/questions/40007753/macos-wkwebview-background-transparency
738
+ NSOperatingSystemVersion version = { 10, 12, 0 };
739
+ if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:version]) {
740
+ [_webView setValue:@(opaque) forKey: @"drawsBackground"];
741
+ } else {
742
+ [_webView setValue:@(!opaque) forKey: @"drawsTransparentBackground"];
743
+ }
744
+ #endif // !TARGET_OS_OSX
538
745
  }
539
746
 
540
- #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
747
+ #if !TARGET_OS_OSX
541
748
  - (void)setContentInsetAdjustmentBehavior:(UIScrollViewContentInsetAdjustmentBehavior)behavior
542
749
  {
543
750
  _savedContentInsetAdjustmentBehavior = behavior;
544
751
  if (_webView == nil) {
545
752
  return;
546
753
  }
547
-
754
+
548
755
  if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
549
756
  CGPoint contentOffset = _webView.scrollView.contentOffset;
550
757
  _webView.scrollView.contentInsetAdjustmentBehavior = behavior;
551
758
  _webView.scrollView.contentOffset = contentOffset;
552
759
  }
553
760
  }
554
- #endif
761
+ #endif // !TARGET_OS_OSX
762
+
555
763
  #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* __IPHONE_13_0 */
556
764
  - (void)setAutomaticallyAdjustsScrollIndicatorInsets:(BOOL)automaticallyAdjustsScrollIndicatorInsets{
557
765
  _savedAutomaticallyAdjustsScrollIndicatorInsets = automaticallyAdjustsScrollIndicatorInsets;
@@ -563,6 +771,7 @@ RCTAutoInsetsProtocol>
563
771
  }
564
772
  }
565
773
  #endif
774
+
566
775
  /**
567
776
  * This method is called whenever JavaScript running within the web view calls:
568
777
  * - window.webkit.messageHandlers[MessageHandlerName].postMessage
@@ -572,13 +781,15 @@ RCTAutoInsetsProtocol>
572
781
  {
573
782
  if ([message.name isEqualToString:HistoryShimName]) {
574
783
  if (_onLoadingFinish) {
575
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
784
+ // Exodus: Use security origin for more secure URL reporting
785
+ NSMutableDictionary<NSString *, id> *event = [self baseEventWithScriptMessage:message];
576
786
  [event addEntriesFromDictionary: @{@"navigationType": message.body}];
577
787
  _onLoadingFinish(event);
578
788
  }
579
789
  } else if ([message.name isEqualToString:MessageHandlerName]) {
580
790
  if (_onMessage) {
581
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
791
+ // Exodus: Use security origin for more secure URL reporting
792
+ NSMutableDictionary<NSString *, id> *event = [self baseEventWithScriptMessage:message];
582
793
  [event addEntriesFromDictionary: @{@"data": message.body}];
583
794
  _onMessage(event);
584
795
  }
@@ -589,32 +800,56 @@ RCTAutoInsetsProtocol>
589
800
  {
590
801
  if (![_source isEqualToDictionary:source]) {
591
802
  _source = [source copy];
592
-
803
+
804
+ if (_webView != nil) {
805
+ [self visitSource];
806
+ }
807
+ }
808
+ }
809
+
810
+ - (void)setAllowingReadAccessToURL:(NSString *)allowingReadAccessToURL
811
+ {
812
+ if (![_allowingReadAccessToURL isEqualToString:allowingReadAccessToURL]) {
813
+ _allowingReadAccessToURL = [allowingReadAccessToURL copy];
814
+
593
815
  if (_webView != nil) {
594
816
  [self visitSource];
595
817
  }
596
818
  }
597
819
  }
598
820
 
599
- #if !TARGET_OS_OSX
600
821
  - (void)setContentInset:(UIEdgeInsets)contentInset
601
822
  {
823
+ #if !TARGET_OS_OSX
602
824
  _contentInset = contentInset;
603
825
  [RCTView autoAdjustInsetsForView:self
604
826
  withScrollView:_webView.scrollView
605
827
  updateOffset:NO];
828
+ #endif // !TARGET_OS_OSX
606
829
  }
607
830
 
608
831
  - (void)refreshContentInset
609
832
  {
833
+ #if !TARGET_OS_OSX
610
834
  [RCTView autoAdjustInsetsForView:self
611
835
  withScrollView:_webView.scrollView
612
836
  updateOffset:YES];
613
- }
614
837
  #endif // !TARGET_OS_OSX
838
+ }
839
+
615
840
 
616
841
  - (void)visitSource
617
842
  {
843
+ // Check for a static html source first
844
+ NSString *html = [RCTConvert NSString:_source[@"html"]];
845
+ if (html) {
846
+ NSURL *baseURL = [RCTConvert NSURL:_source[@"baseUrl"]];
847
+ if (!baseURL) {
848
+ baseURL = [NSURL URLWithString:@"about:blank"];
849
+ }
850
+ [_webView loadHTMLString:html baseURL:baseURL];
851
+ return;
852
+ }
618
853
  // Add cookie for subsequent resource requests sent by page itself, if cookie was set in headers on WebView
619
854
  NSString *headerCookie = [RCTConvert NSString:_source[@"headers"][@"cookie"]];
620
855
  if(headerCookie) {
@@ -623,70 +858,85 @@ RCTAutoInsetsProtocol>
623
858
  NSArray *httpCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:headers forURL:urlString];
624
859
  [self writeCookiesToWebView:httpCookies completion:nil];
625
860
  }
626
-
861
+
627
862
  NSURLRequest *request = [self requestForSource:_source];
628
-
863
+ __weak WKWebView *webView = _webView;
864
+ NSString *allowingReadAccessToURL = _allowingReadAccessToURL;
865
+
629
866
  [self syncCookiesToWebView:^{
867
+ // Add observer to sync cookies from webview to sharedHTTPCookieStorage
868
+ [webView.configuration.websiteDataStore.httpCookieStore addObserver:self];
869
+
630
870
  // Because of the way React works, as pages redirect, we actually end up
631
871
  // passing the redirect urls back here, so we ignore them if trying to load
632
872
  // the same url. We'll expose a call to 'reload' to allow a user to load
633
873
  // the existing page.
634
- if ([request.URL isEqual:_webView.URL]) {
874
+ if ([request.URL isEqual:webView.URL]) {
635
875
  return;
636
876
  }
637
877
  if (!request.URL) {
638
878
  // Clear the webview
639
- [_webView loadHTMLString:@"" baseURL:nil];
879
+ [webView loadHTMLString:@"" baseURL:nil];
640
880
  return;
641
881
  }
642
882
  if (request.URL.host) {
643
- [_webView loadRequest:request];
883
+ [webView loadRequest:request];
644
884
  }
645
885
  else {
646
- // WARNING: UNREACHABLE, non-host loads (file urls)
647
- // Clear the webview
648
- [_webView loadHTMLString:@"" baseURL:nil];
649
- return;
886
+ NSURL* readAccessUrl = allowingReadAccessToURL ? [RCTConvert NSURL:allowingReadAccessToURL] : request.URL;
887
+ [webView loadFileURL:request.URL allowingReadAccessToURL:readAccessUrl];
650
888
  }
651
889
  }];
652
890
  }
653
891
 
654
892
  #if !TARGET_OS_OSX
893
+ -(void)setMenuItems:(NSArray<NSDictionary *> *)menuItems {
894
+ _menuItems = menuItems;
895
+ _webView.menuItems = menuItems;
896
+ }
897
+
898
+ -(void)setSuppressMenuItems:(NSArray<NSString *> *)suppressMenuItems {
899
+ _suppressMenuItems = suppressMenuItems;
900
+ _webView.suppressMenuItems = suppressMenuItems;
901
+ }
902
+
903
+ #if TARGET_OS_IOS
655
904
  -(void)setKeyboardDisplayRequiresUserAction:(BOOL)keyboardDisplayRequiresUserAction
656
905
  {
906
+ _keyboardDisplayRequiresUserAction = keyboardDisplayRequiresUserAction;
657
907
  if (_webView == nil) {
658
908
  _savedKeyboardDisplayRequiresUserAction = keyboardDisplayRequiresUserAction;
659
909
  return;
660
910
  }
661
-
911
+
662
912
  if (_savedKeyboardDisplayRequiresUserAction == true) {
663
913
  return;
664
914
  }
665
-
915
+
666
916
  UIView* subview;
667
-
917
+
668
918
  for (UIView* view in _webView.scrollView.subviews) {
669
919
  if([[view.class description] hasPrefix:@"WK"])
670
920
  subview = view;
671
921
  }
672
-
922
+
673
923
  if(subview == nil) return;
674
-
924
+
675
925
  Class class = subview.class;
676
-
926
+
677
927
  NSOperatingSystemVersion iOS_11_3_0 = (NSOperatingSystemVersion){11, 3, 0};
678
928
  NSOperatingSystemVersion iOS_12_2_0 = (NSOperatingSystemVersion){12, 2, 0};
679
929
  NSOperatingSystemVersion iOS_13_0_0 = (NSOperatingSystemVersion){13, 0, 0};
680
-
930
+
681
931
  Method method;
682
932
  IMP override;
683
-
933
+
684
934
  if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_13_0_0]) {
685
935
  // iOS 13.0.0 - Future
686
936
  SEL selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:");
687
937
  method = class_getInstanceMethod(class, selector);
688
938
  IMP original = method_getImplementation(method);
689
- override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
939
+ override = imp_implementationWithBlock(^void(id me, void* arg0, __unused BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
690
940
  ((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
691
941
  });
692
942
  }
@@ -695,7 +945,7 @@ RCTAutoInsetsProtocol>
695
945
  SEL selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:changingActivityState:userObject:");
696
946
  method = class_getInstanceMethod(class, selector);
697
947
  IMP original = method_getImplementation(method);
698
- override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
948
+ override = imp_implementationWithBlock(^void(id me, void* arg0, __unused BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
699
949
  ((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
700
950
  });
701
951
  }
@@ -704,7 +954,7 @@ RCTAutoInsetsProtocol>
704
954
  SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:");
705
955
  method = class_getInstanceMethod(class, selector);
706
956
  IMP original = method_getImplementation(method);
707
- override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
957
+ override = imp_implementationWithBlock(^void(id me, void* arg0, __unused BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
708
958
  ((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
709
959
  });
710
960
  } else {
@@ -712,48 +962,67 @@ RCTAutoInsetsProtocol>
712
962
  SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:");
713
963
  method = class_getInstanceMethod(class, selector);
714
964
  IMP original = method_getImplementation(method);
715
- override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, id arg3) {
965
+ override = imp_implementationWithBlock(^void(id me, void* arg0, __unused BOOL arg1, BOOL arg2, id arg3) {
716
966
  ((void (*)(id, SEL, void*, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3);
717
967
  });
718
968
  }
719
-
969
+
720
970
  method_setImplementation(method, override);
721
971
  }
722
972
 
723
973
  -(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView
724
974
  {
975
+ _hideKeyboardAccessoryView = hideKeyboardAccessoryView;
976
+ _savedHideKeyboardAccessoryView = hideKeyboardAccessoryView;
977
+
725
978
  if (_webView == nil) {
726
- _savedHideKeyboardAccessoryView = hideKeyboardAccessoryView;
727
979
  return;
728
980
  }
729
-
981
+
730
982
  if (_savedHideKeyboardAccessoryView == false) {
983
+ [self __addInputAccessoryView];
731
984
  return;
732
985
  }
733
-
986
+
734
987
  UIView* subview;
735
-
988
+
736
989
  for (UIView* view in _webView.scrollView.subviews) {
737
990
  if([[view.class description] hasPrefix:@"WK"])
738
991
  subview = view;
739
992
  }
740
-
993
+
741
994
  if(subview == nil) return;
742
-
743
- NSString* name = [NSString stringWithFormat:@"%@__SwizzleHelperWK", subview.class.superclass];
995
+
996
+ NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelperWK", subview.class.superclass];
744
997
  Class newClass = NSClassFromString(name);
745
-
998
+
746
999
  if(newClass == nil)
747
1000
  {
748
1001
  newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0);
749
1002
  if(!newClass) return;
750
-
751
- Method method = class_getInstanceMethod([__SwizzleHelperWK class], @selector(inputAccessoryView));
1003
+
1004
+ Method method = class_getInstanceMethod([_SwizzleHelperWK class], @selector(inputAccessoryView));
752
1005
  class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method));
753
-
1006
+
754
1007
  objc_registerClassPair(newClass);
755
1008
  }
756
-
1009
+
1010
+ object_setClass(subview, newClass);
1011
+ }
1012
+ #endif // TARGET_OS_IOS
1013
+
1014
+ - (void)__addInputAccessoryView {
1015
+ UIView* subview;
1016
+
1017
+ for (UIView* view in _webView.scrollView.subviews) {
1018
+ if([[view.class description] hasSuffix:@"_SwizzleHelperWK"])
1019
+ subview = view;
1020
+ }
1021
+
1022
+ if(subview == nil) return;
1023
+
1024
+ Class newClass = subview.superclass;
1025
+
757
1026
  object_setClass(subview, newClass);
758
1027
  }
759
1028
 
@@ -829,6 +1098,19 @@ RCTAutoInsetsProtocol>
829
1098
  _showsVerticalScrollIndicator = showsVerticalScrollIndicator;
830
1099
  _webView.scrollView.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
831
1100
  }
1101
+
1102
+ - (void)setIndicatorStyle:(NSString *)indicatorStyle
1103
+ {
1104
+ _indicatorStyle = indicatorStyle;
1105
+
1106
+ if ([indicatorStyle isEqualToString:@"black"]) {
1107
+ _webView.scrollView.indicatorStyle = UIScrollViewIndicatorStyleBlack;
1108
+ } else if ([indicatorStyle isEqualToString:@"white"]) {
1109
+ _webView.scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
1110
+ } else {
1111
+ _webView.scrollView.indicatorStyle = UIScrollViewIndicatorStyleDefault;
1112
+ }
1113
+ }
832
1114
  #endif // !TARGET_OS_OSX
833
1115
 
834
1116
  - (void)postMessage:(NSString *)message
@@ -844,8 +1126,8 @@ RCTAutoInsetsProtocol>
844
1126
  - (void)layoutSubviews
845
1127
  {
846
1128
  [super layoutSubviews];
847
-
848
- // Ensure webview takes the position and dimensions of RNCWebView
1129
+
1130
+ // Ensure webview takes the position and dimensions of RNCWebViewImpl
849
1131
  _webView.frame = self.bounds;
850
1132
  #if !TARGET_OS_OSX
851
1133
  _webView.scrollView.contentInset = _contentInset;
@@ -864,6 +1146,19 @@ RCTAutoInsetsProtocol>
864
1146
  return [[NSMutableDictionary alloc] initWithDictionary: event];
865
1147
  }
866
1148
 
1149
+ // Exodus: Get URL from security origin for message events (more secure than webView.URL)
1150
+ - (NSMutableDictionary<NSString *, id> *)baseEventWithScriptMessage:(WKScriptMessage *)message {
1151
+ WKSecurityOrigin *securityOrigin = message.frameInfo.securityOrigin;
1152
+ NSString *protocol = securityOrigin.protocol;
1153
+ NSString *host = securityOrigin.host;
1154
+
1155
+ NSString *messageOriginURL = [NSString stringWithFormat:@"%@://%@", protocol, host];
1156
+
1157
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1158
+ event[@"url"] = messageOriginURL;
1159
+ return event;
1160
+ }
1161
+
867
1162
  + (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential {
868
1163
  clientAuthenticationCredential = credential;
869
1164
  }
@@ -872,6 +1167,11 @@ RCTAutoInsetsProtocol>
872
1167
  customCertificatesForHost = certificates;
873
1168
  }
874
1169
 
1170
+ // Exodus: Camera permission whitelist for security
1171
+ + (void)setCameraPermissionOriginWhitelist:(nullable NSArray<NSString *>*)whitelist {
1172
+ cameraPermissionOriginWhitelist = whitelist ? [NSSet setWithArray:whitelist] : nil;
1173
+ }
1174
+
875
1175
  - (void) webView:(WKWebView *)webView
876
1176
  didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
877
1177
  completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable))completionHandler
@@ -926,7 +1226,7 @@ RCTAutoInsetsProtocol>
926
1226
  {
927
1227
  #if !TARGET_OS_OSX
928
1228
  UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
929
- [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
1229
+ [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) {
930
1230
  completionHandler();
931
1231
  }]];
932
1232
  [[self topViewController] presentViewController:alert animated:YES completion:NULL];
@@ -945,10 +1245,10 @@ RCTAutoInsetsProtocol>
945
1245
  - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
946
1246
  #if !TARGET_OS_OSX
947
1247
  UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
948
- [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
1248
+ [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) {
949
1249
  completionHandler(YES);
950
1250
  }]];
951
- [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
1251
+ [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(__unused UIAlertAction *action) {
952
1252
  completionHandler(NO);
953
1253
  }]];
954
1254
  [[self topViewController] presentViewController:alert animated:YES completion:NULL];
@@ -973,11 +1273,11 @@ RCTAutoInsetsProtocol>
973
1273
  [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
974
1274
  textField.text = defaultText;
975
1275
  }];
976
- UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
1276
+ UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) {
977
1277
  completionHandler([[alert.textFields lastObject] text]);
978
1278
  }];
979
1279
  [alert addAction:okAction];
980
- UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
1280
+ UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(__unused UIAlertAction *action) {
981
1281
  completionHandler(nil);
982
1282
  }];
983
1283
  [alert addAction:cancelAction];
@@ -986,13 +1286,16 @@ RCTAutoInsetsProtocol>
986
1286
  #else
987
1287
  NSAlert *alert = [[NSAlert alloc] init];
988
1288
  [alert setMessageText:prompt];
989
-
1289
+
990
1290
  const NSRect RCTSingleTextFieldFrame = NSMakeRect(0.0, 0.0, 275.0, 22.0);
991
1291
  NSTextField *textField = [[NSTextField alloc] initWithFrame:RCTSingleTextFieldFrame];
992
1292
  textField.cell.scrollable = YES;
1293
+ if (@available(macOS 10.11, *)) {
1294
+ textField.maximumNumberOfLines = 1;
1295
+ }
993
1296
  textField.stringValue = defaultText;
994
1297
  [alert setAccessoryView:textField];
995
-
1298
+
996
1299
  [alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button")];
997
1300
  [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"Cancel button")];
998
1301
  [alert beginSheetModalForWindow:[NSApp keyWindow] completionHandler:^(NSModalResponse response) {
@@ -1049,67 +1352,108 @@ RCTAutoInsetsProtocol>
1049
1352
  decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
1050
1353
  decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
1051
1354
  {
1052
- static NSDictionary<NSNumber *, NSString *> *navigationTypes;
1053
- static dispatch_once_t onceToken;
1054
-
1055
- dispatch_once(&onceToken, ^{
1056
- navigationTypes = @{
1057
- @(WKNavigationTypeLinkActivated): @"click",
1058
- @(WKNavigationTypeFormSubmitted): @"formsubmit",
1059
- @(WKNavigationTypeBackForward): @"backforward",
1060
- @(WKNavigationTypeReload): @"reload",
1061
- @(WKNavigationTypeFormResubmitted): @"formresubmit",
1062
- @(WKNavigationTypeOther): @"other",
1063
- };
1064
- });
1065
-
1066
- WKNavigationType navigationType = navigationAction.navigationType;
1067
- NSURLRequest *request = navigationAction.request;
1068
- BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
1069
-
1070
- if (_onShouldStartLoadWithRequest) {
1071
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1072
- if (request.mainDocumentURL) {
1073
- [event addEntriesFromDictionary: @{
1074
- @"mainDocumentURL": (request.mainDocumentURL).absoluteString,
1075
- }];
1076
- }
1077
- [event addEntriesFromDictionary: @{
1078
- @"url": (request.URL).absoluteString,
1079
- @"navigationType": navigationTypes[@(navigationType)],
1080
- @"isTopFrame": @(isTopFrame)
1081
- }];
1082
- if (![self.delegate webView:self
1083
- shouldStartLoadForRequest:event
1084
- withCallback:_onShouldStartLoadWithRequest]) {
1355
+ static NSDictionary<NSNumber *, NSString *> *navigationTypes;
1356
+ static dispatch_once_t onceToken;
1357
+
1358
+ dispatch_once(&onceToken, ^{
1359
+ navigationTypes = @{
1360
+ @(WKNavigationTypeLinkActivated): @"click",
1361
+ @(WKNavigationTypeFormSubmitted): @"formsubmit",
1362
+ @(WKNavigationTypeBackForward): @"backforward",
1363
+ @(WKNavigationTypeReload): @"reload",
1364
+ @(WKNavigationTypeFormResubmitted): @"formresubmit",
1365
+ @(WKNavigationTypeOther): @"other",
1366
+ };
1367
+ });
1368
+
1369
+ WKNavigationType navigationType = navigationAction.navigationType;
1370
+ NSURLRequest *request = navigationAction.request;
1371
+ BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
1372
+ BOOL hasTargetFrame = navigationAction.targetFrame != nil;
1373
+
1374
+ if (_onOpenWindow && !hasTargetFrame) {
1375
+ // When OnOpenWindow should be called, we want to prevent the navigation
1376
+ // If not prevented, the `decisionHandler` is called first and after that `createWebViewWithConfiguration` is called
1377
+ // In that order the WebView's ref would be updated with the target URL even if `createWebViewWithConfiguration` does not call `loadRequest`
1378
+ // So the WebView's document stays on the current URL, but the WebView's ref is replaced by the target URL
1379
+ // By preventing the navigation here, we also prevent the WebView's ref mutation
1380
+ // The counterpart is that we have to manually call `_onOpenWindow` here, because no navigation means no call to `createWebViewWithConfiguration`
1381
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1382
+ [event addEntriesFromDictionary: @{@"targetUrl": request.URL.absoluteString}];
1085
1383
  decisionHandler(WKNavigationActionPolicyCancel);
1384
+ _onOpenWindow(event);
1086
1385
  return;
1087
1386
  }
1088
- }
1089
-
1090
- if (_onLoadingStart) {
1091
- // We have this check to filter out iframe requests and whatnot
1092
- if (isTopFrame) {
1093
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1094
- [event addEntriesFromDictionary: @{
1095
- @"url": (request.URL).absoluteString,
1096
- @"navigationType": navigationTypes[@(navigationType)]
1097
- }];
1098
- _onLoadingStart(event);
1387
+
1388
+ if (_onShouldStartLoadWithRequest) {
1389
+ int lockIdentifier = [[RNCWebViewDecisionManager getInstance] setDecisionHandler: ^(BOOL shouldStart){
1390
+ dispatch_async(dispatch_get_main_queue(), ^{
1391
+ if (!shouldStart) {
1392
+ decisionHandler(WKNavigationActionPolicyCancel);
1393
+ return;
1394
+ }
1395
+ if (self->_onLoadingStart) {
1396
+ // We have this check to filter out iframe requests and whatnot
1397
+ if (isTopFrame) {
1398
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1399
+ [event addEntriesFromDictionary: @{
1400
+ @"url": (request.URL).absoluteString,
1401
+ @"navigationType": navigationTypes[@(navigationType)]
1402
+ }];
1403
+ self->_onLoadingStart(event);
1404
+ }
1405
+ }
1406
+
1407
+ // Allow all navigation by default
1408
+ decisionHandler(WKNavigationActionPolicyAllow);
1409
+ });
1410
+
1411
+ }];
1412
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1413
+ if (request.mainDocumentURL) {
1414
+ [event addEntriesFromDictionary: @{
1415
+ @"mainDocumentURL": (request.mainDocumentURL).absoluteString,
1416
+ }];
1417
+ }
1418
+ [event addEntriesFromDictionary: @{
1419
+ @"url": (request.URL).absoluteString,
1420
+ @"navigationType": navigationTypes[@(navigationType)],
1421
+ @"isTopFrame": @(isTopFrame),
1422
+ @"hasTargetFrame": @(hasTargetFrame),
1423
+ @"lockIdentifier": @(lockIdentifier)
1424
+ }];
1425
+ _onShouldStartLoadWithRequest(event);
1426
+ // decisionHandler(WKNavigationActionPolicyAllow);
1427
+ return;
1099
1428
  }
1100
- }
1101
-
1102
- // Allow all navigation by default
1103
- decisionHandler(WKNavigationActionPolicyAllow);
1429
+
1430
+ if (_onLoadingStart) {
1431
+ // We have this check to filter out iframe requests and whatnot
1432
+ if (isTopFrame) {
1433
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1434
+ [event addEntriesFromDictionary: @{
1435
+ @"url": (request.URL).absoluteString,
1436
+ @"navigationType": navigationTypes[@(navigationType)]
1437
+ }];
1438
+ _onLoadingStart(event);
1439
+ }
1440
+ }
1441
+
1442
+ // Allow all navigation by default
1443
+ decisionHandler(WKNavigationActionPolicyAllow);
1104
1444
  }
1105
1445
 
1106
1446
  /**
1107
- * Called when the web views content process is terminated.
1447
+ * Called when the web view's content process is terminated.
1108
1448
  * @see https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455639-webviewwebcontentprocessdidtermi?language=objc
1109
1449
  */
1110
1450
  - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
1111
1451
  {
1112
1452
  RCTLogWarn(@"Webview Process Terminated");
1453
+ if (_onContentProcessDidTerminate) {
1454
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1455
+ _onContentProcessDidTerminate(event);
1456
+ }
1113
1457
  }
1114
1458
 
1115
1459
  /**
@@ -1121,23 +1465,38 @@ RCTAutoInsetsProtocol>
1121
1465
  decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
1122
1466
  {
1123
1467
  WKNavigationResponsePolicy policy = WKNavigationResponsePolicyAllow;
1124
- if (navigationResponse.forMainFrame) {
1125
- if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
1126
- NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
1127
- NSInteger statusCode = response.statusCode;
1128
-
1129
- NSString *disposition = nil;
1130
- if (@available(iOS 13, *)) {
1131
- disposition = [response valueForHTTPHeaderField:@"Content-Disposition"];
1468
+ if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
1469
+ NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
1470
+ NSInteger statusCode = response.statusCode;
1471
+ if (_onHttpError && navigationResponse.forMainFrame) {
1472
+ if (statusCode >= 400) {
1473
+ NSMutableDictionary<NSString *, id> *httpErrorEvent = [self baseEvent];
1474
+ [httpErrorEvent addEntriesFromDictionary: @{
1475
+ @"url": response.URL.absoluteString,
1476
+ @"statusCode": @(statusCode)
1477
+ }];
1478
+
1479
+ _onHttpError(httpErrorEvent);
1132
1480
  }
1133
- BOOL isAttachment = disposition != nil && [disposition hasPrefix:@"attachment"];
1134
- if (isAttachment || !navigationResponse.canShowMIMEType) {
1481
+ }
1482
+ NSString *disposition = nil;
1483
+ if (@available(iOS 13, macOS 10.15, *)) {
1484
+ disposition = [response valueForHTTPHeaderField:@"Content-Disposition"];
1485
+ }
1486
+ BOOL isAttachment = disposition != nil && [disposition hasPrefix:@"attachment"];
1487
+ if (isAttachment || !navigationResponse.canShowMIMEType) {
1488
+ if (_onFileDownload) {
1135
1489
  policy = WKNavigationResponsePolicyCancel;
1136
- // File downloads are cancelled
1490
+
1491
+ NSMutableDictionary<NSString *, id> *downloadEvent = [self baseEvent];
1492
+ [downloadEvent addEntriesFromDictionary: @{
1493
+ @"downloadUrl": (response.URL).absoluteString,
1494
+ }];
1495
+ _onFileDownload(downloadEvent);
1137
1496
  }
1138
1497
  }
1139
1498
  }
1140
-
1499
+
1141
1500
  decisionHandler(policy);
1142
1501
  }
1143
1502
 
@@ -1157,7 +1516,7 @@ RCTAutoInsetsProtocol>
1157
1516
  // http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
1158
1517
  return;
1159
1518
  }
1160
-
1519
+
1161
1520
  if ([error.domain isEqualToString:@"WebKitErrorDomain"] &&
1162
1521
  (error.code == 102 || error.code == 101)) {
1163
1522
  // Error code 102 "Frame load interrupted" is raised by the WKWebView
@@ -1165,7 +1524,7 @@ RCTAutoInsetsProtocol>
1165
1524
  // implementing OAuth with a WebView.
1166
1525
  return;
1167
1526
  }
1168
-
1527
+
1169
1528
  NSMutableDictionary<NSString *, id> *event = [self baseEvent];
1170
1529
  [event addEntriesFromDictionary:@{
1171
1530
  @"didFailProvisionalNavigation": @YES,
@@ -1194,6 +1553,37 @@ RCTAutoInsetsProtocol>
1194
1553
  }];
1195
1554
  }
1196
1555
 
1556
+ -(void)forceIgnoreSilentHardwareSwitch:(BOOL)initialSetup
1557
+ {
1558
+ 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==";
1559
+ NSString *scr;
1560
+ if (initialSetup) {
1561
+ scr = [NSString stringWithFormat:@"var s=new Audio('%@');s.id='wkwebviewAudio';s.controls=false;s.loop=true;s.play();document.body.appendChild(s);true", mp3Str];
1562
+ } else {
1563
+ 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];
1564
+ }
1565
+ [self evaluateJS: scr thenCall: nil];
1566
+ }
1567
+
1568
+ -(void)disableIgnoreSilentSwitch
1569
+ {
1570
+ [self evaluateJS: @"document.getElementById('wkwebviewAudio').src=null;true" thenCall: nil];
1571
+ }
1572
+
1573
+ -(void)appDidBecomeActive
1574
+ {
1575
+ if (_ignoreSilentHardwareSwitch) {
1576
+ [self forceIgnoreSilentHardwareSwitch:false];
1577
+ }
1578
+ }
1579
+
1580
+ -(void)appWillResignActive
1581
+ {
1582
+ if (_ignoreSilentHardwareSwitch) {
1583
+ [self disableIgnoreSilentSwitch];
1584
+ }
1585
+ }
1586
+
1197
1587
  /**
1198
1588
  * Called when the navigation is complete.
1199
1589
  * @see https://fburl.com/rtys6jlb
@@ -1201,6 +1591,10 @@ RCTAutoInsetsProtocol>
1201
1591
  - (void)webView:(WKWebView *)webView
1202
1592
  didFinishNavigation:(WKNavigation *)navigation
1203
1593
  {
1594
+ if (_ignoreSilentHardwareSwitch) {
1595
+ [self forceIgnoreSilentHardwareSwitch:true];
1596
+ }
1597
+
1204
1598
  if (_onLoadingFinish) {
1205
1599
  _onLoadingFinish([self baseEvent]);
1206
1600
  }
@@ -1208,6 +1602,16 @@ didFinishNavigation:(WKNavigation *)navigation
1208
1602
 
1209
1603
  - (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore
1210
1604
  {
1605
+ if (@available(iOS 11.0, *)) {
1606
+ if(_sharedCookiesEnabled) {
1607
+ // Write all cookies from WKWebView back to sharedHTTPCookieStorage
1608
+ [cookieStore getAllCookies:^(NSArray* cookies) {
1609
+ for (NSHTTPCookie *cookie in cookies) {
1610
+ [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
1611
+ }
1612
+ }];
1613
+ }
1614
+ }
1211
1615
  }
1212
1616
 
1213
1617
  - (void)injectJavaScript:(NSString *)script
@@ -1233,7 +1637,7 @@ didFinishNavigation:(WKNavigation *)navigation
1233
1637
  * manually call [_webView loadRequest:request].
1234
1638
  */
1235
1639
  NSURLRequest *request = [self requestForSource:self.source];
1236
-
1640
+
1237
1641
  if (request.URL && !_webView.URL.absoluteString.length) {
1238
1642
  [_webView loadRequest:request];
1239
1643
  } else {
@@ -1245,6 +1649,9 @@ didFinishNavigation:(WKNavigation *)navigation
1245
1649
  {
1246
1650
  UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
1247
1651
  _refreshControl = refreshControl;
1652
+ if(_refreshControlLightMode) {
1653
+ [refreshControl setTintColor:[UIColor whiteColor]];
1654
+ }
1248
1655
  [_webView.scrollView addSubview: refreshControl];
1249
1656
  [refreshControl addTarget:self action:@selector(pullToRefresh:) forControlEvents: UIControlEventValueChanged];
1250
1657
  }
@@ -1259,13 +1666,13 @@ didFinishNavigation:(WKNavigation *)navigation
1259
1666
  - (void)setPullToRefreshEnabled:(BOOL)pullToRefreshEnabled
1260
1667
  {
1261
1668
  _pullToRefreshEnabled = pullToRefreshEnabled;
1262
-
1669
+
1263
1670
  if (pullToRefreshEnabled) {
1264
1671
  [self addPullToRefreshControl];
1265
1672
  } else {
1266
1673
  [_refreshControl removeFromSuperview];
1267
1674
  }
1268
-
1675
+
1269
1676
  [self setBounces:_bounces];
1270
1677
  }
1271
1678
  #endif // !TARGET_OS_OSX
@@ -1282,6 +1689,37 @@ didFinishNavigation:(WKNavigation *)navigation
1282
1689
  #endif // !TARGET_OS_OSX
1283
1690
  }
1284
1691
 
1692
+ - (void)clearCache:(BOOL)includeDiskFiles
1693
+ {
1694
+ NSMutableSet *dataTypes = [NSMutableSet setWithArray:@[
1695
+ WKWebsiteDataTypeMemoryCache,
1696
+ WKWebsiteDataTypeOfflineWebApplicationCache,
1697
+ ]];
1698
+ if (@available(iOS 11.3, *)) {
1699
+ [dataTypes addObject:WKWebsiteDataTypeFetchCache];
1700
+ }
1701
+ if (includeDiskFiles) {
1702
+ [dataTypes addObjectsFromArray:@[
1703
+ WKWebsiteDataTypeDiskCache,
1704
+ WKWebsiteDataTypeSessionStorage,
1705
+ WKWebsiteDataTypeLocalStorage,
1706
+ WKWebsiteDataTypeWebSQLDatabases,
1707
+ WKWebsiteDataTypeIndexedDBDatabases
1708
+ ]];
1709
+ }
1710
+ [self removeData:dataTypes];
1711
+ }
1712
+
1713
+ - (void)removeData:(NSSet *)dataTypes
1714
+ {
1715
+ if (_webView == nil) {
1716
+ return;
1717
+ }
1718
+ NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
1719
+
1720
+ [_webView.configuration.websiteDataStore removeDataOfTypes:dataTypes modifiedSince:dateFrom completionHandler:^{}];
1721
+ }
1722
+
1285
1723
  #if !TARGET_OS_OSX
1286
1724
  - (void)setBounces:(BOOL)bounces
1287
1725
  {
@@ -1293,54 +1731,116 @@ didFinishNavigation:(WKNavigation *)navigation
1293
1731
 
1294
1732
  - (void)setInjectedJavaScript:(NSString *)source {
1295
1733
  _injectedJavaScript = source;
1296
-
1734
+
1297
1735
  self.atEndScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source
1298
1736
  injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
1299
- forMainFrameOnly:YES];
1300
-
1737
+ forMainFrameOnly:_injectedJavaScriptForMainFrameOnly];
1738
+
1301
1739
  if(_webView != nil){
1302
1740
  [self resetupScripts:_webView.configuration];
1303
1741
  }
1304
1742
  }
1305
1743
 
1744
+ - (void)setInjectedJavaScriptObject:(NSString *)source
1745
+ {
1746
+ _injectedJavaScriptObject = source;
1747
+ self.injectedObjectJsonScript = [
1748
+ [WKUserScript alloc]
1749
+ initWithSource: [
1750
+ NSString
1751
+ stringWithFormat:
1752
+ @"window.%@ = window.%@ || {};"
1753
+ "window.%@.injectedObjectJson = function () {"
1754
+ " return `%@`;"
1755
+ "};", MessageHandlerName, MessageHandlerName, MessageHandlerName, source
1756
+ ]
1757
+ injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1758
+ /* 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.
1759
+ * I am keeping it as YES for consistency with previous behaviour. */
1760
+ // forMainFrameOnly:_messagingEnabledForMainFrameOnly
1761
+ forMainFrameOnly:YES
1762
+ ];
1763
+ }
1764
+
1765
+ - (void)setEnableApplePay:(BOOL)enableApplePay {
1766
+ _enableApplePay = enableApplePay;
1767
+ if(_webView != nil){
1768
+ [self resetupScripts:_webView.configuration];
1769
+ }
1770
+ }
1771
+
1306
1772
  - (void)setInjectedJavaScriptBeforeContentLoaded:(NSString *)source {
1307
1773
  _injectedJavaScriptBeforeContentLoaded = source;
1308
-
1774
+
1309
1775
  self.atStartScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source
1310
1776
  injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1311
- forMainFrameOnly:YES];
1312
-
1777
+ forMainFrameOnly:_injectedJavaScriptBeforeContentLoadedForMainFrameOnly];
1778
+
1313
1779
  if(_webView != nil){
1314
1780
  [self resetupScripts:_webView.configuration];
1315
1781
  }
1316
1782
  }
1317
1783
 
1784
+ - (void)setInjectedJavaScriptForMainFrameOnly:(BOOL)mainFrameOnly {
1785
+ _injectedJavaScriptForMainFrameOnly = mainFrameOnly;
1786
+ [self setInjectedJavaScript:_injectedJavaScript];
1787
+ }
1788
+
1789
+ - (void)setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly:(BOOL)mainFrameOnly {
1790
+ _injectedJavaScriptBeforeContentLoadedForMainFrameOnly = mainFrameOnly;
1791
+ [self setInjectedJavaScriptBeforeContentLoaded:_injectedJavaScriptBeforeContentLoaded];
1792
+ }
1793
+
1318
1794
  - (void)setMessagingEnabled:(BOOL)messagingEnabled {
1319
1795
  _messagingEnabled = messagingEnabled;
1320
-
1796
+
1321
1797
  self.postMessageScript = _messagingEnabled ?
1322
1798
  [
1323
1799
  [WKUserScript alloc]
1324
1800
  initWithSource: [
1325
1801
  NSString
1326
1802
  stringWithFormat:
1327
- @"window.%@ = {"
1328
- " postMessage: function (data) {"
1329
- " window.webkit.messageHandlers.%@.postMessage(String(data));"
1330
- " }"
1331
- "};", MessageHandlerName, MessageHandlerName
1803
+ @"window.%@ = window.%@ || {};"
1804
+ "window.%@.postMessage = function (data) {"
1805
+ " window.webkit.messageHandlers.%@.postMessage(String(data));"
1806
+ "};", MessageHandlerName, MessageHandlerName, MessageHandlerName, MessageHandlerName
1332
1807
  ]
1333
1808
  injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1809
+ /* 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.
1810
+ * I am keeping it as YES for consistency with previous behaviour. */
1811
+ // forMainFrameOnly:_messagingEnabledForMainFrameOnly
1334
1812
  forMainFrameOnly:YES
1335
1813
  ] :
1336
1814
  nil;
1337
-
1815
+
1338
1816
  if(_webView != nil){
1339
1817
  [self resetupScripts:_webView.configuration];
1340
1818
  }
1341
1819
  }
1342
1820
 
1343
1821
  - (void)writeCookiesToWebView:(NSArray<NSHTTPCookie *>*)cookies completion:(void (^)(void))completion {
1822
+ // The required cookie APIs only became available on iOS 11
1823
+ if (@available(iOS 11.0, *)) {
1824
+ if (_sharedCookiesEnabled) {
1825
+ __weak WKWebView *webView = _webView;
1826
+ dispatch_async(dispatch_get_main_queue(), ^{
1827
+ dispatch_group_t group = dispatch_group_create();
1828
+ for (NSHTTPCookie *cookie in cookies) {
1829
+ dispatch_group_enter(group);
1830
+ [webView.configuration.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:^{
1831
+ dispatch_group_leave(group);
1832
+ }];
1833
+ }
1834
+ dispatch_group_notify(group, dispatch_get_main_queue(), ^{
1835
+ if (completion) {
1836
+ completion();
1837
+ }
1838
+ });
1839
+ });
1840
+ return;
1841
+ }
1842
+ }
1843
+
1344
1844
  if (completion) {
1345
1845
  completion();
1346
1846
  }
@@ -1361,7 +1861,7 @@ didFinishNavigation:(WKNavigation *)navigation
1361
1861
  }
1362
1862
  return;
1363
1863
  }
1364
-
1864
+
1365
1865
  NSString *html5HistoryAPIShimSource = [NSString stringWithFormat:
1366
1866
  @"(function(history) {\n"
1367
1867
  " function notify(type) {\n"
@@ -1382,9 +1882,69 @@ didFinishNavigation:(WKNavigation *)navigation
1382
1882
  " })\n"
1383
1883
  "})(window.history)\n", HistoryShimName
1384
1884
  ];
1385
- WKUserScript *script = [[WKUserScript alloc] initWithSource:html5HistoryAPIShimSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
1386
- [wkWebViewConfig.userContentController addUserScript:script];
1387
-
1885
+ WKUserScript *userScript = [[WKUserScript alloc] initWithSource:html5HistoryAPIShimSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
1886
+ [wkWebViewConfig.userContentController addUserScript:userScript];
1887
+
1888
+ if(_sharedCookiesEnabled) {
1889
+ // More info to sending cookies with WKWebView
1890
+ // https://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview/26577303#26577303
1891
+ if (@available(iOS 11.0, *)) {
1892
+ // Set Cookies in iOS 11 and above, initialize websiteDataStore before setting cookies
1893
+ // See also https://forums.developer.apple.com/thread/97194
1894
+ // check if websiteDataStore has not been initialized before
1895
+ if(!_incognito && !_cacheEnabled) {
1896
+ wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
1897
+ }
1898
+ [self syncCookiesToWebView:^{}];
1899
+ } else {
1900
+ NSMutableString *script = [NSMutableString string];
1901
+
1902
+ // Clear all existing cookies in a direct called function. This ensures that no
1903
+ // javascript error will break the web content javascript.
1904
+ // We keep this code here, if someone requires that Cookies are also removed within the
1905
+ // the WebView and want to extends the current sharedCookiesEnabled option with an
1906
+ // additional property.
1907
+ // Generates JS: document.cookie = "key=; Expires=Thu, 01 Jan 1970 00:00:01 GMT;"
1908
+ // for each cookie which is already available in the WebView context.
1909
+ /*
1910
+ [script appendString:@"(function () {\n"];
1911
+ [script appendString:@" var cookies = document.cookie.split('; ');\n"];
1912
+ [script appendString:@" for (var i = 0; i < cookies.length; i++) {\n"];
1913
+ [script appendString:@" if (cookies[i].indexOf('=') !== -1) {\n"];
1914
+ [script appendString:@" document.cookie = cookies[i].split('=')[0] + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT';\n"];
1915
+ [script appendString:@" }\n"];
1916
+ [script appendString:@" }\n"];
1917
+ [script appendString:@"})();\n\n"];
1918
+ */
1919
+
1920
+ // Set cookies in a direct called function. This ensures that no
1921
+ // javascript error will break the web content javascript.
1922
+ // Generates JS: document.cookie = "key=value; Path=/; Expires=Thu, 01 Jan 20xx 00:00:01 GMT;"
1923
+ // for each cookie which is available in the application context.
1924
+ [script appendString:@"(function () {\n"];
1925
+ for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
1926
+ [script appendFormat:@"document.cookie = %@ + '=' + %@",
1927
+ RCTJSONStringify(cookie.name, NULL),
1928
+ RCTJSONStringify(cookie.value, NULL)];
1929
+ if (cookie.path) {
1930
+ [script appendFormat:@" + '; Path=' + %@", RCTJSONStringify(cookie.path, NULL)];
1931
+ }
1932
+ if (cookie.expiresDate) {
1933
+ [script appendFormat:@" + '; Expires=' + new Date(%f).toUTCString()",
1934
+ cookie.expiresDate.timeIntervalSince1970 * 1000
1935
+ ];
1936
+ }
1937
+ [script appendString:@";\n"];
1938
+ }
1939
+ [script appendString:@"})();\n"];
1940
+
1941
+ WKUserScript* cookieInScript = [[WKUserScript alloc] initWithSource:script
1942
+ injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1943
+ forMainFrameOnly:YES];
1944
+ [wkWebViewConfig.userContentController addUserScript:cookieInScript];
1945
+ }
1946
+ }
1947
+
1388
1948
  if(_messagingEnabled){
1389
1949
  if (self.postMessageScript){
1390
1950
  [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self]
@@ -1399,11 +1959,28 @@ didFinishNavigation:(WKNavigation *)navigation
1399
1959
  if (self.atStartScript) {
1400
1960
  [wkWebViewConfig.userContentController addUserScript:self.atStartScript];
1401
1961
  }
1962
+ if (self.injectedObjectJsonScript) {
1963
+ [wkWebViewConfig.userContentController addUserScript:self.injectedObjectJsonScript];
1964
+ }
1402
1965
  }
1403
1966
 
1404
1967
  - (NSURLRequest *)requestForSource:(id)json {
1405
1968
  NSURLRequest *request = [RCTConvert NSURLRequest:self.source];
1406
-
1969
+
1970
+ // If sharedCookiesEnabled we automatically add all application cookies to the
1971
+ // http request. This is automatically done on iOS 11+ in the WebView constructor.
1972
+ // Se we need to manually add these shared cookies here only for iOS versions < 11.
1973
+ if (_sharedCookiesEnabled) {
1974
+ if (@available(iOS 11.0, *)) {
1975
+ // see WKWebView initialization for added cookies
1976
+ } else if (request != nil) {
1977
+ NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL];
1978
+ NSDictionary<NSString *, NSString *> *cookieHeader = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
1979
+ NSMutableURLRequest *mutableRequest = [request mutableCopy];
1980
+ [mutableRequest setAllHTTPHeaderFields:cookieHeader];
1981
+ return mutableRequest;
1982
+ }
1983
+ }
1407
1984
  return request;
1408
1985
  }
1409
1986