Javascript 回调函数传递给 Android

2022-09-01 05:08:23

我有一个用Java实现的javascript接口,它由我在web视图中加载的javascript代码调用。

JS Inside Webview:

Android.myFunction(function(data){
    console.log(data);
});

爪哇岛:

public class JavaScriptInterface {

    Context context;
    WebView webView;

    JavaScriptInterface(Context c, WebView w) {
        context = c;
        webView = w;
    }

    public void myFunction(String callback) {
        //when I log callback, it is "undefined"
         String someData = "Yay for data";
         String js =
             "javascript:(function() { "
                 + "var callback = " + callback + ";"
                 + "callback('" + someData + "');"
             + "})()";
        webView.loadUrl(js);
    }
}

由 webview 加载的字符串最终为:

javascript:(function() {var callback = undefined; undefined();})()

我有几个想法:

一个。在 JS 中将回调构建为字符串。

b.在将回调传递给 Android.myFunction() 之前调用回调的 toString();

我的问题是,最好的方法是什么?我希望能够将对象传递到Android,它神奇地工作。显然,事实并非如此。;)下一个最好的方法是什么?


答案 1

我遇到了类似的问题:在网络应用程序中,我想使用本机Android确认对话框。这意味着我必须从Android回调到Javascript部分,并给出确认对话框的结果。

我按如下方式解决了这个问题:

function foo() {
    // user confirmation needed
    var dataString = <encode data into string>;
    MyClient.showConfirmationDialog('myCallBackFunction', dataString, 'A title', 'A message');
}

上面的代码调用Android javascript接口(见下文)。javascript提供了回调方法,其名称作为参数传递给Android(以及数据字符串,标题和消息)。回调函数如下所示:myCallbackFunction()

function myCallbackFunction(dataString, result) {
    var data = <decode data from dataString>;
    if (result) {
        // user has confirmed
    } else {
        // user has denied
    }
}

在 Android 方面,我首先在 Activity 的方法中激活 Javascript 接口:onCreate()

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    WebView webView = new WebView(this);
    setContentView(webView);
    WebSettings settings = webView.getSettings();
    settings.setJavaScriptEnabled(true);
    webView.addJavascriptInterface(new MyJavascriptInterface(webView), "MyClient");
}

然后,实现将创建相应的 Android 对话框,并将结果传递回 javascript:MyJavascriptInterface

    WebView webView;

    public MyJavascriptInterface(WebView w) {
         this.webView = w;
    }

    @JavascriptInterface
    public void showConfirmationDialog(final String callbackFunction, final String data, String title,
            String message) {

        Dialog.OnClickListener positiveListener = new Dialog.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                webView.loadUrl("javascript:" + callbackFunction + "('" + data + "', true)");
            }
        };
        Dialog.OnClickListener negativeListener = new Dialog.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                webView.loadUrl("javascript:" + callbackFunction + "('" + data + "', false)");
            }
        };

        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle(title).setMessage(message).setPositiveButton("Ok", positiveListener)
                .setNegativeButton("Cancel", negativeListener).setCancelable(false);
        builder.create().show();
    }

将回调函数的名称传递给Android允许使用多个调用确认对话框,每个对话都配备了自己的函数来执行实际操作。数据字符串将携带执行操作所需的所有数据(甚至可以包含 Json 编码的对象)。


答案 2

您将无法以指定方式传递函数。您将一个函数传递给 Android.myData,但 Android.myData 采用字符串。相反,你可能想要

var myCallback = console.log;
Android.myFunction("myCallback");

您仍然有一个问题,因为您没有将任何数据传递给回调。虽然这与您的问题没有直接关系,但它将成为一个问题,因为您将具有相同的投射到/来自字符串问题(可通过JSON解决...但如果Android为您处理该部分,那就太好了)。

最后,你可以将javascript:string缩短为

String js = "javascript:" + callback + "();";

但是,当然,首先测试;)