evaluateJavascript 是如何工作的?

Posted

技术标签:

【中文标题】evaluateJavascript 是如何工作的?【英文标题】:How does evaluateJavascript work? 【发布时间】:2013-11-16 06:51:47 【问题描述】:

我正在尝试在 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
    
);

如何将结果返回给该方法?

更新:更多信息:

    我设置了 INTERNET 权限 我有setJavascriptEnabled(true); 尝试过的撇号字符串:return 'test';, 尝试过的 JS 对象:return test: 'this' console.log('test'); 执行良好。 将targetSdkVersion 设置为 19,如下所示:If your app uses WebView

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

【问题讨论】:

你试过去掉javascript中的return关键字吗?所以:webView1.evaluateJavascript("\"test\"", new ValueCallback&lt;String&gt;() /*callback code here*/ ); 我已经阅读了WebView 文档,并试图了解evaluateJavascript 函数的实际用例? 【参考方案1】:

本示例中使用了 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)
    
);

【讨论】:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)在evaluateJavascript里面有什么用? 它涵盖了使用 Honeycomb 中引入的 JSONReader 类的编译器警告 我们如何评估 KITKAT 之前的 JavaScript?当您检查 API 时 - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) @KaluKhanLuhar 你可以使用webview.loadurl("javascript:(function () document.body.background='red';);"); +1 用于说明 onReceiveValue 返回例如JSON 值。花了很多时间试图弄清楚为什么在 html 元素上调用 innerHTML 会返回 qoutes 中的内容【参考方案2】:

好的,原来resultJavascript 调用的结果 - 就像将命令输入到 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"
    
);

【讨论】:

【参考方案3】:

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

【讨论】:

当我在 onPageFinished(WebView view, String url) 方法中使用它与 webview.evaluareJavaScript() 非常相似时,我没有得到与 evaluareJavaScript() 方法相同的 html 【参考方案4】:

总结@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 返回正确的 nulls 可能是一个字符串 "null",因此您显然需要在第一步进行检查。

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

【讨论】:

【参考方案5】:

每个人的回答都很棒。我只是再补充一点。不要像这样将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);
            
        );

    

【讨论】:

我已经阅读了WebView 文档,并试图了解evaluateJavascript 函数的实际用例? @AdamHurwitz 例如,向 webview 注入一些脚本以与网站显示进行交互【参考方案6】:

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

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

【讨论】:

以上是关于evaluateJavascript 是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

WKWebview evaluateJavascript 不工作,抛出错误

WKWebView goBack(_:) evaluateJavaScript 如果返回超过 2 个历史记录失败

如何使用evaluateJavaScript 将数据从WKWebview 发送到HTML 文件| iOS | Objective-C

使用 evaluateJavaScript(..) 调用 javascript 函数,以读取应用程序包中的文本文件

evaluateJavaScript 用于整个文件

webView.evaluateJavascript。不想执行。