Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit be3e558

Browse files
authored
Add an initialUrl and a javaScriptMode parameters to WebView. (#753)
Adding just these 2 parameters to set up the skeleton for webview settings and initial parameters. Settings (like javaScriptMode) are set and updated by rebuilding the widget. initialUrl is a covinience parameter for simple use cases, as the WebView's loadUrl method cannot be modeled nicely as a widget parameter (e.g when the widget is rebuilt with the same url value there is no nice way to tell if you should load that url again or not). These kind of "edge triggers" fit in the WevView's controller. initialUrl is completely ignored when the widget is rebuilt.
1 parent f100277 commit be3e558

File tree

5 files changed

+239
-26
lines changed

5 files changed

+239
-26
lines changed

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

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,20 @@
1010
import io.flutter.plugin.common.MethodCall;
1111
import io.flutter.plugin.common.MethodChannel;
1212
import io.flutter.plugin.platform.PlatformView;
13+
import java.util.Map;
1314

1415
public class FlutterWebView implements PlatformView, MethodCallHandler {
1516
private final WebView webView;
1617
private final MethodChannel methodChannel;
1718

18-
FlutterWebView(Context context, BinaryMessenger messenger, int id) {
19+
@SuppressWarnings("unchecked")
20+
FlutterWebView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params) {
1921
webView = new WebView(context);
22+
if (params.containsKey("initialUrl")) {
23+
String url = (String) params.get("initialUrl");
24+
webView.loadUrl(url);
25+
}
26+
applySettings((Map<String, Object>) params.get("settings"));
2027
methodChannel = new MethodChannel(messenger, "plugins.flutter.io/webview_" + id);
2128
methodChannel.setMethodCallHandler(this);
2229
}
@@ -32,6 +39,9 @@ public void onMethodCall(MethodCall methodCall, Result result) {
3239
case "loadUrl":
3340
loadUrl(methodCall, result);
3441
break;
42+
case "updateSettings":
43+
updateSettings(methodCall, result);
44+
break;
3545
default:
3646
result.notImplemented();
3747
}
@@ -43,6 +53,37 @@ private void loadUrl(MethodCall methodCall, Result result) {
4353
result.success(null);
4454
}
4555

56+
@SuppressWarnings("unchecked")
57+
private void updateSettings(MethodCall methodCall, Result result) {
58+
applySettings((Map<String, Object>) methodCall.arguments);
59+
result.success(null);
60+
}
61+
62+
private void applySettings(Map<String, Object> settings) {
63+
for (String key : settings.keySet()) {
64+
switch (key) {
65+
case "jsMode":
66+
updateJsMode((Integer) settings.get(key));
67+
break;
68+
default:
69+
throw new IllegalArgumentException("Unknown WebView setting: " + key);
70+
}
71+
}
72+
}
73+
74+
private void updateJsMode(int mode) {
75+
switch (mode) {
76+
case 0: // disabled
77+
webView.getSettings().setJavaScriptEnabled(false);
78+
break;
79+
case 1: //unrestricted
80+
webView.getSettings().setJavaScriptEnabled(true);
81+
break;
82+
default:
83+
throw new IllegalArgumentException("Trying to set unknown Javascript mode: " + mode);
84+
}
85+
}
86+
4687
@Override
4788
public void dispose() {}
4889
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import io.flutter.plugin.common.StandardMessageCodec;
66
import io.flutter.plugin.platform.PlatformView;
77
import io.flutter.plugin.platform.PlatformViewFactory;
8+
import java.util.Map;
89

910
public class WebViewFactory extends PlatformViewFactory {
1011
private final BinaryMessenger messenger;
@@ -14,8 +15,10 @@ public WebViewFactory(BinaryMessenger messenger) {
1415
this.messenger = messenger;
1516
}
1617

18+
@SuppressWarnings("unchecked")
1719
@Override
1820
public PlatformView create(Context context, int id, Object args) {
19-
return new FlutterWebView(context, messenger, id);
21+
Map<String, Object> params = (Map<String, Object>) args;
22+
return new FlutterWebView(context, messenger, id, params);
2023
}
2124
}

packages/webview_flutter/example/lib/main.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,12 @@ class WebViewExample extends StatelessWidget {
1616
// This drop down menu demonstrates that Flutter widgets can be shown over the web view.
1717
actions: <Widget>[const SampleMenu()],
1818
),
19-
body: WebView(
20-
onWebViewCreated: _onWebViewCreated,
19+
body: const WebView(
20+
initialUrl: 'https://youtube.com',
21+
javaScriptMode: JavaScriptMode.unrestricted,
2122
),
2223
);
2324
}
24-
25-
void _onWebViewCreated(WebViewController controller) {
26-
controller.loadUrl('https://flutter.io');
27-
}
2825
}
2926

3027
class SampleMenu extends StatelessWidget {

packages/webview_flutter/lib/webview_flutter.dart

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,30 @@ import 'package:flutter/widgets.dart';
1111

1212
typedef void WebViewCreatedCallback(WebViewController controller);
1313

14+
enum JavaScriptMode {
15+
/// JavaScript execution is disabled.
16+
disabled,
17+
18+
/// JavaScript execution is not restricted.
19+
unrestricted,
20+
}
21+
1422
/// A web view widget for showing html content.
1523
class WebView extends StatefulWidget {
1624
/// Creates a new web view.
1725
///
1826
/// The web view can be controlled using a `WebViewController` that is passed to the
1927
/// `onWebViewCreated` callback once the web view is created.
2028
///
21-
/// The `gestureRecognizers` parameter must not be null;
29+
/// The `gestureRecognizers` and `javaScriptMode` parameters must not be null.
2230
const WebView({
2331
Key key,
2432
this.onWebViewCreated,
33+
this.initialUrl,
34+
this.javaScriptMode = JavaScriptMode.disabled,
2535
this.gestureRecognizers = const <OneSequenceGestureRecognizer>[],
2636
}) : assert(gestureRecognizers != null),
37+
assert(javaScriptMode != null),
2738
super(key: key);
2839

2940
/// If not null invoked once the web view is created.
@@ -40,11 +51,22 @@ class WebView extends StatefulWidget {
4051
/// were not claimed by any other gesture recognizer.
4152
final List<OneSequenceGestureRecognizer> gestureRecognizers;
4253

54+
/// The initial URL to load.
55+
final String initialUrl;
56+
57+
/// Whether JavaScript execution is enabled.
58+
final JavaScriptMode javaScriptMode;
59+
4360
@override
4461
State<StatefulWidget> createState() => _WebViewState();
4562
}
4663

4764
class _WebViewState extends State<WebView> {
65+
final Completer<WebViewController> _controller =
66+
new Completer<WebViewController>();
67+
68+
_WebSettings _settings;
69+
4870
@override
4971
Widget build(BuildContext context) {
5072
if (defaultTargetPlatform == TargetPlatform.android) {
@@ -63,18 +85,93 @@ class _WebViewState extends State<WebView> {
6385
// we explicitly set it here so that the widget doesn't require an ambient
6486
// directionality.
6587
layoutDirection: TextDirection.rtl,
88+
creationParams: _CreationParams.fromWidget(widget).toMap(),
89+
creationParamsCodec: const StandardMessageCodec(),
6690
),
6791
);
6892
}
6993
return Text(
7094
'$defaultTargetPlatform is not yet supported by the webview_flutter plugin');
7195
}
7296

73-
void _onPlatformViewCreated(int id) {
74-
if (widget.onWebViewCreated == null) {
97+
@override
98+
void initState() {
99+
super.initState();
100+
_settings = _WebSettings.fromWidget(widget);
101+
}
102+
103+
@override
104+
void didUpdateWidget(WebView oldWidget) {
105+
super.didUpdateWidget(oldWidget);
106+
final _WebSettings newSettings = _WebSettings.fromWidget(widget);
107+
final Map<String, dynamic> settingsUpdate =
108+
_settings.updatesMap(newSettings);
109+
_updateSettings(settingsUpdate);
110+
_settings = newSettings;
111+
}
112+
113+
Future<void> _updateSettings(Map<String, dynamic> update) async {
114+
if (update == null) {
75115
return;
76116
}
77-
widget.onWebViewCreated(new WebViewController._(id));
117+
final WebViewController controller = await _controller.future;
118+
controller._updateSettings(update);
119+
}
120+
121+
void _onPlatformViewCreated(int id) {
122+
final WebViewController controller = new WebViewController._(id);
123+
_controller.complete(controller);
124+
if (widget.onWebViewCreated != null) {
125+
widget.onWebViewCreated(controller);
126+
}
127+
}
128+
}
129+
130+
class _CreationParams {
131+
_CreationParams({this.initialUrl, this.settings});
132+
133+
static _CreationParams fromWidget(WebView widget) {
134+
return new _CreationParams(
135+
initialUrl: widget.initialUrl,
136+
settings: _WebSettings.fromWidget(widget),
137+
);
138+
}
139+
140+
final String initialUrl;
141+
final _WebSettings settings;
142+
143+
Map<String, dynamic> toMap() {
144+
return <String, dynamic>{
145+
'initialUrl': initialUrl,
146+
'settings': settings.toMap(),
147+
};
148+
}
149+
}
150+
151+
class _WebSettings {
152+
_WebSettings({
153+
this.javaScriptMode,
154+
});
155+
156+
static _WebSettings fromWidget(WebView widget) {
157+
return new _WebSettings(javaScriptMode: widget.javaScriptMode);
158+
}
159+
160+
final JavaScriptMode javaScriptMode;
161+
162+
Map<String, dynamic> toMap() {
163+
return <String, dynamic>{
164+
'jsMode': javaScriptMode.index,
165+
};
166+
}
167+
168+
Map<String, dynamic> updatesMap(_WebSettings newSettings) {
169+
if (javaScriptMode == newSettings.javaScriptMode) {
170+
return null;
171+
}
172+
return <String, dynamic>{
173+
'jsMode': newSettings.javaScriptMode.index,
174+
};
78175
}
79176
}
80177

@@ -98,6 +195,10 @@ class WebViewController {
98195
_validateUrlString(url);
99196
return _channel.invokeMethod('loadUrl', url);
100197
}
198+
199+
Future<void> _updateSettings(Map<String, dynamic> update) async {
200+
return _channel.invokeMethod('updateSettings', update);
201+
}
101202
}
102203

103204
// Throws an ArgumentError if url is not a valid url string.

0 commit comments

Comments
 (0)