From 45cc819bf753e61409d19354d5ff4d1fc31f91ce Mon Sep 17 00:00:00 2001 From: Amir Hardon Date: Fri, 8 Mar 2019 19:41:40 -0800 Subject: [PATCH] Allow specifying a navigation delegate (iOS implementation). (#1323) This is the iOS implementation of the navigation delegate method channel. The Dart and Android implementations are in #1236 Splitting off the iOS to keep a reasonable change size. This PR will be merged first. flutter/flutter#25329 --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../xcshareddata/WorkspaceSettings.xcsettings | 8 +++ .../ios/Classes/FLTWKNavigationDelegate.h | 21 +++++++ .../ios/Classes/FLTWKNavigationDelegate.m | 59 +++++++++++++++++++ .../ios/Classes/FlutterWebView.m | 7 +++ 5 files changed, 103 insertions(+) create mode 100644 packages/webview_flutter/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/webview_flutter/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h create mode 100644 packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m diff --git a/packages/webview_flutter/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/webview_flutter/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/webview_flutter/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/webview_flutter/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/webview_flutter/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..949b67898200 --- /dev/null +++ b/packages/webview_flutter/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + BuildSystemType + Original + + diff --git a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h new file mode 100644 index 000000000000..1625c4999bd2 --- /dev/null +++ b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h @@ -0,0 +1,21 @@ +// 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 +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTWKNavigationDelegate : NSObject + +- (instancetype)initWithChannel:(FlutterMethodChannel*)channel; + +/** + * Whether to delegate navigation decisions over the method channel. + */ +@property(nonatomic, assign) BOOL hasDartNavigationDelegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m new file mode 100644 index 000000000000..3638ddcda117 --- /dev/null +++ b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m @@ -0,0 +1,59 @@ +// 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; +} + +- (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); + }]; +} + +@end diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 87d4d25bd9dc..ea3b192f47ff 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "FlutterWebView.h" +#import "FLTWKNavigationDelegate.h" #import "JavaScriptChannelHandler.h" @implementation FLTWebViewFactory { @@ -40,6 +41,7 @@ @implementation FLTWebViewController { NSString* _currentUrl; // The set of registered JavaScript channel names. NSMutableSet* _javaScriptChannelNames; + FLTWKNavigationDelegate* _navigationDelegate; } - (instancetype)initWithFrame:(CGRect)frame @@ -64,6 +66,8 @@ - (instancetype)initWithFrame:(CGRect)frame configuration.userContentController = userContentController; _webView = [[WKWebView alloc] initWithFrame:frame configuration:configuration]; + _navigationDelegate = [[FLTWKNavigationDelegate alloc] initWithChannel:_channel]; + _webView.navigationDelegate = _navigationDelegate; __weak __typeof__(self) weakSelf = self; [_channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { [weakSelf onMethodCall:call result:result]; @@ -229,6 +233,9 @@ - (void)applySettings:(NSDictionary*)settings { if ([key isEqualToString:@"jsMode"]) { NSNumber* mode = settings[key]; [self updateJsMode:mode]; + } else if ([key isEqualToString:@"hasNavigationDelegate"]) { + NSNumber* hasDartNavigationDelegate = settings[key]; + _navigationDelegate.hasDartNavigationDelegate = [hasDartNavigationDelegate boolValue]; } else { NSLog(@"webview_flutter: unknown setting key: %@", key); }