EvaluateJavascript 是如何工作的?

我尝试在 Android 4.4中使用新的 EvaluateJavascript方法,但是我得到的结果是一个空值:

webView1.evaluateJavascript("return \"test\";", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Log is written, but s is always null
}
});

如何向此方法返回结果?

更新: 更多信息:

  1. 我有互联网权限集
  2. 我有 setJavascriptEnabled(true);
  3. 试试撇号字符串: return 'test';,
  4. 尝试了 JS 对象: return { test: 'this' }
  5. console.log('test');的执行情况良好。
  6. targetSdkVersion设置为19,如下所示: 如果你的应用程序使用 WebView

设备: Nexus7和 Nexus5(库存)

124022 次浏览

好的,这里的 result就是 Javascript 调用的结果-就好像把命令输入到 Javascript 控制台中一样。

因此,为了得到一个结果,它需要包装在一个函数中:

webView1.evaluateJavascript("(function() { return \"this\"; })();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints 'this'
}
});

这也会奏效:

webView1.evaluateJavascript("window.variable = \"asd\";", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints asd
}
});

该方法还处理 Javascript 对象:

webView1.evaluateJavascript("(function() { return { var1: \"variable1\", var2: \"variable2\" }; })();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints: {"var1":"variable1","var2":"variable2"}
}
});

这个示例中使用了 evaluateJavascript 方法的一个例子:

Https://github.com/googlechrome/chromium-webview-samples/tree/master/jsinterface-example

本质上,如果您在 WebView 中执行的 javascript 返回一个值,它将在回调中传递。

主要需要注意的是,OnReceiveValue 中返回的 String 是 JSON 值、 JSON 对象或 JSON 数组,具体取决于返回的内容。

需要注意的是,如果返回单个值,则需要在 JSON 读取器上使用 setLenient (true)才能正常工作。

     if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// In KitKat+ you should use the evaluateJavascript method
mWebView.evaluateJavascript(javascript, new ValueCallback<String>() {
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onReceiveValue(String s) {
JsonReader reader = new JsonReader(new StringReader(s));


// Must set lenient to parse single values
reader.setLenient(true);


try {
if(reader.peek() != JsonToken.NULL) {
if(reader.peek() == JsonToken.STRING) {
String msg = reader.nextString();
if(msg != null) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
}
}
} catch (IOException e) {
Log.e("TAG", "MainActivity: IOException", e);
} finally {
try {
reader.close();
} catch (IOException e) {
// NOOP
}
}
}
});
}

您可能仍然希望将解析器用于字符串响应的原因是它被转换为一个 JSON 值,这意味着它将被包装在引号中。

例如,如果你去:

mWebView.evaluateJavascript("(function() { return 'this'; })();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints: "this"
}
});

它将打印字符串 this,包装在双引号中: “ this”。

其他值得注意的例子:

mWebView.evaluateJavascript("(function() { return null; })();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints the string 'null' NOT Java null
}
});


mWebView.evaluateJavascript("(function() { })();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); //s is Java null
}
});


mWebView.evaluateJavascript("(function() { return ''; })();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints "" (Two double quotes)
}
});

AndroidJSCore 是评估不使用 WebView 的 JavaScript 的一个很好的替代方案。

如果你想坚持使用 WebView,并且需要在早期版本的 Android (4 +)上评估 JavaScript,这里有一个小程序库:

Https://github.com/evgenyneu/js-evaluator-for-android

jsEvaluator.evaluate("put your JavaScript code", new JsCallback() {
@Override
public void onResult(final String result) {
// get result here (optional)
}
});

为了总结@GauntFace 的答案并提供一个不使用 JSON 解析器的替代解决方案:

如果您的 JS 函数只返回一个 String,并且您想知道为什么这个字符串在 Java 中是错误的,那是因为它是 JSON 转义的。

mWebView.evaluateJavascript("(function() { return 'Earvin \"Magic\" Johnson'; })();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s);
// expected: s == Earvin "Magic" Johnson
// actual:   s == "Earvin \"Magic\" Johnson"
}
});

(请注意,onReceiveValue总是提供一个 String,而 JS 函数可能返回一个 null,一个数字字面值等。)

要获得与 JS 中相同的字符串值,如果您100% 确定您期望返回正确的 String,则需要取消转义 JSON,例如:

String unescaped = s.substring(1, s.length() - 1)  // remove wrapping quotes
.replace("\\\\", "\\")        // unescape \\ -> \
.replace("\\\"", "\"");       // unescape \" -> "

但是,请注意,如果 JS 返回正确的 null,则 s可能是字符串 "null",因此显然需要在第一步中检查它。

if ("null".equals(s)) {
...
} else {
// unescape JSON
}

每个人的回答都很棒。我再加一点。不要像这样在带有@JavascripInterface 注释的方法中放入 evaluateJavascript

    @JavascriptInterface  //this is the right annotation
public void onData(){
mWebView.evaluateJavascript("javascript:executeNext()",null);
}

因为它会阻塞 JavaBridge 线程。 如果你想把 evaluateJavascript 放进去,这样做

    @JavascriptInterface
public void onData(){
mWebView.post(new Runnable() {
@Override
public void run() {
mWebView.evaluateJavascript("javascript:executeNext()",null);
}
});


}

重要提示:
在调用 evaluateJavascript之前,您必须为您的 WebView 启用 JavaScript,否则您将得不到任何结果。

WebSettings settings = yourWebview.getSettings();
settings.setJavaScriptEnabled(true);