blob: 7eb08daea40e38f753d710886852d747dd893faa [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "FLTWKNavigationDelegate.h"
@implementation FLTWKNavigationDelegate {
FlutterMethodChannel *_methodChannel;
}
- (instancetype)initWithChannel:(FlutterMethodChannel *)channel {
self = [super init];
if (self) {
_methodChannel = channel;
}
return self;
}
#pragma mark - WKNavigationDelegate conformance
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
[_methodChannel invokeMethod:@"onPageStarted" arguments:@{@"url" : webView.URL.absoluteString}];
}
- (void)webView:(WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
if (!self.hasDartNavigationDelegate) {
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
NSDictionary *arguments = @{
@"url" : navigationAction.request.URL.absoluteString,
@"isForMainFrame" : @(navigationAction.targetFrame.isMainFrame)
};
[_methodChannel invokeMethod:@"navigationRequest"
arguments:arguments
result:^(id _Nullable result) {
if ([result isKindOfClass:[FlutterError class]]) {
NSLog(@"navigationRequest has unexpectedly completed with an error, "
@"allowing navigation.");
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
if (result == FlutterMethodNotImplemented) {
NSLog(@"navigationRequest was unexepectedly not implemented: %@, "
@"allowing navigation.",
result);
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
if (![result isKindOfClass:[NSNumber class]]) {
NSLog(@"navigationRequest unexpectedly returned a non boolean value: "
@"%@, allowing navigation.",
result);
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
NSNumber *typedResult = result;
decisionHandler([typedResult boolValue] ? WKNavigationActionPolicyAllow
: WKNavigationActionPolicyCancel);
}];
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[_methodChannel invokeMethod:@"onPageFinished" arguments:@{@"url" : webView.URL.absoluteString}];
}
+ (id)errorCodeToString:(NSUInteger)code {
switch (code) {
case WKErrorUnknown:
return @"unknown";
case WKErrorWebContentProcessTerminated:
return @"webContentProcessTerminated";
case WKErrorWebViewInvalidated:
return @"webViewInvalidated";
case WKErrorJavaScriptExceptionOccurred:
return @"javaScriptExceptionOccurred";
case WKErrorJavaScriptResultTypeIsUnsupported:
return @"javaScriptResultTypeIsUnsupported";
}
return [NSNull null];
}
- (void)onWebResourceError:(NSError *)error {
[_methodChannel invokeMethod:@"onWebResourceError"
arguments:@{
@"errorCode" : @(error.code),
@"domain" : error.domain,
@"description" : error.description,
@"errorType" : [FLTWKNavigationDelegate errorCodeToString:error.code],
}];
}
- (void)webView:(WKWebView *)webView
didFailNavigation:(WKNavigation *)navigation
withError:(NSError *)error {
[self onWebResourceError:error];
}
- (void)webView:(WKWebView *)webView
didFailProvisionalNavigation:(WKNavigation *)navigation
withError:(NSError *)error {
[self onWebResourceError:error];
}
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
NSError *contentProcessTerminatedError =
[[NSError alloc] initWithDomain:WKErrorDomain
code:WKErrorWebContentProcessTerminated
userInfo:nil];
[self onWebResourceError:contentProcessTerminatedError];
}
@end