[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: