15

How can I disable the Android WebView/WebViewClient from sending out a request for favicon.ico when I call WebView.loadUrl()? I can see the call being made while profiling requests via CharlesProxy.

I do not own the HTML content that I am displaying in the WebView. My research has turned up a lot of results on workarounds from the server side but these won't work for me.

Travis Yim
  • 384
  • 3
  • 14

5 Answers5

10

for me the complete solution was:

   @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;
    }
marmor
  • 27,641
  • 11
  • 107
  • 150
ventura8
  • 554
  • 6
  • 18
  • @MilošČernilovský dis one is right answer instead of putting icon in asset. seems to be very clean simple and right approach – Android is everything for me Sep 19 '19 at 04:29
  • 1
    As a side note, `request.isForMainFrame()` is however probably not doing what you expect, since it returns false for even the initially loaded URL containing the iframe. See: https://stackoverflow.com/questions/40000939/what-is-isformainframe-request-in-android-webviewclient-property-meaning – mtkopone Nov 21 '19 at 12:57
  • What I find weird is that after doing that, even though I see no call being done in Charles, I receive an error as if the call had been made and no icon had been found (that's what happened to the app before removing the favicon call). I cleared the cache and disabled it, but it still happens...Idk why that's happening. Also, whatever I pass in the WebSourceResponse, like the mimeType, appears as empty when onReceivedHttpError or onReceivedError are called. – FabioR Jun 19 '20 at 17:22
6

I achieved this by a little hack. First, I've created a fake 1x1 icon file and saved it to the assets folder. Then I overrode WebViewClient's shouldInterceptRequest() method, where I check the URL whether it is the request for favicon file and in that case return WebResourceResponse with InputStream which contains our fake icon:

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

Note that the InputStream must not be closed in our code, because it is subsequently used by the WebView to read the icon. The WebviewClient must be set to the WebView via its setter:

mWebView.setWebViewClient(subclassedWebViewClient);
Miloš Černilovský
  • 3,846
  • 1
  • 28
  • 30
2

This is an answer for 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)
    }
}

By default, return type is not nullable WebResourceResponse when Android Studio generates code, but It does not work so change return type to nullable WebResourceResponse.

J.J. Kim
  • 1,845
  • 1
  • 16
  • 21
2

You can simply pass some dummy InputStream to WebResourceResponse as shown below.

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)
        }
    }
}
Ashwin
  • 7,277
  • 1
  • 48
  • 70
-2

There is a method for WebView class named getFavicon(). I think that method is called by WebView to retrieve the favicon from server by issuing request. So you can try extending the WebView class and override the getFavicon() method to do nothing. I haven't tried it myself but this might work.

Arun Babu
  • 259
  • 1
  • 4
  • 12