diff --git a/packages/webview_flutter/webview_flutter_android/AUTHORS b/packages/webview_flutter/webview_flutter_android/AUTHORS index 4461b602a13b..22e2b0ef78fc 100644 --- a/packages/webview_flutter/webview_flutter_android/AUTHORS +++ b/packages/webview_flutter/webview_flutter_android/AUTHORS @@ -65,4 +65,5 @@ Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> Maurits van Beusekom +Nick Bradshaw diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index d4827a71e47d..c0837263509d 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.0 + +* Add `zoomEnabled` functionality. + ## 2.0.15 * Added Overrides in FlutterWebView.java diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index ff573c771960..b2a453adcdac 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -176,9 +176,10 @@ static WebView createWebView( .setJavaScriptCanOpenWindowsAutomatically( true) // Always allow automatically opening of windows. .setSupportMultipleWindows(true) // Always support multiple windows. - .setWebChromeClient(webChromeClient) - .setDownloadListener( - downloadListener); // Always use {@link FlutterWebChromeClient} as web Chrome client. + .setWebChromeClient( + webChromeClient) // Always use {@link FlutterWebChromeClient} as web Chrome client. + .setDownloadListener(downloadListener) + .setZoomControlsEnabled(true); // Always use built-in zoom mechanisms. return webViewBuilder.build(); } @@ -428,6 +429,9 @@ private void applySettings(Map settings) { case "allowsInlineMediaPlayback": // no-op inline media playback is always allowed on Android. break; + case "zoomEnabled": + setZoomEnabled((boolean) settings.get(key)); + break; default: throw new IllegalArgumentException("Unknown WebView setting: " + key); } @@ -467,6 +471,10 @@ private void updateUserAgent(String userAgent) { webView.getSettings().setUserAgentString(userAgent); } + private void setZoomEnabled(boolean shouldEnable) { + webView.getSettings().setSupportZoom(shouldEnable); + } + @Override public void dispose() { methodChannel.setMethodCallHandler(null); diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewBuilder.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewBuilder.java index d3cd1d57cdae..e0d5e8815f31 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewBuilder.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewBuilder.java @@ -46,6 +46,7 @@ static WebView create(Context context, boolean usesHybridComposition, View conta private boolean usesHybridComposition; private WebChromeClient webChromeClient; private DownloadListener downloadListener; + private boolean enableBuiltInZoomControls; /** * Constructs a new {@link WebViewBuilder} object with a custom implementation of the {@link @@ -136,6 +137,18 @@ public WebViewBuilder setDownloadListener(@Nullable DownloadListener downloadLis return this; } + /** + * Sets whether the {@link WebView} should use its built-in zoom mechanisms. The default value is + * {@code true}. + * + * @param flag {@code true} if built in zoom controls are allowed. + * @return This builder. This value cannot be {@code null}. + */ + public WebViewBuilder setZoomControlsEnabled(boolean flag) { + this.enableBuiltInZoomControls = flag; + return this; + } + /** * Build the {@link android.webkit.WebView} using the current settings. * @@ -148,6 +161,10 @@ public WebView build() { webSettings.setDomStorageEnabled(enableDomStorage); webSettings.setJavaScriptCanOpenWindowsAutomatically(javaScriptCanOpenWindowsAutomatically); webSettings.setSupportMultipleWindows(supportMultipleWindows); + webSettings.setLoadWithOverviewMode(true); + webSettings.setUseWideViewPort(true); + webSettings.setDisplayZoomControls(false); + webSettings.setBuiltInZoomControls(enableBuiltInZoomControls); webView.setWebChromeClient(webChromeClient); webView.setDownloadListener(downloadListener); return webView; diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewTest.java index 56d9db1ee493..fd79bccabbce 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewTest.java @@ -37,6 +37,7 @@ public void before() { .thenReturn(mockWebViewBuilder); when(mockWebViewBuilder.setSupportMultipleWindows(anyBoolean())).thenReturn(mockWebViewBuilder); when(mockWebViewBuilder.setUsesHybridComposition(anyBoolean())).thenReturn(mockWebViewBuilder); + when(mockWebViewBuilder.setZoomControlsEnabled(anyBoolean())).thenReturn(mockWebViewBuilder); when(mockWebViewBuilder.setWebChromeClient(any(WebChromeClient.class))) .thenReturn(mockWebViewBuilder); when(mockWebViewBuilder.setDownloadListener(any(DownloadListener.class))) @@ -55,6 +56,7 @@ public void createWebView_should_create_webview_with_default_configuration() { verify(mockWebViewBuilder, times(1)).setSupportMultipleWindows(true); verify(mockWebViewBuilder, times(1)).setUsesHybridComposition(false); verify(mockWebViewBuilder, times(1)).setWebChromeClient(mockWebChromeClient); + verify(mockWebViewBuilder, times(1)).setZoomControlsEnabled(true); } private Map createParameterMap(boolean usesHybridComposition) { diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart index 33773f96cad8..5e8a2798b8ca 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart @@ -72,6 +72,7 @@ class WebView extends StatefulWidget { this.debuggingEnabled = false, this.gestureNavigationEnabled = false, this.userAgent, + this.zoomEnabled = true, this.initialMediaPlaybackPolicy = AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, this.allowsInlineMediaPlayback = false, @@ -221,6 +222,11 @@ class WebView extends StatefulWidget { /// By default `gestureNavigationEnabled` is false. final bool gestureNavigationEnabled; + /// A Boolean value indicating whether the WebView should support zooming using its on-screen zoom controls and gestures. + /// + /// By default 'zoomEnabled' is true + final bool zoomEnabled; + /// The value used for the HTTP User-Agent: request header. /// /// When null the platform's webview default is used for the User-Agent header. @@ -553,12 +559,14 @@ class WebViewController { assert(newValue.hasNavigationDelegate != null); assert(newValue.debuggingEnabled != null); assert(newValue.userAgent != null); + assert(newValue.zoomEnabled != null); JavascriptMode? javascriptMode; bool? hasNavigationDelegate; bool? hasProgressTracking; bool? debuggingEnabled; WebSetting userAgent = WebSetting.absent(); + bool? zoomEnabled; if (currentValue.javascriptMode != newValue.javascriptMode) { javascriptMode = newValue.javascriptMode; } @@ -574,6 +582,9 @@ class WebViewController { if (currentValue.userAgent != newValue.userAgent) { userAgent = newValue.userAgent; } + if (currentValue.zoomEnabled != newValue.zoomEnabled) { + zoomEnabled = newValue.zoomEnabled; + } return WebSettings( javascriptMode: javascriptMode, @@ -581,6 +592,7 @@ class WebViewController { hasProgressTracking: hasProgressTracking, debuggingEnabled: debuggingEnabled, userAgent: userAgent, + zoomEnabled: zoomEnabled, ); } @@ -613,5 +625,6 @@ WebSettings _webSettingsFromWidget(WebView widget) { gestureNavigationEnabled: widget.gestureNavigationEnabled, allowsInlineMediaPlayback: widget.allowsInlineMediaPlayback, userAgent: WebSetting.of(widget.userAgent), + zoomEnabled: widget.zoomEnabled, ); } diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 04511e670d4c..577d37359af1 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 2.0.15 +version: 2.1.0 environment: sdk: ">=2.14.0 <3.0.0" @@ -19,8 +19,7 @@ flutter: dependencies: flutter: sdk: flutter - - webview_flutter_platform_interface: ^1.0.0 + webview_flutter_platform_interface: ^1.2.0 dev_dependencies: flutter_driver: diff --git a/packages/webview_flutter/webview_flutter_wkwebview/AUTHORS b/packages/webview_flutter/webview_flutter_wkwebview/AUTHORS index 78f9e5ad9f6b..4fa8b35fca8a 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/AUTHORS +++ b/packages/webview_flutter/webview_flutter_wkwebview/AUTHORS @@ -65,3 +65,5 @@ Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> Maurits van Beusekom +Antonino Di Natale +Nick Bradshaw diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index 242d79b4bd82..b75519af476c 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.0 + +* Add `zoomEnabled` functionality. + ## 2.0.14 * Update example App so navigation menu loads immediatly but only becomes available when `WebViewController` is available (same behavior as example App in webview_flutter package). diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m index eb6d1543ec07..a819a9b53d60 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m @@ -13,11 +13,19 @@ @interface FLTWKNavigationDelegateTests : XCTestCase @property(strong, nonatomic) FlutterMethodChannel *mockMethodChannel; @property(strong, nonatomic) FLTWKNavigationDelegate *navigationDelegate; +@property(strong, nonatomic) WKNavigation *navigation; @end @implementation FLTWKNavigationDelegateTests +NSString *const zoomDisablingJavascript = + @"var meta = document.createElement('meta');" + @"meta.name = 'viewport';" + @"meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0," + @"user-scalable=no';" + @"var head = document.getElementsByTagName('head')[0];head.appendChild(meta);"; + - (void)setUp { self.mockMethodChannel = OCMClassMock(FlutterMethodChannel.class); self.navigationDelegate = @@ -38,4 +46,27 @@ - (void)testWebViewWebContentProcessDidTerminateCallsRecourseErrorChannel { } } +- (void)testWebViewWebEvaluateJavaScriptSourceIsCorrectWhenShouldEnableZoomIsFalse { + WKWebView *webview = OCMClassMock(WKWebView.class); + WKNavigation *navigation = OCMClassMock(WKNavigation.class); + NSURL *testUrl = [[NSURL alloc] initWithString:@"www.example.com"]; + OCMStub([webview URL]).andReturn(testUrl); + + self.navigationDelegate.shouldEnableZoom = false; + [self.navigationDelegate webView:webview didFinishNavigation:navigation]; + OCMVerify([webview evaluateJavaScript:zoomDisablingJavascript completionHandler:nil]); +} + +- (void)testWebViewWebEvaluateJavaScriptShouldNotBeCalledWhenShouldEnableZoomIsTrue { + WKWebView *webview = OCMClassMock(WKWebView.class); + WKNavigation *navigation = OCMClassMock(WKNavigation.class); + NSURL *testUrl = [[NSURL alloc] initWithString:@"www.example.com"]; + OCMStub([webview URL]).andReturn(testUrl); + + self.navigationDelegate.shouldEnableZoom = true; + + OCMReject([webview evaluateJavaScript:zoomDisablingJavascript completionHandler:nil]); + [self.navigationDelegate webView:webview didFinishNavigation:navigation]; +} + @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart index ddb8e9b0f14f..d57499dcef50 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart @@ -4,9 +4,9 @@ import 'dart:async'; -import 'package:flutter/widgets.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; +import 'package:flutter/widgets.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart'; @@ -65,6 +65,7 @@ class WebView extends StatefulWidget { this.debuggingEnabled = false, this.gestureNavigationEnabled = false, this.userAgent, + this.zoomEnabled = true, this.initialMediaPlaybackPolicy = AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, this.allowsInlineMediaPlayback = false, @@ -213,6 +214,11 @@ class WebView extends StatefulWidget { /// By default `userAgent` is null. final String? userAgent; + /// A Boolean value indicating whether the WebView should support zooming using its on-screen zoom controls and gestures. + /// + /// By default 'zoomEnabled' is true + final bool zoomEnabled; + /// Which restrictions apply on automatic media playback. /// /// This initial value is applied to the platform's webview upon creation. Any following @@ -542,6 +548,7 @@ WebSettings _webSettingsFromWidget(WebView widget) { gestureNavigationEnabled: widget.gestureNavigationEnabled, allowsInlineMediaPlayback: widget.allowsInlineMediaPlayback, userAgent: WebSetting.of(widget.userAgent), + zoomEnabled: widget.zoomEnabled, ); } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.h index 31edadc8cc05..6531931c4cf4 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.h @@ -9,13 +9,18 @@ NS_ASSUME_NONNULL_BEGIN @interface FLTWKNavigationDelegate : NSObject -- (instancetype)initWithChannel:(FlutterMethodChannel*)channel; +- (instancetype)initWithChannel:(FlutterMethodChannel *)channel; /** * Whether to delegate navigation decisions over the method channel. */ @property(nonatomic, assign) BOOL hasDartNavigationDelegate; +/** + * Whether to allow zoom functionality on the WebView. + */ +@property(nonatomic, assign) BOOL shouldEnableZoom; + @end NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.m index 8b7ee7d0cfb7..125d3cabdcf1 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.m @@ -63,6 +63,17 @@ - (void)webView:(WKWebView *)webView } - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { + if (!self.shouldEnableZoom) { + NSString *source = + @"var meta = document.createElement('meta');" + @"meta.name = 'viewport';" + @"meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0," + @"user-scalable=no';" + @"var head = document.getElementsByTagName('head')[0];head.appendChild(meta);"; + + [webView evaluateJavaScript:source completionHandler:nil]; + } + [_methodChannel invokeMethod:@"onPageFinished" arguments:@{@"url" : webView.URL.absoluteString}]; } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m index c6d926d3cfc2..7fd78ee302d0 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m @@ -348,6 +348,9 @@ - (NSString*)applySettings:(NSDictionary*)settings { } else if ([key isEqualToString:@"userAgent"]) { NSString* userAgent = settings[key]; [self updateUserAgent:[userAgent isEqual:[NSNull null]] ? nil : userAgent]; + } else if ([key isEqualToString:@"zoomEnabled"]) { + NSNumber* zoomEnabled = settings[key]; + _navigationDelegate.shouldEnableZoom = [zoomEnabled boolValue]; } else { [unknownKeys addObject:key]; } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index a7305cea7a94..bfa4b8050e90 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_wkwebview description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control. repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_wkwebview issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 2.0.14 +version: 2.1.0 environment: sdk: ">=2.14.0 <3.0.0" @@ -18,8 +18,7 @@ flutter: dependencies: flutter: sdk: flutter - - webview_flutter_platform_interface: ^1.0.0 + webview_flutter_platform_interface: ^1.2.0 dev_dependencies: flutter_driver: