如何从Android调用javascript?

时间:2011-09-25 09:24:55

标签: java javascript android return

我们如何从Android调用javascript?我有这个我想使用的javascript库,我想调用javascript函数并将结果值传递给android java代码。从现在起没有找到答案。我设法从javascript调用android代码,但我想要反过来。

4 个答案:

答案 0 :(得分:18)

有一个黑客:

  1. 绑定一些Java对象,以便可以使用WebView从Javascript调用它:

    addJavascriptInterface(javaObjectCallback, "JavaCallback")
    
  2. 强制执行现有页面中的javascript

    WebView.loadUrl("javascript: var result = window.YourJSLibrary.callSomeFunction();
        window.JavaCallback.returnResult(result)");
    
  3. (在这种情况下,您的java类JavaObjectCallback应该有一个方法returnResult(..)

    注意:这是一个安全风险 - 此网页中的任何JS代码都可以访问/调用绑定的Java对象。最好将一些一次性cookie传递给loadUrl()并将它们传回给你的Java对象,以检查它是你的代码进行调用。

答案 1 :(得分:3)

您可以使用Rhino库在没有WebView的情况下执行JavaScript。

Download Rhino首先解压缩,将js.jar文件放在libs文件夹下。它非常小,所以你不必担心你的apk文件会因为这个外部jar而变得非常大。

以下是一些执行JavaScript代码的简单代码。

Object[] params = new Object[] { "javaScriptParam" };

// Every Rhino VM begins with the enter()
// This Context is not Android's Context
Context rhino = Context.enter();

// Turn off optimization to make Rhino Android compatible
rhino.setOptimizationLevel(-1);
try {
    Scriptable scope = rhino.initStandardObjects();

    // Note the forth argument is 1, which means the JavaScript source has
    // been compressed to only one line using something like YUI
    rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);

    // Get the functionName defined in JavaScriptCode
    Object obj = scope.get(functionNameInJavaScriptCode, scope);

    if (obj instanceof Function) {
        Function jsFunction = (Function) obj;

        // Call the function with params
        Object jsResult = jsFunction.call(rhino, scope, scope, params);
        // Parse the jsResult object to a String
        String result = Context.toString(jsResult);
    }
} finally {
    Context.exit();
}

您可以在my post看到更多详情。

答案 2 :(得分:2)

为了匹配iOS WebviewJavascriptBridge(https://github.com/marcuswestin/WebViewJavascriptBridge)的方法调用,我为register_handlecall_handle的调用做了一些代理。请注意我不是Javascript-guru因此可能有更好的解决方案。

     javascriptBridge = (function() {
        var handlers = {};
        return {
            init: function () {
            },
            getHandlers : function() {
                return handlers;
            },
            callHandler : function(name, param) {
                if(param !== null && param !== undefined) {
                    JSInterface[name](param);
                } else {
                    JSInterface[name]();
                }
            },
            registerHandler : function(name, method) {
                if(handlers === undefined) {
                    handlers = {};
                }
                if(handlers[name] === undefined) {
                    handlers[name] = method;
                }
            }
        };
    }());

这样,您可以从Javascript发送到可以具有String参数的Java调用

javascriptBridge.callHandler("login", JSON.stringify(jsonObj));

致电

@JavascriptInterface
public void login(String credentialsJSON)
{
    Log.d(getClass().getName(), "Login: " + credentialsJSON);
    new Thread(new Runnable() {
         public void run() {              
             Gson gson = new Gson();
             LoginObject credentials = gson.fromJson(credentialsJSON, LoginObject.class);
             SingletonBus.INSTANCE.getBus().post(new Events.Login.LoginEvent(credentials));
         }
    }).start();
}

您可以使用

回调Javascript
javascriptBridge.registerHandler('successfullAuthentication', function () {
    alert('hello');
})

private Handler webViewHandler = new Handler(Looper.myLooper());

webViewHandler.post(
        new Runnable()
        {
            public void run()
            {
                webView.loadUrl("javascript: javascriptBridge.getHandlers().successfullAuthentication();"
            }
        }
);

如果您需要传递参数,请序列化为JSON字符串,然后调用StringEscapeUtils.escapeEcmaScript(json),否则会出现unexpected identifier: source (1)错误。

有点俗气和黑客,但它的确有效。您只需要删除以下内容。

connectWebViewJavascriptBridge(function(bridge) {
}

编辑:

为了将全局变量更改为实际属性,我将上面的代码更改为以下代码:

(function(root) {
    root.bridge = (function() {
        var handlers = {};
        return {
            init: function () {
            },
            getHandlers : function() {
                return handlers;
            },
            callHandler : function(name, param) {
                if(param !== null && param !== undefined) {
                    Android[name](param);
                } else {
                    Android[name]();
                }
            },
            registerHandler : function(name, method) {
                if(handlers === undefined) {
                    handlers = {};
                }
                if(handlers[name] === undefined) {
                    handlers[name] = method;
                }
            }
        };
    }());
})(this);

我从Javascript global module or global variable得到了这个想法。

答案 3 :(得分:1)

要完全实现不需要使用慢速WebView的JavaScript,请参阅AndroidJSCore,它是Webkit的Android版JavaScriptCore的完整端口。

更新2018年:不推荐使用AndroidJSCore。但是,它的继任者LiquidCore具有所有相同的功能和更多功能。

从Android调用函数非常简单:

JSContext context = new JSContext();
String script =
  "function factorial(x) { var f = 1; for(; x > 1; x--) f *= x; return f; }\n" +
  "var fact_a = factorial(a);\n";
context.evaluateScript("var a = 10;");
context.evaluateScript(script);
JSValue fact_a = context.property("fact_a");
System.out.println(df.format(fact_a.toNumber())); // 3628800.0