diff --git a/AUTHORS b/AUTHORS index 17ede94e79ba..8afaf84dae7a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -58,3 +58,4 @@ Théo Champion Kazuki Yamaguchi Eitan Schwartz Chris Rutkowski +Antonino Di Natale \ No newline at end of file diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 04155a509b80..be30f096bb4f 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.23 + +* Added possibility to activate the zoom to WebView - IOS & Android. + ## 0.3.22+1 * Update the `setAndGetScrollPosition` to use hard coded values and add a `pumpAndSettle` call. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index f9659d9873f4..fbf668dc8956 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -317,6 +317,9 @@ private void applySettings(Map settings) { case "userAgent": updateUserAgent((String) settings.get(key)); break; + case "zoomEnabled": + updateZoomMode((boolean) settings.get(key)); + break; default: throw new IllegalArgumentException("Unknown WebView setting: " + key); } @@ -354,6 +357,22 @@ private void updateUserAgent(String userAgent) { webView.getSettings().setUserAgentString(userAgent); } + private void updateZoomMode(boolean mode) { + if (!mode) return; + // loads the WebView completely zoomed out + webView.getSettings().setLoadWithOverviewMode(true); + + // It loads the WebView with the attributes defined in the meta tag of the webpage. + // So it scales the webpage as defined in the html. + webView.getSettings().setUseWideViewPort(true); + + // Pop-up zoom controls disabled. This is a temporary stop because dialog is not responding to touch events. + webView.getSettings().setDisplayZoomControls(false); + + // enable zoom + webView.getSettings().setBuiltInZoomControls(true); + } + @Override public void dispose() { methodChannel.setMethodCallHandler(null); diff --git a/packages/webview_flutter/example/lib/main.dart b/packages/webview_flutter/example/lib/main.dart index 59c87a25dedf..0a5e9aa8b773 100644 --- a/packages/webview_flutter/example/lib/main.dart +++ b/packages/webview_flutter/example/lib/main.dart @@ -51,6 +51,7 @@ class _WebViewExampleState extends State { body: Builder(builder: (BuildContext context) { return WebView( initialUrl: 'https://flutter.dev', + zoomEnabled: true, javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController webViewController) { _controller.complete(webViewController); diff --git a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h index 1625c4999bd2..f626ecedca81 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h +++ b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h @@ -9,12 +9,13 @@ 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; +@property(nonatomic, copy) void (^didFinishLoad)(WKNavigation *navigation); @end diff --git a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m index dd9608d57ac0..18ea6aed6b33 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m +++ b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m @@ -63,6 +63,7 @@ - (void)webView:(WKWebView *)webView } - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { + self.didFinishLoad(navigation); [_methodChannel invokeMethod:@"onPageFinished" arguments:@{@"url" : webView.URL.absoluteString}]; } diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 969e010913f3..39559ba563f9 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -332,6 +332,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]; + [self updateZoomEnabled:zoomEnabled]; } else { [unknownKeys addObject:key]; } @@ -437,6 +440,27 @@ - (void)updateUserAgent:(NSString*)userAgent { } } +- (void)updateZoomEnabled:(NSNumber*)zoomEnabled { + BOOL enabled = [zoomEnabled boolValue]; + __typeof__(self) __strong wSelf = self; + if (!enabled) { + _navigationDelegate.didFinishLoad = ^(WKNavigation* view) { + 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);"; + [wSelf->_webView evaluateJavaScript:source completionHandler:nil]; + }; + } else + _navigationDelegate.didFinishLoad = ^(WKNavigation* view) { + }; +} + #pragma mark WKUIDelegate - (WKWebView*)webView:(WKWebView*)webView diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart index 0f848ecec4d4..4737412c6e85 100644 --- a/packages/webview_flutter/lib/platform_interface.dart +++ b/packages/webview_flutter/lib/platform_interface.dart @@ -383,6 +383,7 @@ class WebSettings { this.debuggingEnabled, this.gestureNavigationEnabled, @required this.userAgent, + this.zoomEnabled, }) : assert(userAgent != null); /// The JavaScript execution mode to be used by the webview. @@ -411,9 +412,12 @@ class WebSettings { /// See also: [WebView.gestureNavigationEnabled] final bool gestureNavigationEnabled; + /// Whether the [WebView] has a [WebView.zoomEnabled] set. + final bool zoomEnabled; + @override String toString() { - return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent)'; + return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent, zoomEnabled: $zoomEnabled)'; } } diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index 348b225bb257..60080da05857 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -181,6 +181,7 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { _addIfNonNull('debuggingEnabled', settings.debuggingEnabled); _addIfNonNull( 'gestureNavigationEnabled', settings.gestureNavigationEnabled); + _addIfNonNull('zoomEnabled', settings.zoomEnabled); _addSettingIfPresent('userAgent', settings.userAgent); return map; } diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 2635b0446fa2..b797c996904a 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -154,6 +154,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, }) : assert(javascriptMode != null), @@ -321,6 +322,24 @@ class WebView extends StatefulWidget { /// By default `userAgent` is null. final String userAgent; + /// Controls whether WebView zoom is enabled. + /// + /// Android: + /// - Fully zoomed WebView is enabled by default + /// - By default, WebView checks if there are attributes defined in the meta tag of the web page. + /// This allows you to resize the web page as defined in the html tag + /// - Pop-up zoom controls disabled. This is a temporary stop because dialog is not responding to touch events + /// + /// iOS: + /// Removing viewForZooming in the UIScrollViewDelegate method disables the pinch to zoom, + /// but not the double tap that keeps changing the zoom level. + /// The best solution was to inject JavaScript that adds this meta-tag: + /// + /// It works independently of the WKWebView configuration. + /// + /// 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 @@ -403,6 +422,7 @@ WebSettings _webSettingsFromWidget(WebView widget) { debuggingEnabled: widget.debuggingEnabled, gestureNavigationEnabled: widget.gestureNavigationEnabled, userAgent: WebSetting.of(widget.userAgent), + zoomEnabled: widget.zoomEnabled, ); } @@ -413,15 +433,18 @@ WebSettings _clearUnchangedWebSettings( assert(currentValue.hasNavigationDelegate != null); assert(currentValue.debuggingEnabled != null); assert(currentValue.userAgent.isPresent); + assert(currentValue.zoomEnabled != null); assert(newValue.javascriptMode != null); assert(newValue.hasNavigationDelegate != null); assert(newValue.debuggingEnabled != null); assert(newValue.userAgent.isPresent); + assert(newValue.zoomEnabled != null); JavascriptMode javascriptMode; bool hasNavigationDelegate; bool debuggingEnabled; WebSetting userAgent = WebSetting.absent(); + bool zoomEnabled; if (currentValue.javascriptMode != newValue.javascriptMode) { javascriptMode = newValue.javascriptMode; } @@ -434,12 +457,16 @@ WebSettings _clearUnchangedWebSettings( if (currentValue.userAgent != newValue.userAgent) { userAgent = newValue.userAgent; } + if (currentValue.zoomEnabled != newValue.zoomEnabled) { + zoomEnabled = newValue.zoomEnabled; + } return WebSettings( javascriptMode: javascriptMode, hasNavigationDelegate: hasNavigationDelegate, debuggingEnabled: debuggingEnabled, userAgent: userAgent, + zoomEnabled: zoomEnabled, ); } diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 2ccc3efcccef..8a4a62ea76a6 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 0.3.22+1 +version: 0.3.23 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: