WebView JavasScript channels Android implementation. (#1130)
Platform implementation of the method channel API for adding and removing JavaScript channels.
#1116 adds the Dart side support, the current PR will land first.
flutter/flutter#24837
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 58f249a..a6528cd 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
@@ -9,22 +9,31 @@
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.platform.PlatformView;
+import java.util.List;
import java.util.Map;
public class FlutterWebView implements PlatformView, MethodCallHandler {
+ private static final String JS_CHANNEL_NAMES_FIELD = "javascriptChannelNames";
private final WebView webView;
private final MethodChannel methodChannel;
@SuppressWarnings("unchecked")
FlutterWebView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params) {
webView = new WebView(context);
+
+ methodChannel = new MethodChannel(messenger, "plugins.flutter.io/webview_" + id);
+ methodChannel.setMethodCallHandler(this);
+
+ applySettings((Map<String, Object>) params.get("settings"));
+
+ if (params.containsKey(JS_CHANNEL_NAMES_FIELD)) {
+ registerJavaScriptChannelNames((List<String>) params.get(JS_CHANNEL_NAMES_FIELD));
+ }
+
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);
}
@Override
@@ -62,6 +71,12 @@
case "evaluateJavascript":
evaluateJavaScript(methodCall, result);
break;
+ case "addJavascriptChannels":
+ addJavaScriptChannels(methodCall, result);
+ break;
+ case "removeJavascriptChannels":
+ removeJavaScriptChannels(methodCall, result);
+ break;
default:
result.notImplemented();
}
@@ -125,6 +140,22 @@
});
}
+ @SuppressWarnings("unchecked")
+ private void addJavaScriptChannels(MethodCall methodCall, Result result) {
+ List<String> channelNames = (List<String>) methodCall.arguments;
+ registerJavaScriptChannelNames(channelNames);
+ result.success(null);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void removeJavaScriptChannels(MethodCall methodCall, Result result) {
+ List<String> channelNames = (List<String>) methodCall.arguments;
+ for (String channelName : channelNames) {
+ webView.removeJavascriptInterface(channelName);
+ }
+ result.success(null);
+ }
+
private void applySettings(Map<String, Object> settings) {
for (String key : settings.keySet()) {
switch (key) {
@@ -150,6 +181,13 @@
}
}
+ private void registerJavaScriptChannelNames(List<String> channelNames) {
+ for (String channelName : channelNames) {
+ webView.addJavascriptInterface(
+ new JavaScriptChannel(methodChannel, channelName), channelName);
+ }
+ }
+
@Override
public void dispose() {}
}
diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java
new file mode 100644
index 0000000..1fba623
--- /dev/null
+++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java
@@ -0,0 +1,38 @@
+package io.flutter.plugins.webviewflutter;
+
+import android.webkit.JavascriptInterface;
+import io.flutter.plugin.common.MethodChannel;
+import java.util.HashMap;
+
+/**
+ * Added as a JavaScript interface to the WebView for any JavaScript channel that the Dart code sets
+ * up.
+ *
+ * <p>Exposes a single method named `postMessage` to JavaScript, which sends a message over a method
+ * channel to the Dart code.
+ */
+class JavaScriptChannel {
+ private final MethodChannel methodChannel;
+ private final String javaScriptChannelName;
+
+ /**
+ * @param methodChannel the Flutter WebView method channel to which JS messages are sent
+ * @param javaScriptChannelName the name of the JavaScript channel, this is sent over the method
+ * channel with each message to let the Dart code know which JavaScript channel the message
+ * was sent through
+ */
+ JavaScriptChannel(MethodChannel methodChannel, String javaScriptChannelName) {
+ this.methodChannel = methodChannel;
+ this.javaScriptChannelName = javaScriptChannelName;
+ }
+
+ // Suppressing unused warning as this is invoked from JavaScript.
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ public void postMessage(String message) {
+ HashMap<String, String> arguments = new HashMap<>();
+ arguments.put("channel", javaScriptChannelName);
+ arguments.put("message", message);
+ methodChannel.invokeMethod("javascriptChannelMessage", arguments);
+ }
+}