Make sure to post javascript channel messages from the platform thread. (#1429)
The Android's webview's JavascriptInterface doesn't promise to invoke
the interface's Java method on the main thread, since postMessage is
sending a message over the platform channel we need to make sure it's
doing so from the platform thread.
diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md
index 81801b8..fc34c1c 100644
--- a/packages/webview_flutter/CHANGELOG.md
+++ b/packages/webview_flutter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.5+3
+
+* Make sure to post javascript channel messages from the platform thread.
+
## 0.3.5+2
* Fix crash from `NavigationDelegate` on later versions of Android.
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 9db7d5e..21720cf 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
@@ -7,6 +7,7 @@
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
+import android.os.Handler;
import android.view.View;
import android.webkit.WebStorage;
import android.webkit.WebView;
@@ -25,10 +26,12 @@
private final WebView webView;
private final MethodChannel methodChannel;
private final FlutterWebViewClient flutterWebViewClient;
+ private final Handler platformThreadHandler;
@SuppressWarnings("unchecked")
FlutterWebView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params) {
webView = new WebView(context);
+ platformThreadHandler = new Handler(context.getMainLooper());
// Allow local storage.
webView.getSettings().setDomStorageEnabled(true);
@@ -214,7 +217,7 @@
private void registerJavaScriptChannelNames(List<String> channelNames) {
for (String channelName : channelNames) {
webView.addJavascriptInterface(
- new JavaScriptChannel(methodChannel, channelName), channelName);
+ new JavaScriptChannel(methodChannel, channelName, platformThreadHandler), channelName);
}
}
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
index e7e76b2..180ca4f 100644
--- 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
@@ -4,6 +4,8 @@
package io.flutter.plugins.webviewflutter;
+import android.os.Handler;
+import android.os.Looper;
import android.webkit.JavascriptInterface;
import io.flutter.plugin.common.MethodChannel;
import java.util.HashMap;
@@ -18,6 +20,7 @@
class JavaScriptChannel {
private final MethodChannel methodChannel;
private final String javaScriptChannelName;
+ private final Handler platformThreadHandler;
/**
* @param methodChannel the Flutter WebView method channel to which JS messages are sent
@@ -25,18 +28,31 @@
* channel with each message to let the Dart code know which JavaScript channel the message
* was sent through
*/
- JavaScriptChannel(MethodChannel methodChannel, String javaScriptChannelName) {
+ JavaScriptChannel(
+ MethodChannel methodChannel, String javaScriptChannelName, Handler platformThreadHandler) {
this.methodChannel = methodChannel;
this.javaScriptChannelName = javaScriptChannelName;
+ this.platformThreadHandler = platformThreadHandler;
}
// 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);
+ public void postMessage(final String message) {
+ Runnable postMessageRunnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ HashMap<String, String> arguments = new HashMap<>();
+ arguments.put("channel", javaScriptChannelName);
+ arguments.put("message", message);
+ methodChannel.invokeMethod("javascriptChannelMessage", arguments);
+ }
+ };
+ if (platformThreadHandler.getLooper() == Looper.getMainLooper()) {
+ postMessageRunnable.run();
+ } else {
+ platformThreadHandler.post(postMessageRunnable);
+ }
}
}
diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml
index db694ed..77c0ce9 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.5+2
+version: 0.3.5+3
author: Flutter Team <flutter-dev@googlegroups.com>
homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter