|
@@ -14,6 +14,7 @@
|
14
|
14
|
#import "objc/runtime.h"
|
15
|
15
|
|
16
|
16
|
static NSTimer *keyboardTimer;
|
|
17
|
+static NSString *const HistoryShimName = @"ReactNativeHistoryShim";
|
17
|
18
|
static NSString *const MessageHandlerName = @"ReactNativeWebView";
|
18
|
19
|
static NSURLCredential* clientAuthenticationCredential;
|
19
|
20
|
static NSDictionary* customCertificatesForHost;
|
|
@@ -138,8 +139,16 @@ static NSDictionary* customCertificatesForHost;
|
138
|
139
|
if (self.window != nil && _webView == nil) {
|
139
|
140
|
WKWebViewConfiguration *wkWebViewConfig = [WKWebViewConfiguration new];
|
140
|
141
|
WKPreferences *prefs = [[WKPreferences alloc]init];
|
|
142
|
+ BOOL _prefsUsed = NO;
|
141
|
143
|
if (!_javaScriptEnabled) {
|
142
|
144
|
prefs.javaScriptEnabled = NO;
|
|
145
|
+ _prefsUsed = YES;
|
|
146
|
+ }
|
|
147
|
+ if (_allowFileAccessFromFileURLs) {
|
|
148
|
+ [prefs setValue:@TRUE forKey:@"allowFileAccessFromFileURLs"];
|
|
149
|
+ _prefsUsed = YES;
|
|
150
|
+ }
|
|
151
|
+ if (_prefsUsed) {
|
143
|
152
|
wkWebViewConfig.preferences = prefs;
|
144
|
153
|
}
|
145
|
154
|
if (_incognito) {
|
|
@@ -152,8 +161,35 @@ static NSDictionary* customCertificatesForHost;
|
152
|
161
|
}
|
153
|
162
|
wkWebViewConfig.userContentController = [WKUserContentController new];
|
154
|
163
|
|
|
164
|
+ // Shim the HTML5 history API:
|
|
165
|
+ [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self]
|
|
166
|
+ name:HistoryShimName];
|
|
167
|
+ NSString *source = [NSString stringWithFormat:
|
|
168
|
+ @"(function(history) {\n"
|
|
169
|
+ " function notify(type) {\n"
|
|
170
|
+ " setTimeout(function() {\n"
|
|
171
|
+ " window.webkit.messageHandlers.%@.postMessage(type)\n"
|
|
172
|
+ " }, 0)\n"
|
|
173
|
+ " }\n"
|
|
174
|
+ " function shim(f) {\n"
|
|
175
|
+ " return function pushState() {\n"
|
|
176
|
+ " notify('other')\n"
|
|
177
|
+ " return f.apply(history, arguments)\n"
|
|
178
|
+ " }\n"
|
|
179
|
+ " }\n"
|
|
180
|
+ " history.pushState = shim(history.pushState)\n"
|
|
181
|
+ " history.replaceState = shim(history.replaceState)\n"
|
|
182
|
+ " window.addEventListener('popstate', function() {\n"
|
|
183
|
+ " notify('backforward')\n"
|
|
184
|
+ " })\n"
|
|
185
|
+ "})(window.history)\n", HistoryShimName
|
|
186
|
+ ];
|
|
187
|
+ WKUserScript *script = [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
|
|
188
|
+ [wkWebViewConfig.userContentController addUserScript:script];
|
|
189
|
+
|
155
|
190
|
if (_messagingEnabled) {
|
156
|
|
- [wkWebViewConfig.userContentController addScriptMessageHandler:self name:MessageHandlerName];
|
|
191
|
+ [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self]
|
|
192
|
+ name:MessageHandlerName];
|
157
|
193
|
|
158
|
194
|
NSString *source = [NSString stringWithFormat:
|
159
|
195
|
@"window.%@ = {"
|
|
@@ -165,6 +201,12 @@ static NSDictionary* customCertificatesForHost;
|
165
|
201
|
|
166
|
202
|
WKUserScript *script = [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
|
167
|
203
|
[wkWebViewConfig.userContentController addUserScript:script];
|
|
204
|
+
|
|
205
|
+ if (_injectedJavaScriptBeforeContentLoaded) {
|
|
206
|
+ // If user has provided an injectedJavascript prop, execute it at the start of the document
|
|
207
|
+ WKUserScript *injectedScript = [[WKUserScript alloc] initWithSource:_injectedJavaScriptBeforeContentLoaded injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
|
|
208
|
+ [wkWebViewConfig.userContentController addUserScript:injectedScript];
|
|
209
|
+ }
|
168
|
210
|
}
|
169
|
211
|
|
170
|
212
|
wkWebViewConfig.allowsInlineMediaPlayback = _allowsInlineMediaPlayback;
|
|
@@ -390,10 +432,18 @@ static NSDictionary* customCertificatesForHost;
|
390
|
432
|
- (void)userContentController:(WKUserContentController *)userContentController
|
391
|
433
|
didReceiveScriptMessage:(WKScriptMessage *)message
|
392
|
434
|
{
|
393
|
|
- if (_onMessage != nil) {
|
394
|
|
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
|
395
|
|
- [event addEntriesFromDictionary: @{@"data": message.body}];
|
396
|
|
- _onMessage(event);
|
|
435
|
+ if ([message.name isEqualToString:HistoryShimName]) {
|
|
436
|
+ if (_onLoadingFinish) {
|
|
437
|
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
|
|
438
|
+ [event addEntriesFromDictionary: @{@"navigationType": message.body}];
|
|
439
|
+ _onLoadingFinish(event);
|
|
440
|
+ }
|
|
441
|
+ } else if ([message.name isEqualToString:MessageHandlerName]) {
|
|
442
|
+ if (_onMessage) {
|
|
443
|
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
|
|
444
|
+ [event addEntriesFromDictionary: @{@"data": message.body}];
|
|
445
|
+ _onMessage(event);
|
|
446
|
+ }
|
397
|
447
|
}
|
398
|
448
|
}
|
399
|
449
|
|
|
@@ -914,7 +964,7 @@ static NSDictionary* customCertificatesForHost;
|
914
|
964
|
return;
|
915
|
965
|
}
|
916
|
966
|
|
917
|
|
- if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102) {
|
|
967
|
+ if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102 || [error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 101) {
|
918
|
968
|
// Error code 102 "Frame load interrupted" is raised by the WKWebView
|
919
|
969
|
// when the URL is from an http redirect. This is a common pattern when
|
920
|
970
|
// implementing OAuth with a WebView.
|
|
@@ -949,19 +999,19 @@ static NSDictionary* customCertificatesForHost;
|
949
|
999
|
* Called when the navigation is complete.
|
950
|
1000
|
* @see https://fburl.com/rtys6jlb
|
951
|
1001
|
*/
|
952
|
|
-- (void) webView:(WKWebView *)webView
|
|
1002
|
+- (void)webView:(WKWebView *)webView
|
953
|
1003
|
didFinishNavigation:(WKNavigation *)navigation
|
954
|
1004
|
{
|
955
|
|
- if (_injectedJavaScript) {
|
956
|
|
- [self evaluateJS: _injectedJavaScript thenCall: ^(NSString *jsEvaluationValue) {
|
957
|
|
- NSMutableDictionary *event = [self baseEvent];
|
958
|
|
- event[@"jsEvaluationValue"] = jsEvaluationValue;
|
959
|
|
-
|
960
|
|
- if (self.onLoadingFinish) {
|
961
|
|
- self.onLoadingFinish(event);
|
962
|
|
- }
|
963
|
|
- }];
|
964
|
|
- } else if (_onLoadingFinish) {
|
|
1005
|
+ if (_injectedJavaScript) {
|
|
1006
|
+ [self evaluateJS: _injectedJavaScript thenCall: ^(NSString *jsEvaluationValue) {
|
|
1007
|
+ NSMutableDictionary *event = [self baseEvent];
|
|
1008
|
+ event[@"jsEvaluationValue"] = jsEvaluationValue;
|
|
1009
|
+
|
|
1010
|
+ if (self.onLoadingFinish) {
|
|
1011
|
+ self.onLoadingFinish(event);
|
|
1012
|
+ }
|
|
1013
|
+ }];
|
|
1014
|
+ } else if (_onLoadingFinish) {
|
965
|
1015
|
_onLoadingFinish([self baseEvent]);
|
966
|
1016
|
}
|
967
|
1017
|
}
|
|
@@ -1029,3 +1079,20 @@ static NSDictionary* customCertificatesForHost;
|
1029
|
1079
|
}
|
1030
|
1080
|
|
1031
|
1081
|
@end
|
|
1082
|
+
|
|
1083
|
+@implementation RNCWeakScriptMessageDelegate
|
|
1084
|
+
|
|
1085
|
+- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
|
|
1086
|
+ self = [super init];
|
|
1087
|
+ if (self) {
|
|
1088
|
+ _scriptDelegate = scriptDelegate;
|
|
1089
|
+ }
|
|
1090
|
+ return self;
|
|
1091
|
+}
|
|
1092
|
+
|
|
1093
|
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
|
|
1094
|
+ [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
|
|
1095
|
+}
|
|
1096
|
+
|
|
1097
|
+@end
|
|
1098
|
+
|