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

Add an initialUrl and a javaScriptMode parameters to WebView #753

Merged
merged 1 commit into from
Sep 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.platform.PlatformView;
import java.util.Map;

public class FlutterWebView implements PlatformView, MethodCallHandler {
private final WebView webView;
private final MethodChannel methodChannel;

FlutterWebView(Context context, BinaryMessenger messenger, int id) {
@SuppressWarnings("unchecked")
FlutterWebView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params) {
webView = new WebView(context);
if (params.containsKey("initialUrl")) {
String url = (String) params.get("initialUrl");
webView.loadUrl(url);
}
applySettings((Map<String, Object>) params.get("settings"));
methodChannel = new MethodChannel(messenger, "plugins.flutter.io/webview_" + id);
methodChannel.setMethodCallHandler(this);
}
Expand All @@ -32,6 +39,9 @@ public void onMethodCall(MethodCall methodCall, Result result) {
case "loadUrl":
loadUrl(methodCall, result);
break;
case "updateSettings":
updateSettings(methodCall, result);
break;
default:
result.notImplemented();
}
Expand All @@ -43,6 +53,37 @@ private void loadUrl(MethodCall methodCall, Result result) {
result.success(null);
}

@SuppressWarnings("unchecked")
private void updateSettings(MethodCall methodCall, Result result) {
applySettings((Map<String, Object>) methodCall.arguments);
result.success(null);
}

private void applySettings(Map<String, Object> settings) {
for (String key : settings.keySet()) {
switch (key) {
case "jsMode":
updateJsMode((Integer) settings.get(key));
break;
default:
throw new IllegalArgumentException("Unknown WebView setting: " + key);
}
}
}

private void updateJsMode(int mode) {
switch (mode) {
case 0: // disabled
webView.getSettings().setJavaScriptEnabled(false);
break;
case 1: //unrestricted
webView.getSettings().setJavaScriptEnabled(true);
break;
default:
throw new IllegalArgumentException("Trying to set unknown Javascript mode: " + mode);
}
}

@Override
public void dispose() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
import java.util.Map;

public class WebViewFactory extends PlatformViewFactory {
private final BinaryMessenger messenger;
Expand All @@ -14,8 +15,10 @@ public WebViewFactory(BinaryMessenger messenger) {
this.messenger = messenger;
}

@SuppressWarnings("unchecked")
@Override
public PlatformView create(Context context, int id, Object args) {
return new FlutterWebView(context, messenger, id);
Map<String, Object> params = (Map<String, Object>) args;
return new FlutterWebView(context, messenger, id, params);
}
}
9 changes: 3 additions & 6 deletions packages/webview_flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,12 @@ class WebViewExample extends StatelessWidget {
// This drop down menu demonstrates that Flutter widgets can be shown over the web view.
actions: <Widget>[const SampleMenu()],
),
body: WebView(
onWebViewCreated: _onWebViewCreated,
body: const WebView(
initialUrl: 'https://youtube.com',
javaScriptMode: JavaScriptMode.unrestricted,
),
);
}

void _onWebViewCreated(WebViewController controller) {
controller.loadUrl('https://flutter.io');
}
}

class SampleMenu extends StatelessWidget {
Expand Down
109 changes: 105 additions & 4 deletions packages/webview_flutter/lib/webview_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,30 @@ import 'package:flutter/widgets.dart';

typedef void WebViewCreatedCallback(WebViewController controller);

enum JavaScriptMode {
/// JavaScript execution is disabled.
disabled,

/// JavaScript execution is not restricted.
unrestricted,
}

/// A web view widget for showing html content.
class WebView extends StatefulWidget {
/// Creates a new web view.
///
/// The web view can be controlled using a `WebViewController` that is passed to the
/// `onWebViewCreated` callback once the web view is created.
///
/// The `gestureRecognizers` parameter must not be null;
/// The `gestureRecognizers` and `javaScriptMode` parameters must not be null.
const WebView({
Key key,
this.onWebViewCreated,
this.initialUrl,
this.javaScriptMode = JavaScriptMode.disabled,
this.gestureRecognizers = const <OneSequenceGestureRecognizer>[],
}) : assert(gestureRecognizers != null),
assert(javaScriptMode != null),
super(key: key);

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

/// The initial URL to load.
final String initialUrl;

/// Whether JavaScript execution is enabled.
final JavaScriptMode javaScriptMode;

@override
State<StatefulWidget> createState() => _WebViewState();
}

class _WebViewState extends State<WebView> {
final Completer<WebViewController> _controller =
new Completer<WebViewController>();

_WebSettings _settings;

@override
Widget build(BuildContext context) {
if (defaultTargetPlatform == TargetPlatform.android) {
Expand All @@ -63,18 +85,93 @@ class _WebViewState extends State<WebView> {
// we explicitly set it here so that the widget doesn't require an ambient
// directionality.
layoutDirection: TextDirection.rtl,
creationParams: _CreationParams.fromWidget(widget).toMap(),
creationParamsCodec: const StandardMessageCodec(),
),
);
}
return Text(
'$defaultTargetPlatform is not yet supported by the webview_flutter plugin');
}

void _onPlatformViewCreated(int id) {
if (widget.onWebViewCreated == null) {
@override
void initState() {
super.initState();
_settings = _WebSettings.fromWidget(widget);
}

@override
void didUpdateWidget(WebView oldWidget) {
super.didUpdateWidget(oldWidget);
final _WebSettings newSettings = _WebSettings.fromWidget(widget);
final Map<String, dynamic> settingsUpdate =
_settings.updatesMap(newSettings);
_updateSettings(settingsUpdate);
_settings = newSettings;
}

Future<void> _updateSettings(Map<String, dynamic> update) async {
if (update == null) {
return;
}
widget.onWebViewCreated(new WebViewController._(id));
final WebViewController controller = await _controller.future;
controller._updateSettings(update);
}

void _onPlatformViewCreated(int id) {
final WebViewController controller = new WebViewController._(id);
_controller.complete(controller);
if (widget.onWebViewCreated != null) {
widget.onWebViewCreated(controller);
}
}
}

class _CreationParams {
_CreationParams({this.initialUrl, this.settings});

static _CreationParams fromWidget(WebView widget) {
return new _CreationParams(
initialUrl: widget.initialUrl,
settings: _WebSettings.fromWidget(widget),
);
}

final String initialUrl;
final _WebSettings settings;

Map<String, dynamic> toMap() {
return <String, dynamic>{
'initialUrl': initialUrl,
'settings': settings.toMap(),
};
}
}

class _WebSettings {
_WebSettings({
this.javaScriptMode,
});

static _WebSettings fromWidget(WebView widget) {
return new _WebSettings(javaScriptMode: widget.javaScriptMode);
}

final JavaScriptMode javaScriptMode;

Map<String, dynamic> toMap() {
return <String, dynamic>{
'jsMode': javaScriptMode.index,
};
}

Map<String, dynamic> updatesMap(_WebSettings newSettings) {
if (javaScriptMode == newSettings.javaScriptMode) {
return null;
}
return <String, dynamic>{
'jsMode': newSettings.javaScriptMode.index,
};
}
}

Expand All @@ -98,6 +195,10 @@ class WebViewController {
_validateUrlString(url);
return _channel.invokeMethod('loadUrl', url);
}

Future<void> _updateSettings(Map<String, dynamic> update) async {
return _channel.invokeMethod('updateSettings', update);
}
}

// Throws an ArgumentError if url is not a valid url string.
Expand Down
Loading