From df26e3eb61e0256b27d620bec512e98e3b141b5c Mon Sep 17 00:00:00 2001 From: DNA Date: Wed, 17 Jun 2020 00:01:19 +0200 Subject: [PATCH 1/4] Added possibility to activate the zoom webview - IOS & Android --- AUTHORS | 1 + .../webviewflutter/FlutterWebView.java | 19 +++++++++++++ .../webview_flutter/example/lib/main.dart | 1 + .../ios/Classes/FLTWKNavigationDelegate.h | 3 ++- .../ios/Classes/FLTWKNavigationDelegate.m | 1 + .../ios/Classes/FlutterWebView.m | 23 ++++++++++++++++ .../lib/platform_interface.dart | 6 ++++- .../lib/src/webview_method_channel.dart | 1 + .../webview_flutter/lib/webview_flutter.dart | 27 +++++++++++++++++++ 9 files changed, 80 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 17ede94e79ba..47e28a4a73cd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -58,3 +58,4 @@ Théo Champion Kazuki Yamaguchi Eitan Schwartz Chris Rutkowski +Antonino Di Natale 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..4907ec9514b6 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,26 @@ - (void)updateUserAgent:(NSString*)userAgent { } } +- (void)updateZoomEnabled:(NSNumber*)zoomEnabled { + BOOL enabled = [zoomEnabled boolValue]; + 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);"; + [_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, ); } From fdaca50f2c2cad5549b28abf8c9110816983906c Mon Sep 17 00:00:00 2001 From: Dn-a Date: Wed, 17 Jun 2020 00:52:21 +0200 Subject: [PATCH 2/4] Added possibility to activate the zoom webview - IOS & Android --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 47e28a4a73cd..8afaf84dae7a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -58,4 +58,4 @@ Théo Champion Kazuki Yamaguchi Eitan Schwartz Chris Rutkowski -Antonino Di Natale +Antonino Di Natale \ No newline at end of file From 460cd79546ed4d38b60682f93e23d07cadbc24f1 Mon Sep 17 00:00:00 2001 From: Dn-a Date: Wed, 17 Jun 2020 02:03:16 +0200 Subject: [PATCH 3/4] fix: implicitly retains 'self' on IOS; enabled zoom --- packages/webview_flutter/ios/Classes/FlutterWebView.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 4907ec9514b6..39559ba563f9 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -442,7 +442,8 @@ - (void)updateUserAgent:(NSString*)userAgent { - (void)updateZoomEnabled:(NSNumber*)zoomEnabled { BOOL enabled = [zoomEnabled boolValue]; - if (enabled) { + __typeof__(self) __strong wSelf = self; + if (!enabled) { _navigationDelegate.didFinishLoad = ^(WKNavigation* view) { NSString* source = @"var meta = document.createElement('meta'); \ meta.name = " @@ -453,7 +454,7 @@ - (void)updateZoomEnabled:(NSNumber*)zoomEnabled { @" var head = document.getElementsByTagName('head')[0];\ " @"head.appendChild(meta);"; - [_webView evaluateJavaScript:source completionHandler:nil]; + [wSelf->_webView evaluateJavaScript:source completionHandler:nil]; }; } else _navigationDelegate.didFinishLoad = ^(WKNavigation* view) { From 69df049fb874fbcae50298b163e5bc0559decae3 Mon Sep 17 00:00:00 2001 From: Dn-a Date: Wed, 17 Jun 2020 11:18:25 +0200 Subject: [PATCH 4/4] update: changelog & pubspec.yaml version --- packages/webview_flutter/CHANGELOG.md | 4 ++++ packages/webview_flutter/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) 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/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: