|
@@ -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,6 +161,31 @@ static NSDictionary* customCertificatesForHost;
|
152
|
161
|
}
|
153
|
162
|
wkWebViewConfig.userContentController = [WKUserContentController new];
|
154
|
163
|
|
|
164
|
+ // Shim the HTML5 history API:
|
|
165
|
+ [wkWebViewConfig.userContentController addScriptMessageHandler:self name:HistoryShimName];
|
|
166
|
+ NSString *source = [NSString stringWithFormat:
|
|
167
|
+ @"(function(history) {\n"
|
|
168
|
+ " function notify(type) {\n"
|
|
169
|
+ " setTimeout(function() {\n"
|
|
170
|
+ " window.webkit.messageHandlers.%@.postMessage(type)\n"
|
|
171
|
+ " }, 0)\n"
|
|
172
|
+ " }\n"
|
|
173
|
+ " function shim(f) {\n"
|
|
174
|
+ " return function pushState() {\n"
|
|
175
|
+ " notify('other')\n"
|
|
176
|
+ " return f.apply(history, arguments)\n"
|
|
177
|
+ " }\n"
|
|
178
|
+ " }\n"
|
|
179
|
+ " history.pushState = shim(history.pushState)\n"
|
|
180
|
+ " history.replaceState = shim(history.replaceState)\n"
|
|
181
|
+ " window.addEventListener('popstate', function() {\n"
|
|
182
|
+ " notify('backforward')\n"
|
|
183
|
+ " })\n"
|
|
184
|
+ "})(window.history)\n", HistoryShimName
|
|
185
|
+ ];
|
|
186
|
+ WKUserScript *script = [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
|
|
187
|
+ [wkWebViewConfig.userContentController addUserScript:script];
|
|
188
|
+
|
155
|
189
|
if (_messagingEnabled) {
|
156
|
190
|
[wkWebViewConfig.userContentController addScriptMessageHandler:self name:MessageHandlerName];
|
157
|
191
|
|
|
@@ -165,6 +199,12 @@ static NSDictionary* customCertificatesForHost;
|
165
|
199
|
|
166
|
200
|
WKUserScript *script = [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
|
167
|
201
|
[wkWebViewConfig.userContentController addUserScript:script];
|
|
202
|
+
|
|
203
|
+ if (_injectedJavaScriptBeforeContentLoaded) {
|
|
204
|
+ // If user has provided an injectedJavascript prop, execute it at the start of the document
|
|
205
|
+ WKUserScript *injectedScript = [[WKUserScript alloc] initWithSource:_injectedJavaScriptBeforeContentLoaded injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
|
|
206
|
+ [wkWebViewConfig.userContentController addUserScript:injectedScript];
|
|
207
|
+ }
|
168
|
208
|
}
|
169
|
209
|
|
170
|
210
|
wkWebViewConfig.allowsInlineMediaPlayback = _allowsInlineMediaPlayback;
|
|
@@ -390,10 +430,18 @@ static NSDictionary* customCertificatesForHost;
|
390
|
430
|
- (void)userContentController:(WKUserContentController *)userContentController
|
391
|
431
|
didReceiveScriptMessage:(WKScriptMessage *)message
|
392
|
432
|
{
|
393
|
|
- if (_onMessage != nil) {
|
394
|
|
- NSMutableDictionary<NSString *, id> *event = [self baseEvent];
|
395
|
|
- [event addEntriesFromDictionary: @{@"data": message.body}];
|
396
|
|
- _onMessage(event);
|
|
433
|
+ if ([message.name isEqualToString:HistoryShimName]) {
|
|
434
|
+ if (_onLoadingFinish) {
|
|
435
|
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
|
|
436
|
+ [event addEntriesFromDictionary: @{@"navigationType": message.body}];
|
|
437
|
+ _onLoadingFinish(event);
|
|
438
|
+ }
|
|
439
|
+ } else if ([message.name isEqualToString:MessageHandlerName]) {
|
|
440
|
+ if (_onMessage) {
|
|
441
|
+ NSMutableDictionary<NSString *, id> *event = [self baseEvent];
|
|
442
|
+ [event addEntriesFromDictionary: @{@"data": message.body}];
|
|
443
|
+ _onMessage(event);
|
|
444
|
+ }
|
397
|
445
|
}
|
398
|
446
|
}
|
399
|
447
|
|
|
@@ -922,7 +970,7 @@ static NSDictionary* customCertificatesForHost;
|
922
|
970
|
return;
|
923
|
971
|
}
|
924
|
972
|
|
925
|
|
- if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102) {
|
|
973
|
+ if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102 || [error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 101) {
|
926
|
974
|
// Error code 102 "Frame load interrupted" is raised by the WKWebView
|
927
|
975
|
// when the URL is from an http redirect. This is a common pattern when
|
928
|
976
|
// implementing OAuth with a WebView.
|
|
@@ -957,19 +1005,19 @@ static NSDictionary* customCertificatesForHost;
|
957
|
1005
|
* Called when the navigation is complete.
|
958
|
1006
|
* @see https://fburl.com/rtys6jlb
|
959
|
1007
|
*/
|
960
|
|
-- (void) webView:(WKWebView *)webView
|
|
1008
|
+- (void)webView:(WKWebView *)webView
|
961
|
1009
|
didFinishNavigation:(WKNavigation *)navigation
|
962
|
1010
|
{
|
963
|
|
- if (_injectedJavaScript) {
|
964
|
|
- [self evaluateJS: _injectedJavaScript thenCall: ^(NSString *jsEvaluationValue) {
|
965
|
|
- NSMutableDictionary *event = [self baseEvent];
|
966
|
|
- event[@"jsEvaluationValue"] = jsEvaluationValue;
|
967
|
|
-
|
968
|
|
- if (self.onLoadingFinish) {
|
969
|
|
- self.onLoadingFinish(event);
|
970
|
|
- }
|
971
|
|
- }];
|
972
|
|
- } else if (_onLoadingFinish) {
|
|
1011
|
+ if (_injectedJavaScript) {
|
|
1012
|
+ [self evaluateJS: _injectedJavaScript thenCall: ^(NSString *jsEvaluationValue) {
|
|
1013
|
+ NSMutableDictionary *event = [self baseEvent];
|
|
1014
|
+ event[@"jsEvaluationValue"] = jsEvaluationValue;
|
|
1015
|
+
|
|
1016
|
+ if (self.onLoadingFinish) {
|
|
1017
|
+ self.onLoadingFinish(event);
|
|
1018
|
+ }
|
|
1019
|
+ }];
|
|
1020
|
+ } else if (_onLoadingFinish) {
|
973
|
1021
|
_onLoadingFinish([self baseEvent]);
|
974
|
1022
|
}
|
975
|
1023
|
}
|