Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Listen javascript function from flutter #523

Merged
merged 8 commits into from
Sep 23, 2019
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
1 change: 1 addition & 0 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.flutter_webview_plugin">

charafau marked this conversation as resolved.
Show resolved Hide resolved
<application>
<provider
android:name="androidx.core.content.FileProvider"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import android.webkit.ValueCallback;
import android.os.Build;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import io.flutter.plugin.common.MethodCall;
Expand All @@ -27,10 +29,11 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
private Context context;
static MethodChannel channel;
private static final String CHANNEL_NAME = "flutter_webview_plugin";
private static final String JS_CHANNEL_NAMES_FIELD = "javascriptChannelNames";

public static void registerWith(PluginRegistry.Registrar registrar) {
channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
final FlutterWebviewPlugin instance = new FlutterWebviewPlugin(registrar.activity(),registrar.activeContext());
final FlutterWebviewPlugin instance = new FlutterWebviewPlugin(registrar.activity(), registrar.activeContext());
registrar.addActivityResultListener(instance);
channel.setMethodCallHandler(instance);
}
Expand Down Expand Up @@ -107,7 +110,12 @@ private void openUrl(MethodCall call, MethodChannel.Result result) {
boolean debuggingEnabled = call.argument("debuggingEnabled");

if (webViewManager == null || webViewManager.closed == true) {
webViewManager = new WebviewManager(activity, context);
Map<String, Object> arguments = (Map<String, Object>) call.arguments;
List<String> channelNames = new ArrayList();
if (arguments.containsKey(JS_CHANNEL_NAMES_FIELD)) {
channelNames = (List<String>) arguments.get(JS_CHANNEL_NAMES_FIELD);
}
webViewManager = new WebviewManager(activity, context, channelNames);
}

FrameLayout.LayoutParams params = buildLayoutParams(call);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package com.flutter_webview_plugin;

import android.os.Handler;
import android.os.Looper;
import android.webkit.JavascriptInterface;

import java.util.HashMap;

import io.flutter.plugin.common.MethodChannel;

/**
* 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;
private final Handler platformThreadHandler;

/**
* @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, 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(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.myLooper()) {
postMessageRunnable.run();
} else {
platformThreadHandler.post(postMessageRunnable);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -17,7 +18,9 @@
import android.webkit.WebView;
import android.widget.FrameLayout;
import android.provider.MediaStore;

import androidx.core.content.FileProvider;

import android.database.Cursor;
import android.provider.OpenableColumns;

Expand All @@ -43,7 +46,7 @@ class WebviewManager {

private ValueCallback<Uri> mUploadMessage;
private ValueCallback<Uri[]> mUploadMessageArray;
private final static int FILECHOOSER_RESULTCODE=1;
private final static int FILECHOOSER_RESULTCODE = 1;
private Uri fileUri;
private Uri videoUri;

Expand All @@ -56,29 +59,29 @@ private long getFileSize(Uri fileUri) {

@TargetApi(7)
class ResultHandler {
public boolean handleResult(int requestCode, int resultCode, Intent intent){
public boolean handleResult(int requestCode, int resultCode, Intent intent) {
boolean handled = false;
if(Build.VERSION.SDK_INT >= 21){
if(requestCode == FILECHOOSER_RESULTCODE){
if (Build.VERSION.SDK_INT >= 21) {
if (requestCode == FILECHOOSER_RESULTCODE) {
Uri[] results = null;
if (resultCode == Activity.RESULT_OK) {
if (fileUri != null && getFileSize(fileUri) > 0) {
results = new Uri[] { fileUri };
results = new Uri[]{fileUri};
} else if (videoUri != null && getFileSize(videoUri) > 0) {
results = new Uri[] { videoUri };
results = new Uri[]{videoUri};
} else if (intent != null) {
results = getSelectedFiles(intent);
}
}
if(mUploadMessageArray != null){
if (mUploadMessageArray != null) {
mUploadMessageArray.onReceiveValue(results);
mUploadMessageArray = null;
}
handled = true;
}
}else {
} else {
if (requestCode == FILECHOOSER_RESULTCODE) {
Uri result = null;
Uri result = null;
if (resultCode == RESULT_OK && intent != null) {
result = intent.getData();
}
Expand All @@ -97,8 +100,8 @@ private Uri[] getSelectedFiles(Intent data) {
// we have one files selected
if (data.getData() != null) {
String dataString = data.getDataString();
if(dataString != null){
return new Uri[]{ Uri.parse(dataString) };
if (dataString != null) {
return new Uri[]{Uri.parse(dataString)};
}
}
// we have multiple files selected
Expand All @@ -113,18 +116,20 @@ private Uri[] getSelectedFiles(Intent data) {
return null;
}

private final Handler platformThreadHandler;
boolean closed = false;
WebView webView;
Activity activity;
BrowserClient webViewClient;
ResultHandler resultHandler;
Context context;

WebviewManager(final Activity activity, final Context context) {
WebviewManager(final Activity activity, final Context context, final List<String> channelNames) {
this.webView = new ObservableWebView(activity);
this.activity = activity;
this.context = context;
this.resultHandler = new ResultHandler();
this.platformThreadHandler = new Handler(context.getMainLooper());
webViewClient = new BrowserClient();
webView.setOnKeyListener(new View.OnKeyListener() {
@Override
Expand All @@ -145,20 +150,19 @@ public boolean onKey(View v, int keyCode, KeyEvent event) {
}
});

((ObservableWebView) webView).setOnScrollChangedCallback(new ObservableWebView.OnScrollChangedCallback(){
public void onScroll(int x, int y, int oldx, int oldy){
((ObservableWebView) webView).setOnScrollChangedCallback(new ObservableWebView.OnScrollChangedCallback() {
public void onScroll(int x, int y, int oldx, int oldy) {
Map<String, Object> yDirection = new HashMap<>();
yDirection.put("yDirection", (double)y);
yDirection.put("yDirection", (double) y);
FlutterWebviewPlugin.channel.invokeMethod("onScrollYChanged", yDirection);
Map<String, Object> xDirection = new HashMap<>();
xDirection.put("xDirection", (double)x);
xDirection.put("xDirection", (double) x);
FlutterWebviewPlugin.channel.invokeMethod("onScrollXChanged", xDirection);
}
});

webView.setWebViewClient(webViewClient);
webView.setWebChromeClient(new WebChromeClient()
{
webView.setWebChromeClient(new WebChromeClient() {
//The undocumented magic method override
//Eclipse will swear at you if you try to put @Override here
// For Android 3.0+
Expand All @@ -168,36 +172,36 @@ public void openFileChooser(ValueCallback<Uri> uploadMsg) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
activity.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE);
activity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);

}

// For Android 3.0+
public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
activity.startActivityForResult(
activity.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE);
}

//For Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
activity.startActivityForResult( Intent.createChooser( i, "File Chooser" ), FILECHOOSER_RESULTCODE );
activity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);

}

//For Android 5.0+
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams){
if(mUploadMessageArray != null){
FileChooserParams fileChooserParams) {
if (mUploadMessageArray != null) {
mUploadMessageArray.onReceiveValue(null);
}
mUploadMessageArray = filePathCallback;
Expand Down Expand Up @@ -248,6 +252,7 @@ public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermiss
callback.invoke(origin, true, false);
}
});
registerJavaScriptChannelNames(channelNames);
}

private Uri getOutputFilename(String intentType) {
Expand Down Expand Up @@ -334,6 +339,13 @@ private void clearCache() {
webView.clearFormData();
}

private void registerJavaScriptChannelNames(List<String> channelNames) {
for (String channelName : channelNames) {
webView.addJavascriptInterface(
new JavaScriptChannel(FlutterWebviewPlugin.channel, channelName, platformThreadHandler), channelName);
}
}

void openUrl(
boolean withJavascript,
boolean clearCache,
Expand Down Expand Up @@ -371,7 +383,7 @@ void openUrl(
webView.getSettings().setAllowUniversalAccessFromFileURLs(allowFileURLs);

webView.getSettings().setUseWideViewPort(useWideViewPort);

// Handle debugging
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.setWebContentsDebuggingEnabled(debuggingEnabled);
Expand Down Expand Up @@ -403,7 +415,7 @@ void openUrl(
webView.getSettings().setUserAgentString(userAgent);
}

if(!scrollBar){
if (!scrollBar) {
webView.setVerticalScrollBarEnabled(false);
}

Expand Down Expand Up @@ -451,25 +463,28 @@ public void onReceiveValue(String value) {
}
});
}

/**
* Reloads the Webview.
*/
* Reloads the Webview.
*/
void reload(MethodCall call, MethodChannel.Result result) {
if (webView != null) {
webView.reload();
}
}

/**
* Navigates back on the Webview.
*/
* Navigates back on the Webview.
*/
void back(MethodCall call, MethodChannel.Result result) {
if (webView != null && webView.canGoBack()) {
webView.goBack();
}
}

/**
* Navigates forward on the Webview.
*/
* Navigates forward on the Webview.
*/
void forward(MethodCall call, MethodChannel.Result result) {
if (webView != null && webView.canGoForward()) {
webView.goForward();
Expand All @@ -479,31 +494,35 @@ void forward(MethodCall call, MethodChannel.Result result) {
void resize(FrameLayout.LayoutParams params) {
webView.setLayoutParams(params);
}

/**
* Checks if going back on the Webview is possible.
*/
* Checks if going back on the Webview is possible.
*/
boolean canGoBack() {
return webView.canGoBack();
}

/**
* Checks if going forward on the Webview is possible.
*/
* Checks if going forward on the Webview is possible.
*/
boolean canGoForward() {
return webView.canGoForward();
}

void hide(MethodCall call, MethodChannel.Result result) {
if (webView != null) {
webView.setVisibility(View.GONE);
}
}

void show(MethodCall call, MethodChannel.Result result) {
if (webView != null) {
webView.setVisibility(View.VISIBLE);
}
}

void stopLoading(MethodCall call, MethodChannel.Result result){
if (webView != null){
void stopLoading(MethodCall call, MethodChannel.Result result) {
if (webView != null) {
webView.stopLoading();
}
}
Expand Down
5 changes: 3 additions & 2 deletions example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ task clean(type: Delete) {
delete rootProject.buildDir
}

task wrapper(type: Wrapper) {
gradleVersion = '4.10.2'
wrapper {
gradleVersion = '4.4'
distributionUrl = distributionUrl.replace("bin", "all")
}
Loading