禁用Android WebView/WebViewClient发起的favicon.ico请求

15

当我调用WebView.loadUrl()时,Android WebView/WebViewClient如何禁用发送favicon.ico请求?我可以通过CharlesProxy监视请求时看到这个调用。

我不拥有在WebView中显示的HTML内容。我的研究已经找到了很多关于从服务器端解决问题的结果,但这些对我没有用。

5个回答

10

对我来说完整的解决方案是:

   @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

        if(url.toLowerCase().contains("/favicon.ico")) {
            try {
                return new WebResourceResponse("image/png", null, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    @Override
    @SuppressLint("NewApi")
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

        if(!request.isForMainFrame() && request.getUrl().getPath().endsWith("/favicon.ico")) {
            try {
                return new WebResourceResponse("image/png", null, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }

@MilošČernilovský 这个答案是正确的,而不是将图标放在资产中。看起来非常干净、简单和正确的方法。 - Android is everything for me
1
顺便提一下,request.isForMainFrame() 可能不会像你期望的那样工作,因为即使最初加载包含 iframe 的 URL,它也会返回 false。请参见:https://dev59.com/3Jvga4cB1Zd3GeqP348F - mtkopone
我觉得奇怪的是,尽管在Charles中看不到任何调用,但在执行操作后,我收到了一个错误,好像已经进行了调用,而且没有找到图标(这就是在删除favicon调用之前应用程序发生的情况)。我清除了缓存并禁用了它,但仍然发生...我不知道为什么会发生这种情况。另外,无论我传递什么WebSourceResponse,如mimeType,在onReceivedHttpError或onReceivedError被调用时都为空。 - FabioR

6
我通过一点小技巧实现了这个。首先,我创建了一个假的1x1图标文件并将其保存到资产文件夹中。然后我重写了WebViewClient的shouldInterceptRequest()方法,在该方法中检查URL是否为请求网站图标文件,如果是,则返回包含我们假图标的InputStream的WebResourceResponse:
    @Override
    @CallSuper
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        if(!request.isForMainFrame() && request.getUrl().getPath().equals("/favicon.ico")) {
            try {
                return new WebResourceResponse("image/png", null, new BufferedInputStream(view.getContext().getAssets().open("empty_favicon.ico")));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

请注意,我们的代码中不得关闭InputStream,因为WebView随后会使用它来读取图标。必须通过其setter将WebviewClient设置为WebView:
mWebView.setWebViewClient(subclassedWebViewClient);

非常有用,对我很有效。如果您不需要支持早期的Lollipop设备,则WebResourceResponse可以传达404状态,您不需要虚拟图标(或异常处理)。 - rhashimoto
你可以返回新的WebResourceResponse("image/png", null, null); - ventura8
我认为我们不应该要求在资产中放置图标并进行黑客攻击,而是可以将响应传递为null并进行下一步处理。 - Android is everything for me

2

以下是 Kotlin 的答案:

override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? {
    return if (request?.url?.lastPathSegment == "favicon.ico") {
        WebResourceResponse("image/png", null, null)
    } else {
        super.shouldInterceptRequest(view, request)
    }
}

默认情况下,当Android Studio生成代码时,返回类型WebResourceResponse不可为空,但实际上这样并不奏效,因此将返回类型更改为可为空的WebResourceResponse


2
您可以像下面展示的那样,简单地传递一些虚拟的InputStream给WebResourceResponse。
my_webview.webViewClient = object : WebViewClient() {
    override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? {
        if (request?.url?.toString()?.toLowerCase()?.endsWith("/favicon.ico") == true) {
            val inputStream = "".byteInputStream(Charset.defaultCharset())
            return WebResourceResponse("text", "UTF-8", inputStream)
        } else {
            return super.shouldInterceptRequest(view, request)
        }
    }
}

-2

WebView类中有一个名为getFavicon()的方法。我认为这个方法是由WebView调用的,通过发出请求从服务器检索favicon。因此,您可以尝试扩展WebView类并覆盖getFavicon()方法以不执行任何操作。我自己还没有尝试过,但这可能有效。


1
这个不行,这个方法是同步的,并且只返回当前缓存的网站图标位图。 - Miloš Černilovský

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接