68

我正在尝试在 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. 我有 INTERNET 权限集
  2. 我有setJavascriptEnabled(true);
  3. 尝试撇号字符串:return 'test'; ,
  4. 尝试过的 JS 对象:return { test: 'this' }
  5. console.log('test');执行得很好。
  6. 按照以下方式设置targetSdkVersion为 19:如果您的应用使用 WebView

设备: Nexus 7 和 Nexus 5(库存)

4

6 回答 6

82

此示例中使用了 evaluateJavascript 方法的示例:

https://github.com/GoogleChrome/chromium-webview-samples/tree/master/jsinterface-example

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

需要注意的主要是 OnReceiveValue 中返回的字符串是 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)
    }
});
于 2013-12-04T14:23:56.273 回答
15

好的,事实证明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"}
    }
});
于 2013-11-05T14:06:43.577 回答
9

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)
  }
});
于 2014-03-15T00:31:14.917 回答
7

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

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

    }
于 2019-01-26T02:36:21.630 回答
7

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

如果您的 JS 函数只返回 aString并且您想知道为什么字符串在 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总是提供Stringwhile JS 函数可能会返回 a null、 Number 文字等)

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

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

但是,请注意,如果 JS 返回了 proper ,则它s可能是一个字符串,因此您显然需要在第一步进行检查。"null"null

if ("null".equals(s)) {
   ...
} else {
   // unescape JSON
}
于 2017-07-06T13:13:19.827 回答
0

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

WebSettings settings = yourWebview.getSettings();
settings.setJavaScriptEnabled(true);
于 2020-08-26T09:46:31.100 回答