evaluateJavascript如何工作?

时间:2013-11-05 11:50:08

标签: android android-webview android-4.4-kitkat

我正在尝试在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. 根据If your app uses WebView
  7. targetSdkVersion设置为19

    设备:Nexus 7和Nexus 5(股票)

6 个答案:

答案 0 :(得分:58)

此示例中使用了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”。

其他值得注意的例子:

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

答案 1 :(得分:10)

好的,所以事实证明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"}
    }
});

答案 2 :(得分:7)

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

答案 3 :(得分:3)

总结@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-unescape它,例如:< / p>

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

但是,请注意,如果JS返回正确的s"null"可能是字符串null,因此您显然需要将其作为第一步检查。

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

答案 4 :(得分:2)

每个人的回答都很好。我再增加一点。不要像这样用@JavascripInterface注释将评估Javascript放在方法中

    @JavascripInterface
    public void onData(){ 
            mWebView.evaluateJavascript("javascript:executeNext()",null);
    }  

因为它将阻塞JavaBridge线程。 如果您要在其中放入评估Javascript。用这种方式做

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

    }

答案 5 :(得分:0)

重要提示:
在调用evaluateJavascript之前,您必须为WebView启用JavaScript。否则您将无法获得结果。

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