我们如何从 Android 调用 javascript?我有我想使用的这个 javascript 库,我想调用 javascript 函数并将结果值传递给 android java 代码。从现在开始一直没有找到答案。我设法从 javascript 调用 android 代码,但我想反过来。
如何从Android调用javascript?
有一个黑客:
绑定一些 Java 对象,以便可以使用 WebView 从 Javascript 调用它:
addJavascriptInterface(javaObjectCallback, "JavaCallback")
通过以下方式在现有页面中强制执行 javascript
WebView.loadUrl("javascript: var result = window.YourJSLibrary.callSomeFunction(); window.JavaCallback.returnResult(result)");
(在这种情况下,您的 java 类JavaObjectCallback
应该有一个方法returnResult(..)
)
注意:这是一个安全风险 - 此网页中的任何 JS 代码都可以访问/调用您绑定的 Java 对象。最好将一些一次性 cookie 传递给 loadUrl() 并将它们传递回您的 Java 对象以检查是否是您的代码进行调用。
您可以使用Rhino
库在没有 WebView 的情况下执行 JavaScript。
先下载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();
}
您可以在我的帖子中查看更多详细信息。
为了匹配iOS的WebviewJavascriptBridge(的方法调用https://github.com/marcuswestin/WebViewJavascriptBridge),我为的叫声一些代理register_handle
和call_handle
。请注意,我不是 Javascript 专家,因此可能有更好的解决方案。
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();
}
你可以用
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);
有关不需要使用慢速 WebView 的 JavaScript 的完整实现,请参阅AndroidJSCore,它是 Webkit 的 JavaScriptCore for Android 的完整端口。
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