Skip to content

Commit bb62aaa

Browse files
authored
[webview_flutter] Implement zoom enabled for ios and android (flutter#4417)
1 parent 984015d commit bb62aaa

File tree

15 files changed

+117
-11
lines changed

15 files changed

+117
-11
lines changed

packages/webview_flutter/webview_flutter_android/AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,5 @@ Anton Borries <[email protected]>
6565
6666
Rahul Raj <[email protected]>
6767
Maurits van Beusekom <[email protected]>
68+
Nick Bradshaw <[email protected]>
6869

packages/webview_flutter/webview_flutter_android/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.1.0
2+
3+
* Add `zoomEnabled` functionality.
4+
15
## 2.0.15
26

37
* Added Overrides in FlutterWebView.java

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,10 @@ static WebView createWebView(
176176
.setJavaScriptCanOpenWindowsAutomatically(
177177
true) // Always allow automatically opening of windows.
178178
.setSupportMultipleWindows(true) // Always support multiple windows.
179-
.setWebChromeClient(webChromeClient)
180-
.setDownloadListener(
181-
downloadListener); // Always use {@link FlutterWebChromeClient} as web Chrome client.
179+
.setWebChromeClient(
180+
webChromeClient) // Always use {@link FlutterWebChromeClient} as web Chrome client.
181+
.setDownloadListener(downloadListener)
182+
.setZoomControlsEnabled(true); // Always use built-in zoom mechanisms.
182183

183184
return webViewBuilder.build();
184185
}
@@ -428,6 +429,9 @@ private void applySettings(Map<String, Object> settings) {
428429
case "allowsInlineMediaPlayback":
429430
// no-op inline media playback is always allowed on Android.
430431
break;
432+
case "zoomEnabled":
433+
setZoomEnabled((boolean) settings.get(key));
434+
break;
431435
default:
432436
throw new IllegalArgumentException("Unknown WebView setting: " + key);
433437
}
@@ -467,6 +471,10 @@ private void updateUserAgent(String userAgent) {
467471
webView.getSettings().setUserAgentString(userAgent);
468472
}
469473

474+
private void setZoomEnabled(boolean shouldEnable) {
475+
webView.getSettings().setSupportZoom(shouldEnable);
476+
}
477+
470478
@Override
471479
public void dispose() {
472480
methodChannel.setMethodCallHandler(null);

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewBuilder.java

+17
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ static WebView create(Context context, boolean usesHybridComposition, View conta
4646
private boolean usesHybridComposition;
4747
private WebChromeClient webChromeClient;
4848
private DownloadListener downloadListener;
49+
private boolean enableBuiltInZoomControls;
4950

5051
/**
5152
* Constructs a new {@link WebViewBuilder} object with a custom implementation of the {@link
@@ -136,6 +137,18 @@ public WebViewBuilder setDownloadListener(@Nullable DownloadListener downloadLis
136137
return this;
137138
}
138139

140+
/**
141+
* Sets whether the {@link WebView} should use its built-in zoom mechanisms. The default value is
142+
* {@code true}.
143+
*
144+
* @param flag {@code true} if built in zoom controls are allowed.
145+
* @return This builder. This value cannot be {@code null}.
146+
*/
147+
public WebViewBuilder setZoomControlsEnabled(boolean flag) {
148+
this.enableBuiltInZoomControls = flag;
149+
return this;
150+
}
151+
139152
/**
140153
* Build the {@link android.webkit.WebView} using the current settings.
141154
*
@@ -148,6 +161,10 @@ public WebView build() {
148161
webSettings.setDomStorageEnabled(enableDomStorage);
149162
webSettings.setJavaScriptCanOpenWindowsAutomatically(javaScriptCanOpenWindowsAutomatically);
150163
webSettings.setSupportMultipleWindows(supportMultipleWindows);
164+
webSettings.setLoadWithOverviewMode(true);
165+
webSettings.setUseWideViewPort(true);
166+
webSettings.setDisplayZoomControls(false);
167+
webSettings.setBuiltInZoomControls(enableBuiltInZoomControls);
151168
webView.setWebChromeClient(webChromeClient);
152169
webView.setDownloadListener(downloadListener);
153170
return webView;

packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public void before() {
3737
.thenReturn(mockWebViewBuilder);
3838
when(mockWebViewBuilder.setSupportMultipleWindows(anyBoolean())).thenReturn(mockWebViewBuilder);
3939
when(mockWebViewBuilder.setUsesHybridComposition(anyBoolean())).thenReturn(mockWebViewBuilder);
40+
when(mockWebViewBuilder.setZoomControlsEnabled(anyBoolean())).thenReturn(mockWebViewBuilder);
4041
when(mockWebViewBuilder.setWebChromeClient(any(WebChromeClient.class)))
4142
.thenReturn(mockWebViewBuilder);
4243
when(mockWebViewBuilder.setDownloadListener(any(DownloadListener.class)))
@@ -55,6 +56,7 @@ public void createWebView_should_create_webview_with_default_configuration() {
5556
verify(mockWebViewBuilder, times(1)).setSupportMultipleWindows(true);
5657
verify(mockWebViewBuilder, times(1)).setUsesHybridComposition(false);
5758
verify(mockWebViewBuilder, times(1)).setWebChromeClient(mockWebChromeClient);
59+
verify(mockWebViewBuilder, times(1)).setZoomControlsEnabled(true);
5860
}
5961

6062
private Map<String, Object> createParameterMap(boolean usesHybridComposition) {

packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart

+13
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class WebView extends StatefulWidget {
7272
this.debuggingEnabled = false,
7373
this.gestureNavigationEnabled = false,
7474
this.userAgent,
75+
this.zoomEnabled = true,
7576
this.initialMediaPlaybackPolicy =
7677
AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
7778
this.allowsInlineMediaPlayback = false,
@@ -221,6 +222,11 @@ class WebView extends StatefulWidget {
221222
/// By default `gestureNavigationEnabled` is false.
222223
final bool gestureNavigationEnabled;
223224

225+
/// A Boolean value indicating whether the WebView should support zooming using its on-screen zoom controls and gestures.
226+
///
227+
/// By default 'zoomEnabled' is true
228+
final bool zoomEnabled;
229+
224230
/// The value used for the HTTP User-Agent: request header.
225231
///
226232
/// When null the platform's webview default is used for the User-Agent header.
@@ -553,12 +559,14 @@ class WebViewController {
553559
assert(newValue.hasNavigationDelegate != null);
554560
assert(newValue.debuggingEnabled != null);
555561
assert(newValue.userAgent != null);
562+
assert(newValue.zoomEnabled != null);
556563

557564
JavascriptMode? javascriptMode;
558565
bool? hasNavigationDelegate;
559566
bool? hasProgressTracking;
560567
bool? debuggingEnabled;
561568
WebSetting<String?> userAgent = WebSetting.absent();
569+
bool? zoomEnabled;
562570
if (currentValue.javascriptMode != newValue.javascriptMode) {
563571
javascriptMode = newValue.javascriptMode;
564572
}
@@ -574,13 +582,17 @@ class WebViewController {
574582
if (currentValue.userAgent != newValue.userAgent) {
575583
userAgent = newValue.userAgent;
576584
}
585+
if (currentValue.zoomEnabled != newValue.zoomEnabled) {
586+
zoomEnabled = newValue.zoomEnabled;
587+
}
577588

578589
return WebSettings(
579590
javascriptMode: javascriptMode,
580591
hasNavigationDelegate: hasNavigationDelegate,
581592
hasProgressTracking: hasProgressTracking,
582593
debuggingEnabled: debuggingEnabled,
583594
userAgent: userAgent,
595+
zoomEnabled: zoomEnabled,
584596
);
585597
}
586598

@@ -613,5 +625,6 @@ WebSettings _webSettingsFromWidget(WebView widget) {
613625
gestureNavigationEnabled: widget.gestureNavigationEnabled,
614626
allowsInlineMediaPlayback: widget.allowsInlineMediaPlayback,
615627
userAgent: WebSetting<String?>.of(widget.userAgent),
628+
zoomEnabled: widget.zoomEnabled,
616629
);
617630
}

packages/webview_flutter/webview_flutter_android/pubspec.yaml

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter_android
22
description: A Flutter plugin that provides a WebView widget on Android.
33
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 2.0.15
5+
version: 2.1.0
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"
@@ -19,8 +19,7 @@ flutter:
1919
dependencies:
2020
flutter:
2121
sdk: flutter
22-
23-
webview_flutter_platform_interface: ^1.0.0
22+
webview_flutter_platform_interface: ^1.2.0
2423

2524
dev_dependencies:
2625
flutter_driver:

packages/webview_flutter/webview_flutter_wkwebview/AUTHORS

+2
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,5 @@ Anton Borries <[email protected]>
6565
6666
Rahul Raj <[email protected]>
6767
Maurits van Beusekom <[email protected]>
68+
Antonino Di Natale <[email protected]>
69+
Nick Bradshaw <[email protected]>

packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.1.0
2+
3+
* Add `zoomEnabled` functionality.
4+
15
## 2.0.14
26

37
* 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).

packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m

+31
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,19 @@ @interface FLTWKNavigationDelegateTests : XCTestCase
1313

1414
@property(strong, nonatomic) FlutterMethodChannel *mockMethodChannel;
1515
@property(strong, nonatomic) FLTWKNavigationDelegate *navigationDelegate;
16+
@property(strong, nonatomic) WKNavigation *navigation;
1617

1718
@end
1819

1920
@implementation FLTWKNavigationDelegateTests
2021

22+
NSString *const zoomDisablingJavascript =
23+
@"var meta = document.createElement('meta');"
24+
@"meta.name = 'viewport';"
25+
@"meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0,"
26+
@"user-scalable=no';"
27+
@"var head = document.getElementsByTagName('head')[0];head.appendChild(meta);";
28+
2129
- (void)setUp {
2230
self.mockMethodChannel = OCMClassMock(FlutterMethodChannel.class);
2331
self.navigationDelegate =
@@ -38,4 +46,27 @@ - (void)testWebViewWebContentProcessDidTerminateCallsRecourseErrorChannel {
3846
}
3947
}
4048

49+
- (void)testWebViewWebEvaluateJavaScriptSourceIsCorrectWhenShouldEnableZoomIsFalse {
50+
WKWebView *webview = OCMClassMock(WKWebView.class);
51+
WKNavigation *navigation = OCMClassMock(WKNavigation.class);
52+
NSURL *testUrl = [[NSURL alloc] initWithString:@"www.example.com"];
53+
OCMStub([webview URL]).andReturn(testUrl);
54+
55+
self.navigationDelegate.shouldEnableZoom = false;
56+
[self.navigationDelegate webView:webview didFinishNavigation:navigation];
57+
OCMVerify([webview evaluateJavaScript:zoomDisablingJavascript completionHandler:nil]);
58+
}
59+
60+
- (void)testWebViewWebEvaluateJavaScriptShouldNotBeCalledWhenShouldEnableZoomIsTrue {
61+
WKWebView *webview = OCMClassMock(WKWebView.class);
62+
WKNavigation *navigation = OCMClassMock(WKNavigation.class);
63+
NSURL *testUrl = [[NSURL alloc] initWithString:@"www.example.com"];
64+
OCMStub([webview URL]).andReturn(testUrl);
65+
66+
self.navigationDelegate.shouldEnableZoom = true;
67+
68+
OCMReject([webview evaluateJavaScript:zoomDisablingJavascript completionHandler:nil]);
69+
[self.navigationDelegate webView:webview didFinishNavigation:navigation];
70+
}
71+
4172
@end

packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
import 'dart:async';
66

7-
import 'package:flutter/widgets.dart';
87
import 'package:flutter/foundation.dart';
98
import 'package:flutter/gestures.dart';
9+
import 'package:flutter/widgets.dart';
1010
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
1111
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
1212

@@ -65,6 +65,7 @@ class WebView extends StatefulWidget {
6565
this.debuggingEnabled = false,
6666
this.gestureNavigationEnabled = false,
6767
this.userAgent,
68+
this.zoomEnabled = true,
6869
this.initialMediaPlaybackPolicy =
6970
AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
7071
this.allowsInlineMediaPlayback = false,
@@ -213,6 +214,11 @@ class WebView extends StatefulWidget {
213214
/// By default `userAgent` is null.
214215
final String? userAgent;
215216

217+
/// A Boolean value indicating whether the WebView should support zooming using its on-screen zoom controls and gestures.
218+
///
219+
/// By default 'zoomEnabled' is true
220+
final bool zoomEnabled;
221+
216222
/// Which restrictions apply on automatic media playback.
217223
///
218224
/// This initial value is applied to the platform's webview upon creation. Any following
@@ -542,6 +548,7 @@ WebSettings _webSettingsFromWidget(WebView widget) {
542548
gestureNavigationEnabled: widget.gestureNavigationEnabled,
543549
allowsInlineMediaPlayback: widget.allowsInlineMediaPlayback,
544550
userAgent: WebSetting<String?>.of(widget.userAgent),
551+
zoomEnabled: widget.zoomEnabled,
545552
);
546553
}
547554

packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,18 @@ NS_ASSUME_NONNULL_BEGIN
99

1010
@interface FLTWKNavigationDelegate : NSObject <WKNavigationDelegate>
1111

12-
- (instancetype)initWithChannel:(FlutterMethodChannel*)channel;
12+
- (instancetype)initWithChannel:(FlutterMethodChannel *)channel;
1313

1414
/**
1515
* Whether to delegate navigation decisions over the method channel.
1616
*/
1717
@property(nonatomic, assign) BOOL hasDartNavigationDelegate;
1818

19+
/**
20+
* Whether to allow zoom functionality on the WebView.
21+
*/
22+
@property(nonatomic, assign) BOOL shouldEnableZoom;
23+
1924
@end
2025

2126
NS_ASSUME_NONNULL_END

packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWKNavigationDelegate.m

+11
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ - (void)webView:(WKWebView *)webView
6363
}
6464

6565
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
66+
if (!self.shouldEnableZoom) {
67+
NSString *source =
68+
@"var meta = document.createElement('meta');"
69+
@"meta.name = 'viewport';"
70+
@"meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0,"
71+
@"user-scalable=no';"
72+
@"var head = document.getElementsByTagName('head')[0];head.appendChild(meta);";
73+
74+
[webView evaluateJavaScript:source completionHandler:nil];
75+
}
76+
6677
[_methodChannel invokeMethod:@"onPageFinished" arguments:@{@"url" : webView.URL.absoluteString}];
6778
}
6879

packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m

+3
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,9 @@ - (NSString*)applySettings:(NSDictionary<NSString*, id>*)settings {
348348
} else if ([key isEqualToString:@"userAgent"]) {
349349
NSString* userAgent = settings[key];
350350
[self updateUserAgent:[userAgent isEqual:[NSNull null]] ? nil : userAgent];
351+
} else if ([key isEqualToString:@"zoomEnabled"]) {
352+
NSNumber* zoomEnabled = settings[key];
353+
_navigationDelegate.shouldEnableZoom = [zoomEnabled boolValue];
351354
} else {
352355
[unknownKeys addObject:key];
353356
}

packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter_wkwebview
22
description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
33
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_wkwebview
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 2.0.14
5+
version: 2.1.0
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"
@@ -18,8 +18,7 @@ flutter:
1818
dependencies:
1919
flutter:
2020
sdk: flutter
21-
22-
webview_flutter_platform_interface: ^1.0.0
21+
webview_flutter_platform_interface: ^1.2.0
2322

2423
dev_dependencies:
2524
flutter_driver:

0 commit comments

Comments
 (0)