@exodus/react-native-webview 11.26.1-exodus.9 → 13.16.0-exodus.0
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.
- package/README.md +36 -63
- package/android/build.gradle +83 -110
- package/android/gradle.properties +3 -4
- package/android/src/main/AndroidManifest.xml +12 -0
- package/android/src/main/AndroidManifestNew.xml +26 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java +11 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java +407 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java +468 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +330 -0
- package/android/src/main/java/com/reactnativecommunity/webview/{WebViewConfig.java → RNCWebViewConfig.java} +3 -4
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java +1 -1
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt +746 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMessagingModule.kt +9 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java +554 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java +57 -12
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewWrapper.kt +39 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/SubResourceErrorEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt +24 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopHttpErrorEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopNewWindowEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopRenderProcessGoneEvent.kt +25 -0
- package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +570 -0
- package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java +57 -0
- package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java +341 -0
- package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java +59 -0
- package/apple/RCTConvert+WKDataDetectorTypes.h +11 -0
- package/apple/RCTConvert+WKDataDetectorTypes.m +27 -0
- package/apple/RNCWebView.h +26 -100
- package/apple/RNCWebView.mm +555 -0
- package/apple/RNCWebViewDecisionManager.h +20 -0
- package/apple/RNCWebViewDecisionManager.m +47 -0
- package/apple/RNCWebViewImpl.h +164 -0
- package/apple/{RNCWebView.m → RNCWebViewImpl.m} +803 -226
- package/apple/RNCWebViewManager.h +4 -8
- package/apple/RNCWebViewManager.mm +221 -0
- package/apple/RNCWebViewModule.h +23 -0
- package/apple/RNCWebViewModule.mm +34 -0
- package/index.d.ts +2 -3
- package/lib/NativeRNCWebViewModule.d.ts +8 -0
- package/lib/NativeRNCWebViewModule.js +1 -0
- package/lib/RNCWebViewNativeComponent.d.ts +245 -0
- package/lib/RNCWebViewNativeComponent.js +1 -0
- package/lib/WebView.android.d.ts +0 -1
- package/lib/WebView.android.js +1 -135
- package/lib/WebView.d.ts +2 -3
- package/lib/WebView.ios.d.ts +0 -1
- package/lib/WebView.ios.js +1 -114
- package/lib/WebView.js +1 -11
- package/lib/WebView.macos.d.ts +6 -0
- package/lib/WebView.macos.js +1 -0
- package/lib/WebView.styles.d.ts +37 -11
- package/lib/WebView.styles.js +1 -33
- package/lib/WebView.windows.d.ts +17 -0
- package/lib/WebView.windows.js +1 -0
- package/lib/WebViewNativeComponent.macos.d.ts +3 -0
- package/lib/WebViewNativeComponent.macos.js +1 -0
- package/lib/WebViewNativeComponent.windows.d.ts +3 -0
- package/lib/WebViewNativeComponent.windows.js +1 -0
- package/lib/WebViewShared.d.ts +30 -9
- package/lib/WebViewShared.js +1 -174
- package/lib/WebViewTypes.d.ts +514 -98
- package/lib/WebViewTypes.js +1 -6
- package/lib/index.d.ts +0 -1
- package/lib/index.js +1 -3
- package/lib/validation.d.ts +3 -0
- package/lib/validation.js +1 -0
- package/package.json +57 -33
- package/react-native-webview.podspec +32 -5
- package/react-native.config.js +22 -18
- package/src/NativeRNCWebViewModule.ts +13 -0
- package/src/RNCWebViewNativeComponent.ts +348 -0
- package/src/WebView.android.tsx +345 -0
- package/src/WebView.ios.tsx +341 -0
- package/src/WebView.macos.tsx +252 -0
- package/src/WebView.styles.ts +41 -0
- package/src/WebView.tsx +25 -0
- package/src/WebView.windows.tsx +217 -0
- package/src/WebViewNativeComponent.macos.ts +7 -0
- package/src/WebViewNativeComponent.windows.ts +8 -0
- package/src/WebViewShared.tsx +476 -0
- package/src/WebViewTypes.ts +1402 -0
- package/src/__tests__/WebViewShared-test.js +323 -0
- package/src/__tests__/__snapshots__/WebViewShared-test.js.snap +8 -0
- package/src/__tests__/validation-test.js +38 -0
- package/src/index.ts +4 -0
- package/src/validation.ts +20 -0
- package/android/.editorconfig +0 -6
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +0 -1408
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java +0 -506
- package/apple/RNCWebViewManager.m +0 -278
- package/lib/WebViewNativeComponent.android.d.ts +0 -4
- package/lib/WebViewNativeComponent.android.js +0 -3
- package/lib/WebViewNativeComponent.ios.d.ts +0 -4
- 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 "
|
|
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
|
|
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
|
|
33
|
+
@interface _SwizzleHelperWK : UIView
|
|
32
34
|
@property (nonatomic, copy) WKWebView *webView;
|
|
33
35
|
@end
|
|
34
|
-
@implementation
|
|
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
|
-
|
|
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
|
|
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
|
|
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 //
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
if (!self.menuItems || self.menuItems.count == 0) {
|
|
183
|
-
return;
|
|
265
|
+
if (pressSender.state != UIGestureRecognizerStateEnded || !self.menuItems) {
|
|
266
|
+
return;
|
|
184
267
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 //
|
|
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
|
-
#
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
874
|
+
if ([request.URL isEqual:webView.URL]) {
|
|
635
875
|
return;
|
|
636
876
|
}
|
|
637
877
|
if (!request.URL) {
|
|
638
878
|
// Clear the webview
|
|
639
|
-
[
|
|
879
|
+
[webView loadHTMLString:@"" baseURL:nil];
|
|
640
880
|
return;
|
|
641
881
|
}
|
|
642
882
|
if (request.URL.host) {
|
|
643
|
-
[
|
|
883
|
+
[webView loadRequest:request];
|
|
644
884
|
}
|
|
645
885
|
else {
|
|
646
|
-
|
|
647
|
-
|
|
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:@"%@
|
|
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([
|
|
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,13 +1098,26 @@ 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
|
|
835
1117
|
{
|
|
836
1118
|
NSDictionary *eventInitDict = @{@"data": message};
|
|
837
1119
|
NSString *source = [NSString
|
|
838
|
-
stringWithFormat:@"
|
|
1120
|
+
stringWithFormat:@"window.dispatchEvent(new MessageEvent('message', %@));",
|
|
839
1121
|
RCTJSONStringify(eventInitDict, NULL)
|
|
840
1122
|
];
|
|
841
1123
|
[self injectJavaScript: source];
|
|
@@ -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
|
|
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
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
@"
|
|
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
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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
|
-
|
|
1103
|
-
|
|
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 view
|
|
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.
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
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
|
-
|
|
1134
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
1328
|
-
"
|
|
1329
|
-
"
|
|
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 *
|
|
1386
|
-
[wkWebViewConfig.userContentController addUserScript:
|
|
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
|
|