Add custom headers to WebView resource requests - android

149,047

Solution 1

Try

loadUrl(String url, Map<String, String> extraHeaders)

For adding headers to resources loading requests, make custom WebViewClient and override:

API 24+:
WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
or
WebResourceResponse shouldInterceptRequest(WebView view, String url)

Solution 2

You will need to intercept each request using WebViewClient.shouldInterceptRequest

With each interception, you will need to take the url, make this request yourself, and return the content stream:

WebViewClient wvc = new WebViewClient() {
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

        try {
            DefaultHttpClient client = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(url);
            httpGet.setHeader("MY-CUSTOM-HEADER", "header value");
            httpGet.setHeader(HttpHeaders.USER_AGENT, "custom user-agent");
            HttpResponse httpReponse = client.execute(httpGet);

            Header contentType = httpReponse.getEntity().getContentType();
            Header encoding = httpReponse.getEntity().getContentEncoding();
            InputStream responseInputStream = httpReponse.getEntity().getContent();

            String contentTypeValue = null;
            String encodingValue = null;
            if (contentType != null) {
                contentTypeValue = contentType.getValue();
            }
            if (encoding != null) {
                encodingValue = encoding.getValue();
            }
            return new WebResourceResponse(contentTypeValue, encodingValue, responseInputStream);
        } catch (ClientProtocolException e) {
            //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        } catch (IOException e) {
             //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        }
    }
}

Webview wv = new WebView(this);
wv.setWebViewClient(wvc);

If your minimum API target is level 21, you can use the new shouldInterceptRequest which gives you additional request information (such as headers) instead of just the URL.

Solution 3

Maybe my response quite late, but it covers API below and above 21 level.

To add headers we should intercept every request and create new one with required headers.

So we need to override shouldInterceptRequest method called in both cases: 1. for API until level 21; 2. for API level 21+

    webView.setWebViewClient(new WebViewClient() {

        // Handle API until level 21
        @SuppressWarnings("deprecation")
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

            return getNewResponse(url);
        }

        // Handle API 21+
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

            String url = request.getUrl().toString();

            return getNewResponse(url);
        }

        private WebResourceResponse getNewResponse(String url) {

            try {
                OkHttpClient httpClient = new OkHttpClient();

                Request request = new Request.Builder()
                        .url(url.trim())
                        .addHeader("Authorization", "YOU_AUTH_KEY") // Example header
                        .addHeader("api-key", "YOUR_API_KEY") // Example header
                        .build();

                Response response = httpClient.newCall(request).execute();

                return new WebResourceResponse(
                        null,
                        response.header("content-encoding", "utf-8"),
                        response.body().byteStream()
                );

            } catch (Exception e) {
                return null;
            }

        }
   });

If response type should be processed you could change

        return new WebResourceResponse(
                null, // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

to

        return new WebResourceResponse(
                getMimeType(url), // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

and add method

        private String getMimeType(String url) {
            String type = null;
            String extension = MimeTypeMap.getFileExtensionFromUrl(url);

            if (extension != null) {

                switch (extension) {
                    case "js":
                        return "text/javascript";
                    case "woff":
                        return "application/font-woff";
                    case "woff2":
                        return "application/font-woff2";
                    case "ttf":
                        return "application/x-font-ttf";
                    case "eot":
                        return "application/vnd.ms-fontobject";
                    case "svg":
                        return "image/svg+xml";
                }

                type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
            }

            return type;
        }

Solution 4

As mentioned before, you can do this:

 WebView  host = (WebView)this.findViewById(R.id.webView);
 String url = "<yoururladdress>";

 Map <String, String> extraHeaders = new HashMap<String, String>();
 extraHeaders.put("Authorization","Bearer"); 
 host.loadUrl(url,extraHeaders);

I tested this and on with a MVC Controller that I extended the Authorize Attribute to inspect the header and the header is there.

Solution 5

This works for me:

  1. First you need to create method, which will be returns your headers you want to add to request:

    private Map<String, String> getCustomHeaders()
    {
        Map<String, String> headers = new HashMap<>();
        headers.put("YOURHEADER", "VALUE");
        return headers;
    }
    
  2. Second you need to create WebViewClient:

    private WebViewClient getWebViewClient()
    {
    
        return new WebViewClient()
        {
    
        @Override
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
        {
            view.loadUrl(request.getUrl().toString(), getCustomHeaders());
            return true;
        }
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url)
        {
            view.loadUrl(url, getCustomHeaders());
            return true;
        }
    };
    }
    
  3. Add WebViewClient to your WebView:

    webView.setWebViewClient(getWebViewClient());
    

Hope this helps.

Share:
149,047

Related videos on Youtube

Ray
Author by

Ray

Updated on October 17, 2020

Comments

  • Ray
    Ray over 3 years

    I need to add custom headers to EVERY request coming from the WebView. I know loadURL has the parameter for extraHeaders, but those are only applied to the initial request. All subsequent requests do not contain the headers. I have looked at all overrides in WebViewClient, but nothing allows for adding headers to resource requests - onLoadResource(WebView view, String url). Any help would be wonderful.

    Thanks, Ray

    • CommonsWare
      CommonsWare about 11 years
      @MediumOne: This isn't a bug as much it is a feature that you consider to be missing. I am not aware of anything in the HTTP specification that says subsequent HTTP requests must mirror arbitrary headers from previous HTTP requests.
    • MediumOne
      MediumOne about 11 years
      @CommonsWare: The word "subsequent" is misleading here. When I type "facebook.com" on any browser to load the facebook.com homepage, there are several supporting "resource requests" to load the CSS, js and img files. You can check this in Chrome using the F12 feature (Network tab). For these requests, the webview does not add headers. I tried adding custom headers to FireFox requests using the addons.mozilla.org/en-us/firefox/addon/modify-headers plug-in. This plugin was able to add headers to all such suppporting "resource requests". I think WebView should do the same.
    • CommonsWare
      CommonsWare about 11 years
      @MediumOne: "I think WebView should do the same" -- which is a feature that you consider to be missing. Note that you had to resort to a plugin to make Firefox do this. I am not saying that your proposed feature is a bad idea. I am saying that characterizing it as a bug is unlikely to help your cause to get this proposed feature added to Android.
    • MediumOne
      MediumOne about 11 years
      @CommonsWare: No. I still think it is a bug. Let me explain. WebView already provides the feature to add custom headers. I have just found that it is not doing it properly. When I try to load a URL (say facebook.com), the webview is responsible for loading all the requests needed to display the page. When I add custom headers for leading this URL, webview only adds for the initial request. Firefox doesn't support adding headers at all. We need a plug in to do this. And this plug-in makes sure that all the resource requests get the custom headers as well.
    • MediumOne
      MediumOne about 11 years
      @CommonsWare: Suppose that I am using a WebView to build a browser that can be configured to work with a custom HTTP proxy. This proxy uses custom authentication where are requests to it should have a custom header. Now, webview provides an API to set custom headers, but internally, it is not setting the header to all the resource requests it generates. There aren't any additional APIs to set headers for these requests as well. So, any feature which relies on adding custom headers to WebView requests fails.
    • Janak Nirmal
      Janak Nirmal about 11 years
      @Ray did you get any solution to this problem I am stuck with this too and was not able to find solution?
    • MediumOne
      MediumOne almost 7 years
      @CommonsWare - I am revisiting this conversation after 4 years. I agree now - this should not be a bug. There's nothing in the HTTP specification that says subsequent requests should send the same headers. :)
  • Ray
    Ray over 12 years
    Sorry, but this does not work. It only applies the headers too the initial requests. Headers are NOT added to the resource requests. Other ideas? Thanks.
  • peceps
    peceps over 12 years
    Yes, override WebClient.shouldOverrideUrlLoading like this: public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url, extraHeaders); return true; }
  • MediumOne
    MediumOne over 11 years
    @peceps - the callback 'shouldOverrideUrlLoading' is not called during resource loading. For example, when we try view.loadUrl("http://www.facebook.com", extraHeaders), there are multiple resource requests like 'http://static.fb.com/images/logo.png' etc that are sent from the webiew. For these requests, the extra headers are not added. And shouldOverrideUrlLoading is not called during such resource requests. The callback 'OnLoadResource' is called, but there is no way to set headers at this point.
  • yorkw
    yorkw about 11 years
    @MediumOne, for resource loading, override WebViewClient.shouldInterceptRequest(android.webkit.WebView view, java.lang.String url) Check out API for more.
  • MediumOne
    MediumOne about 11 years
    @yorkw: This method does capture all resource request urls. But there is no way to add headers to these requests. My goal is to add custom HTTP headers to all requests. If this can be achieved using the shouldInterceptRequest method, can you please explain how?
  • younes0
    younes0 about 10 years
    this doesn't answer the question
  • Martin Konecny
    Martin Konecny about 9 years
    As of API Level 21, you should be able to add headers to the WebResourceRequest object passed in
  • James Chen
    James Chen almost 9 years
    Just in case someone encounters same situation I have while using this trick. (This is a good one anyway.) Here is a note for you. Since http content-type header, which can contain optional parameter such as charset, is not fully compatible to MIME type, the requirement of first parameter of WebResourceResponse constructor, so that we should extract the MIME type part from content-type by any mean you can think of, such as RegExp, to make it work for most cases.
  • shoke
    shoke over 8 years
    Hi @MartinKonecny have you found any workarounds to make this work on previous versions of Android?
  • Hirdesh Vishwdewa
    Hirdesh Vishwdewa over 8 years
    Do you have any reference to what you say in your answer.. it will be helpful for others if you give implementation references with your answers.
  • Hirdesh Vishwdewa
    Hirdesh Vishwdewa over 8 years
    This event is deprecated.. use public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request) instead find more here
  • AAnkit
    AAnkit over 8 years
    Hey @HirdeshVishwdewa , could you able to achieve this?
  • Martin Konecny
    Martin Konecny over 8 years
    @HirdeshVishwdewa - look at the last sentence.
  • Carlo Moretti
    Carlo Moretti over 8 years
    This just keeps reloading the url, doesn't it?
  • leeroya
    leeroya about 8 years
    I will have to address this again as when it was written and posted it functioned with the Kit-Kat. I have not tried with Lolly Pop.
  • Erik Verboom
    Erik Verboom about 8 years
    Not working for me on Jelly bean or Marshmallow... doesn't change anything in the headers
  • Erik  Reppen
    Erik Reppen almost 8 years
    You can skip doing your own load by returning the results of the superclass's shouldInterceptRequest method with your webview and modified request as parameters. This is particularly handy in scenarios where you're triggering based on the URL, aren't changing it on the reload and would run into an infinite loop. Much thanks for the new request example though. Java ways of handling things are highly counterintuitive to me.
  • Silviu St
    Silviu St almost 8 years
    For me it did not work without setting user agent in header :-s
  • Tamás Kozmér
    Tamás Kozmér over 7 years
    HttpClient can't be used with compileSdk 23 and above,
  • Ivo Renkema
    Ivo Renkema about 7 years
    Looks good, but does this add a header, or does this replace the headers?
  • narancs
    narancs almost 7 years
    @MediumOne have you found anything related to this? I have the same issue now and really need some help!
  • narancs
    narancs almost 7 years
    for me it works: .post(reqbody) where RequestBody reqbody = RequestBody.create(null, "");
  • NinjaCoder
    NinjaCoder over 6 years
    This doesn't do what OP is asking. He wants to add headers to all requests made by the webview. This adds custom header to first request only
  • Akshay
    Akshay over 6 years
    This is not what OP is asking
  • willcwf
    willcwf over 5 years
    Calling view.loadUrl from this method seems to crash the app
  • Francesco
    Francesco over 5 years
    @willcwf do you have an example of this crashing?
  • Jeff Lockhart
    Jeff Lockhart about 5 years
    Unfortunately calling super.shouldInterceptRequest() after adding headers to the request object does not make the modified request as @ErikReppen described. It would be very nice if it did, but that's not the way the API works. The super call just returns null without making the request. Returning null tells the web client not to intercept the request and the request is made without the modified headers.
  • Joshua Pinter
    Joshua Pinter about 5 years
    I know this doesn't answer what OP was looking for but this was exactly what I wanted, i.e. adding an extra header to a WebViewIntent URL. Thanks, regardless!
  • Giacomo M
    Giacomo M over 4 years
    Sorry to answer to this old post, but with this code my app tries to download the file (and it fails) instead of loading the page.
  • Giacomo M
    Giacomo M over 4 years
    @Francesco my app also crashes
  • Nilzor
    Nilzor over 4 years
    yeah @jeff-lockhart, I noticed the same. So we're back to square 1? No one's got a solution?
  • Vlad
    Vlad about 4 years
    this is not the same as authorization header
  • Francesco
    Francesco almost 4 years
    Too all is downvoting this, saying that it crash is not helping. Please be more specific, write some error information.
  • AbhinayMe
    AbhinayMe almost 4 years
    @IvoRenkema loadUrl(String url, Map<String, String> additionalHttpHeaders) means add additions headers
  • mrid
    mrid over 3 years
    can this be used for post requests ?
  • mrid
    mrid over 3 years
    but this only works for get requests. what about post ?
  • nasser
    nasser almost 3 years
    Read the question again