【问题标题】:WebView + WebChromeClient method onCreateWindow not called for target="_blank"没有为 target="_blank" 调用 WebView + WebChromeClient 方法 onCreateWindow
【发布时间】:2011-12-20 16:06:29
【问题描述】:

我正在尝试使用 Android API level 10 (sdk 2.3.3) 开发 custom browserWebView,不幸的是我不知道如何拦截来自 webpage 的请求以在新浏览器中打开 URL窗口,例如点击带有target="_blank" 的链接。

根据API Doc,我已经覆盖了WebChromeClientonCreateWindow,但在点击这样的链接时不会调用。可能是这个 API 级别的错误?我还将覆盖shouldOverrideUrlLoading 以避免WebView 在内置浏览器中打开后续链接。

这是我打开google.com 的示例代码。要对其进行测试,请点击“新闻”,然后点击任何新闻标题。 Android 内置浏览器通常会在新的browser window 中打开它。

package com.myexample;

import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

public class HelloAndroidActivity extends Activity {

  private static String TAG = "WebViewTest";
  private WebView mWebView;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.i(TAG, "onCreate");
    setContentView(R.layout.main);

    mWebView = (WebView) findViewById(R.id.mywebview);

    mWebView.setWebViewClient(new WebViewClient() {
      @Override
      public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
      }
    });

    mWebView.setWebChromeClient(new WebChromeClient() {
      @Override
      public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture, Message resultMsg) {
        Toast.makeText(getApplicationContext(), "OnCreateWindow", Toast.LENGTH_LONG).show();
        return true;
      }
    });
    mWebView.loadUrl("http://www.google.com");
  }

}

【问题讨论】:

  • Lotzy,只有当你从 shouldOverrideUrlLoading 返回 true 时才会调用 onCreateWindow。似乎是一个网络视图错误,因为在大多数情况下你不能从 shouldOverride 返回 false...
  • 好吧,你可以看到有一个返回 true;在 shouldOverrideUrlLoading 方法中。

标签: android webview webchromeclient


【解决方案1】:

确保将 supportMultipeWindows 设置为 true。没有它,WebChromeClient 的 onCreateWindow 将永远不会被调用。

WebSettings settings = webView.getSettings();
settings.setSupportMultipleWindows(true);

然后注册一个 WebChromeClient 并覆盖 onCreateWindow

 webView.setWebChromeClient(new WebChromeClient() {
        @Override public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture, Message resultMsg)
        {
            WebView newWebView = new WebView(getContext());
            addView(newWebView);
            WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
            transport.setWebView(newWebView);
            resultMsg.sendToTarget();
            return true;
        }
    });

【讨论】:

  • 对我来说它不起作用,没有显示来自 onCreateWindow() 方法的 Toast。我还在该行中放置了一个断点并使用调试器启动了应用程序,但执行并没有在该行停止。
  • 太棒了,终于可以用这个了!只是一个问题,为什么是“addView(newWebView)”?我不明白这条线。而且我也不用。你能解释一下这条线的意义吗?谢谢
  • @Seynorth 很久没有回答这个问题了。可能需要 addView 将新创建的 WebView 添加到视图层次结构中。否则,它只是一个视图对象,没有附加到视图层次结构中的任何位置,并且可能不会显示或呈现。如果您不需要这样做,我想知道您是如何做到的。
  • 是否可以从“onCreateWindow”方法获取当前 URL(我的意思是点击的 url),因为我想在同一个 webview 中打开 url。
  • 什么时候删除视图,如果有的话? :)
【解决方案2】:

除了注入 javascript 代码之外找不到任何解决方案。我什至尝试编译从谷歌源代码库下载的内置 android 浏览器代码,但由于我发现它使用了一些非公共 API,所以无法编译。 Dolphin 浏览器也使用它自己的扩展 WebView,所以我没有找到他们如何实现打开新窗口请求检测的运气。

这段 javascript 代码获取加载页面上的所有链接标签,并分析是否有 target="_blank" 的属性。对于这些链接中的每一个,都会在 href 属性的 url 值前面添加“newtab:”。然后在 shouldOverrideUrlLoading() 方法中检查 url 是否以“newtab:”字符串开头,在这种情况下我打开一个新标签。

以下是代码片段:

    mWebView.setWebViewClient(new WebViewClient() {

        @Override
        public void onPageFinished(WebView view, String url) {
            // Find all <a> with target="_blank" and append "newtab:" at the beginning. 
            // Make sure a null is at the end to avoid displaying a blank page
            view.loadUrl("javascript: var allLinks = document.getElementsByTagName('a'); if (allLinks) {var i;for (i=0; i<allLinks.length; i++) {var link = allLinks[i];var target = link.getAttribute('target'); if (target && target == '_blank') {link.setAttribute('target','_self');link.href = 'newtab:'+link.href;}}} null");
        }



        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String urls) {
            if (urls.startsWith("newtab:")) {
                addTab(); //add a new tab or window
                loadNewURL(urls.substring(7)); //strip "newtab:" and load url in the webview of the newly created tab or window
            }
            else {
                view.loadUrl(urls); //load url in current WebView
            }
            return true;
        }
    }

【讨论】:

【解决方案3】:

你需要看看这个:

webView.getSettings().setSupportMultipleWindows(true);

然后onCreateWindow 将被调用。

【讨论】:

  • 伙计们,您确定您使用 API 级别 10 (sdk 2.3.3) 尝试过我的代码吗?
  • 这个答案对我很有帮助:-)
  • @Lotzy 你有解决方案吗?
  • @JithishPN 抱歉,我的解决方案是带有 javascript 注入的解决方案,我没有找到其他解决方案,因为我也没有编写 Android 代码,因为这个问题于 2012 年发布在 stackoverflow 上。奇怪的是这仍然是个问题。
【解决方案4】:

所有从 WebChromeClient 覆盖 onCreateWindow 的答案对我都不起作用。有时它会在浏览器中打开一张图片,而不是像预期的那样打开网址。

唯一完全有效的解决方案是@Lotzy 结合@Vaughn Armada 添加的答案(在javascript sn-p 的末尾添加null)。使用此代码,所有带有 target="_blank" 的链接都将在新的浏览器窗口中打开,如果没有该目标,它们将在同一个 WebView 中打开。

webView.webViewClient = object : WebViewClient() {
    override fun onPageFinished(view: WebView, url: String) {
        // Check all <a>'s with target="_blank" so that it opens in browsers when it's supposed to.
        // Make sure a null is at the end to avoid displaying a blank page
        view.loadUrl("javascript: var allLinks = document.getElementsByTagName('a'); if (allLinks) {var i;for (i=0; i<allLinks.length; i++) {var link = allLinks[i];var target = link.getAttribute('target'); if (target && target == '_blank') {link.setAttribute('target','_self');link.href = 'newtab:'+link.href;}}} null");
    }

    override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
        if (url.startsWith("newtab:")) {
            // Open browser with the url, removing the added "newtab:"
            view.context.startActivity(Intent(Intent.ACTION_VIEW).setData(Uri.parse(url.removePrefix("newtab:"))))
        } else {
            // Load inside webview
            view.loadUrl(url)
        }
        return true
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 2014-05-24
    • 2011-06-25
    • 1970-01-01
    • 2014-11-19
    相关资源
    最近更新 更多