1

I have a specific scenario where I make a POST request with a unique ticket in the body to get a resulting page back.

The resulting page is either Content-Type: application/pdfor text/html. The ticket is only valid once, so the page can only be loaded once.

Problem is that Android WebView does not support rendering of pdf (as the equivalent on iOS do).

I've tried the following:

  1. Check http response headers with a primary request and then download the file with a second request if it's a pdf and open it in a PDF app (works). But for loading html pages, the second request fails, since the ticket is no longer valid.

  2. Download both the pdf and the html page and then open in pdf app/WebView locally. This works, both relative links in the web pages is broken. Is there a nice way to download them as well?

x. Is it possible to interrupt the request in the WebView to read the response headers and trigger a download if it's a pdf otherwise just continue rendering? Can't find a good answer for this.

Black
  • 18,150
  • 39
  • 158
  • 271
likebobby
  • 1,379
  • 2
  • 14
  • 21

2 Answers2

4

You can use the built in method URLConnection.getContentType() for the exact purpose. Once you get the content type proceed with downloading or pass to the WebView.

Imports:

import java.net.URL;
import java.net.URLConnection;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

Here's a sample to intercept the URL before loading:

webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                String requestedUrl = request.getUrl().toString();

                boolean isDownloadableFile = false;

                try {
                    isDownloadableFile = new FetchContentTypeAsync(requestedUrl).execute().get();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                // downloadable file / dont load it in webview
                if (isDownloadableFile) {
                    // download the file here
                    return false;
                } else {
                    // non downloadable file / load it in webview
                    view.loadUrl(requestedUrl);
                    return super.shouldOverrideUrlLoading(view, request);
                }
            }
        });

FetchContentTypeAsync is used for running the task in background

private static class FetchContentTypeAsync extends AsyncTask<Void, Void, Boolean> {

        private String requestedUrl;

        FetchContentTypeAsync(String requestedUrl) {
            this.requestedUrl = requestedUrl;
        }

        @Override
        protected Boolean doInBackground(Void... voids) {
            boolean isDownloadableFile = false;
            try {
                URL url = new URL(requestedUrl);
                URLConnection urlConnection = url.openConnection();
                String contentType = urlConnection.getContentType();
                isDownloadableFile = contentType.equalsIgnoreCase("application/pdf");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return isDownloadableFile;
        }
    }

To download a file check Download a file with Android, and showing the progress in a ProgressDialog

Black
  • 18,150
  • 39
  • 158
  • 271
Prokash Sarkar
  • 11,723
  • 1
  • 37
  • 50
  • It's written in Kotlin. Do you need a Java version of the code? – Prokash Sarkar Nov 05 '19 at 14:27
  • Oh, ok I see. Yes please I am using Java. – Black Nov 05 '19 at 14:32
  • It would be best if you provide both solutions, in case someone else uses Kotlin. – Black Nov 05 '19 at 14:33
  • Thanks, I added code for downloading the file. The only problem is that the file is not getting opened in the app... it is silently downloaded and the browser opens and shows our website – Black Nov 06 '19 at 08:00
  • 1
    WebView doesn't support pdf files by default. You need to open it with a 3rd party library or use Google docs to load it via mWebView.loadUrl("https://docs.google.com/gview?embedded=true&url="+ webUrl); – Prokash Sarkar Nov 06 '19 at 08:31
  • ok but I guess this also means that google will receive a copy of every document downloaded from the app, which is not in our data security interest. But thats another problem... thank you! – Black Nov 06 '19 at 08:33
  • 1
    My pleasure. Google uses web "gview" to render the pdf and doesn't store your file permanently. However, opening a document with a security concern might not be ideal in this scenario. – Prokash Sarkar Nov 06 '19 at 08:38
0

After you set the WebViewClient it has some interfaces to intercept the requests the most widely used is shouldOverrideUrlLoading() but you can also override shouldInterceptRequest() and intercept it there.

webView.setWebViewClient(new WebViewClient() {
    @Override public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // Check the URL here - if it is a file, 
        // then initiate the download
        return false;
    }
}
Black
  • 18,150
  • 39
  • 158
  • 271
Elkdor
  • 121
  • 1
  • 12