【问题标题】:Android WebView evaluateJavaScript Callback is not being invoked未调用 Android WebView evaluateJavaScript 回调
【发布时间】:2017-05-10 14:11:54
【问题描述】:

evaluateJavascript(String script, ValueCallback<String> resultCallback) 方法在 SDK 19 中被添加到 Android 上的 WebView 中。

Android 文档引用:

如果非空,resultCallback 将被调用任何 该执行返回的结果。

我正在使用如下所示的这种方法,但不知何故我的回调没有被调用。我可以从调试中看到 evaluateJavascript() 被调用,但在 Android API 19、20 和 21 中没有调用回调。从 API 22 (LOLLIPOP_MR1) 开始,一切都按预期工作。

evaluateJavascript() 之前调用webview.loadURL("") 使其适用于所有API 级别。我想了解原因,如果有人能对此有所了解/分享任何链接,我将不胜感激。如果我能理解为什么,我想看看是否可以避免调用loadURL()。还有一个不相关的问题使loadURL() 成为不可取的解决方案。

代码:

    private void webViewTest() {
        WebView webview = new WebView(this);
        webview.getSettings().setJavaScriptEnabled(true);
        Log.d("TEST", "BEFORE"); // LOGGED
        // webview.loadUrl(""); // Enabling this makes it work on all Android versions
        webview.evaluateJavascript("(function(){return 'test'})()", new ValueCallback<String>() {
            @Override
            public void onReceiveValue(String s) {
                Log.d("TEST", "From JS: " + s); // NEVER LOGGED on API 19-21
            }
        });
        Log.e("TEST", "AFTER"); // LOGGED
    }


    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            webViewTest();
        }
    });

请在https://github.com/bashok001/TestApp找到这个问题的示例

【问题讨论】:

  • 来自developer.android.com/reference/android/webkit/WebView.html 是否有原因不能使用loadData()loadDataWithBaseURL()
  • 一旦我使用load...() 方法,它就会破坏另一个功能。所以,我想了解为什么调用load...() 会在 19 日、20 日、21 日完成所有工作。

标签: java android webview android-webview chromium


【解决方案1】:

来自docs

当前显示的页面的上下文中异步评估 JavaScript。在 ContentViewCore EvaluateJavascript 检查渲染视图。看起来对于集成在 19,20,21 中的特定版本的 WebView - RenderView 只是在 loadUrl 被调用之前才创建。

我发现以下FIX 可能是相关的:

它是从 WebContentsAndorid 修改 EvaluateJavaScript 的原生实现:

void WebContentsAndroid::EvaluateJavaScript(JNIEnv* env,
                                             jobject obj,
                                             jstring script,
                                            jobject callback,
                                            jboolean start_renderer) {

   RenderViewHost* rvh = web_contents_->GetRenderViewHost();
   DCHECK(rvh);

   if (start_renderer && !rvh->IsRenderViewLive()) {

     if (!static_cast<WebContentsImpl*>(web_contents_)->
         CreateRenderViewForInitialEmptyDocument()) {
         ... 
     }
   }
   ...

到:

 void WebContentsAndroid::EvaluateJavaScript(JNIEnv* env,
                                                jobject obj,
                                                jstring script,
                                                jobject callback) {
   RenderViewHost* rvh = web_contents_->GetRenderViewHost();
   DCHECK(rvh);
   if (!rvh->IsRenderViewLive()) {
     if (!static_cast<WebContentsImpl*>(web_contents_)->
         CreateRenderViewForInitialEmptyDocument()) {
         ...
        }
      }
   ....

ContentViewCore 中有以下代码将false 传递为start_renderer

public void evaluateJavaScript(String script, JavaScriptCallback callback) {
    assert mWebContents != null;
    mWebContents.evaluateJavaScript(script, callback, false);
}

这意味着在前面提到的对evaluateJavaScript 的修复调用上构建的WebView 不会创建RenderView,因此WebContext 无法处理java 脚本执行。 因此,当您使用 loadUrl 时,您会强制创建渲染视图,一切都会按预期开始工作。

【讨论】:

  • 这是一个很好的解释。谢谢!
猜你喜欢
  • 1970-01-01
  • 2018-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
相关资源
最近更新 更多