[webview_flutter] Implement zoom enabled for ios and android (#4417)
diff --git a/packages/webview_flutter/webview_flutter_android/AUTHORS b/packages/webview_flutter/webview_flutter_android/AUTHORS
index 4461b60..22e2b0e 100644
--- a/packages/webview_flutter/webview_flutter_android/AUTHORS
+++ b/packages/webview_flutter/webview_flutter_android/AUTHORS
@@ -65,4 +65,5 @@
Alex Li <google@alexv525.com>
Rahul Raj <64.rahulraj@gmail.com>
Maurits van Beusekom <maurits@baseflow.com>
+Nick Bradshaw <nickalasb@gmail.com>
diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
index d4827a7..c083726 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 ff573c7..b2a453a 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 @@
.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 @@
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 @@
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 d3cd1d5..e0d5e88 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 @@
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
@@ -137,6 +138,18 @@
}
/**
+ * 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.
*
* @return The {@link android.webkit.WebView} using the current settings.
@@ -148,6 +161,10 @@
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 56d9db1..fd79bcc 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 @@
.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 @@
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<String, Object> 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 33773f9..5e8a279 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 @@
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 @@
/// 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 @@
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<String?> userAgent = WebSetting.absent();
+ bool? zoomEnabled;
if (currentValue.javascriptMode != newValue.javascriptMode) {
javascriptMode = newValue.javascriptMode;
}
@@ -574,6 +582,9 @@
if (currentValue.userAgent != newValue.userAgent) {
userAgent = newValue.userAgent;
}
+ if (currentValue.zoomEnabled != newValue.zoomEnabled) {
+ zoomEnabled = newValue.zoomEnabled;
+ }
return WebSettings(
javascriptMode: javascriptMode,
@@ -581,6 +592,7 @@
hasProgressTracking: hasProgressTracking,
debuggingEnabled: debuggingEnabled,
userAgent: userAgent,
+ zoomEnabled: zoomEnabled,
);
}
@@ -613,5 +625,6 @@
gestureNavigationEnabled: widget.gestureNavigationEnabled,
allowsInlineMediaPlayback: widget.allowsInlineMediaPlayback,
userAgent: WebSetting<String?>.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 04511e6..577d373 100644
--- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
@@ -2,7 +2,7 @@
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 @@
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 78f9e5a..4fa8b35 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/AUTHORS
+++ b/packages/webview_flutter/webview_flutter_wkwebview/AUTHORS
@@ -65,3 +65,5 @@
Alex Li <google@alexv525.com>
Rahul Raj <64.rahulraj@gmail.com>
Maurits van Beusekom <maurits@baseflow.com>
+Antonino Di Natale <gyorgio88@gmail.com>
+Nick Bradshaw <nickalasb@gmail.com>
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
index 242d79b..b75519a 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 eb6d154..a819a9b 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 @@
@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)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 ddb8e9b..d57499d 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 @@
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 @@
/// 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 @@
gestureNavigationEnabled: widget.gestureNavigationEnabled,
allowsInlineMediaPlayback: widget.allowsInlineMediaPlayback,
userAgent: WebSetting<String?>.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 31edadc..6531931 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 @@
@interface FLTWKNavigationDelegate : NSObject <WKNavigationDelegate>
-- (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 8b7ee7d..125d3ca 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 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 c6d926d..7fd78ee 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 @@
} 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 a7305ce..bfa4b80 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
@@ -2,7 +2,7 @@
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 @@
dependencies:
flutter:
sdk: flutter
-
- webview_flutter_platform_interface: ^1.0.0
+ webview_flutter_platform_interface: ^1.2.0
dev_dependencies:
flutter_driver: