添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm trying to use the new evaluateJavascript method in Android 4.4, but all I ever get back is a null result:

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

How do I return a result to this method?

Update: Little bit more info:

  • I have the INTERNET permission set
  • I have setJavascriptEnabled(true);
  • Tried apostrophe string: return 'test';,
  • Tried JS object: return { test: 'this' }
  • console.log('test'); is being executed fine.
  • Set targetSdkVersion to 19 as per: If your app uses WebView
  • Devices: Both Nexus 7 and Nexus 5 (Stock)

    have you tried removing the return keyword in the javascript? So: webView1.evaluateJavascript("\"test\"", new ValueCallback<String>() { /*callback code here*/ }); – AndroidKotlinNoob Nov 17, 2020 at 14:23 I've read through the WebView docs and I'm trying to understand the practical use cases for the evaluateJavascript function? – AdamHurwitz Dec 7, 2020 at 19:19

    There is an example of the evaluateJavascript method being used in this sample:

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

    Essentially if the javascript you execute in the WebView returns a value it'll be passed in the callback.

    The main thing to note is that the String returned in OnReceiveValue is either a JSON Value, JSON Object or JSON Array depending on what you return.

    Things to note about this is if you return a single value, you need to use setLenient(true) on a JSON reader for it to work.

         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
    

    The reason you may still want to use a parser for a string response is it is converted to a JSON value which means it will be wrapped in quotes.

    For example if you went:

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

    It would print the string this, wrapped in double quotes: "this".

    Other examples worth noting:

    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)
                    Its to cover a compiler warning for the use of the JSONReader class which was introduced in Honeycomb
    – Matt Gaunt
                    May 16, 2014 at 14:31
                    How can we evaluateJavascript for pre KITKAT? As you checks API like- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
    – Kalu Khan Luhar
                    Nov 7, 2015 at 6:25
                    @KaluKhanLuhar you could use webview.loadurl("javascript:(function () {document.body.background='red';});");
    – lucidbrot
                    Feb 28, 2016 at 15:20
                    +1 For stating that onReceiveValue returns e.g. a JSON-value. Spent a lot of time trying to figure out why a call to innerHTML on a HTML-element returned the content in qoutes
    – Anigif
                    Mar 22, 2018 at 9:21
    

    OK, so it turns out the result here is the result of the Javascript call - as if one were entering the command into a Javascript console.

    So in order to get a result, it needs to be wrapped in a function:

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

    This will also work:

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

    The method also handles Javascript objects:

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

    AndroidJSCore is a good alternative for evaluating JavaScript that does not use a WebView.

    If you want to stick with WebView and need to evaluate JavaScript on earlier versions of Android (4+), here is a little library:

    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)
                    When I use it very smilar to webview.evaluareJavaScript(), in the onPageFinished(WebView view, String url)  method and I don't get the same html as I would get from evaluareJavaScript() method
    – Akshay
                    Apr 19, 2016 at 20:29
    

    Everyone's answer is great. I just add one more point. Don't put evaluateJavascript inside the method with @JavascripInterface annotation like this way

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

    Becasue it will block the JavaBridge Thread. if you want to put evaluateJavascript inside it. Do it with this way

        @JavascriptInterface
        public void onData(){
            mWebView.post(new Runnable() {
                @Override
                public void run() {
                    mWebView.evaluateJavascript("javascript:executeNext()",null);
                    I've read through the WebView docs and I'm trying to understand the practical use cases for the evaluateJavascript function?
    – AdamHurwitz
                    Dec 7, 2020 at 19:20
    

    To summarize the answer of @GauntFace and provide an alternative solution without using JSON parser:

    If your JS function returns just a String and you're wondering about why the string is mangled in Java, it's because it's JSON-escaped.

    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"
    

    (note that onReceiveValue always provides a String while JS function may return a null, a Number literal etc.)

    To get the string value the same as in JS, if you're 100% sure you're expecting a proper String returned, you'd need to JSON-unescape it, for example like that:

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

    However, note that s might be a string "null" if JS returns proper null, so you obviously need to check that as the very first step.

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

    Important hint:
    Before calling evaluateJavascript you have to enable JavaScript for your WebView. Otherwise you get no result.

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

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.