Javascript回调函数传递给Android

时间:2011-08-10 23:39:31

标签: java javascript android webview

我有一个用Java实现的javascript接口,由我在webview中加载的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中以字符串形式构建回调。

湾在将回调传递给Android.myFunction();

之前调用回调的toString()

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

4 个答案:

答案 0 :(得分:36)

我遇到了类似的问题:在网络应用中,我想使用原生的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提供了回调方法myCallbackFunction(),其名称作为参数传递给Android(以及数据字符串,标题和消息)。回调函数如下所示:

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

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

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");
}

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

    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编码的对象)。

答案 1 :(得分:12)

您将无法按照指定的方式传递该功能。您将函数传递给Android.myData,但Android.myData接受一个字符串。相反,你可能想要

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

您仍有问题,因为您没有将任何数据传递给回调。虽然这与你的问题没有直接关系,但它会成为一个问题,因为你对字符串问题有相同的强制转换(通过JSON可以解决......但如果Android为你处理那个部分会很好)。

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

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

但是,当然,先测试一下;)

答案 2 :(得分:4)

WebView允许您直接在窗口上下文中执行一些JavaScript。 因此,您无需通过资源URL传递JavaScript。

这是一种将数据传回html页面的认可方式

/**
 * This is an approved way to pass data back to the html page
 */
 webView.evaluateJavascript("alert('pass here some ...')", new ValueCallback<String>() {
       @Override
       public void onReceiveValue(String s) {

        }
    });

官方文件中的详细信息

  

在当前显示的页面的上下文中异步评估JavaScript。如果非null,| resultCallback |将使用该执行返回的任何结果调用。必须在UI线程上调用此方法,并且将在UI线程上进行回调。

     

兼容性说明。针对N或更高版本的应用程序,来自空WebView的JavaScript状态不再在loadUrl(String)等导航中保留。例如,在加载的页面中不存在调用loadUrl(String)之前定义的全局变量和函数。应用程序应该使用addJavascriptInterface(Object,String)来跨导航持久化JavaScript对象。

Link to the official WebView documentation

答案 3 :(得分:-1)

据我所知,您所做的只是将Java界面对象添加到您的webview中。然后,在javascript中,您可以通过调用myJavaInterface.doEchoTest(stringToEcho)来调用它。您附加方法的方式如下:

myWebView.addJavascriptInterface(MyJavaInterface, "MyJavaInterface");

这是java中的接口:

public class MyJavaInterface{

private WebView mAppView;
public MyJavaInterface  (WebView appView) {
        this.mAppView = appView;
    }

    public void doEchoTest(String echo){
        Toast toast = Toast.makeText(mAppView.getContext(), echo, Toast.LENGTH_SHORT);
        toast.show();
    }
}

所以现在你可以调用JAVA-Android FROM JS了。

要从Java-Android调用JavaScript,您可以调用:

myWebView.loadUrl("javascript:someJsFunctionICreated("hello javascript!");