101

I have a webview in my Android Application. When user goes to webview and click a link to download a file nothing happens.

URL = "my url";
mWebView = (WebView) findViewById(R.id.webview);
mWebView.setWebViewClient(new HelloWebViewClient());
mWebView.getSettings().setDefaultZoom(ZoomDensity.FAR);
mWebView.loadUrl(URL);
Log.v("TheURL", URL);

How to enable download inside a webview? If I disable webview and enable the intent to load the URL on browser from application then download works seamlessly.

String url = "my url";
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);

Can someone help me out here? The page loads without issue but the link to a image file in the HTML page is not working...

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Jay Mayu
  • 17,023
  • 32
  • 114
  • 148
  • 1
    You may use this `Webview` subclass which handles downloads etc. automatically: https://github.com/delight-im/Android-AdvancedWebView – caw Jan 08 '15 at 01:50

6 Answers6

146

Have you tried?

mWebView.setDownloadListener(new DownloadListener() {
    public void onDownloadStart(String url, String userAgent,
                String contentDisposition, String mimetype,
                long contentLength) {
        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setData(Uri.parse(url));
        startActivity(i);
    }
});

Example Link: Webview File Download - Thanks @c49

user370305
  • 108,599
  • 23
  • 164
  • 151
  • 2
    This code works, but if the user was authenticated in the WebView they are asked to log in again once the Android browser launches, after that the download happens. I'm trying to find a way to avoid that, so the download happens without them having to log in again. – MetaGuru Sep 12 '12 at 16:14
  • 1
    Try this link for any kind of download http://androidtrainningcenter.blogspot.in/2013/11/download-file-videoaudiotext-through.html – Tofeeq Ahmad Dec 02 '13 at 06:13
  • 1
    @ioSamurai Have you found a way to download files which requires user authentication. `webView.setDownloadListener()` works perfectly when there is no user auth required. But when I download a file from google drive or other sources which requires user auth, a file is downloaded but there is no data. @user370305 you can also help. – Sp4Rx Nov 07 '16 at 04:57
  • 1
    You can check [Chrome Custom tabs](https://developer.chrome.com/multidevice/android/customtabs) which will solve most of the problems. @Rohit – Sp4Rx Aug 22 '18 at 05:38
  • 1
    @Sp4Rx yeah it works on that but I need some other functionality that only works on webview – Rohit Aug 22 '18 at 10:22
  • 1
    @user370305 Where would I insert this code? I am using React Native. – Laney Williams Nov 25 '18 at 18:44
  • 1
    I like the simplicity of this method and with a dynamically created PDF file it works very well for me, but the process opens a browser and leave it on top of my application; is it possible to run the same code, but without the browser being left open? – Sean Dec 03 '18 at 15:17
70

Try this out. After going through a lot of posts and forums, I found this.

mWebView.setDownloadListener(new DownloadListener() {       

    @Override
    public void onDownloadStart(String url, String userAgent,
                                    String contentDisposition, String mimetype,
                                    long contentLength) {
            DownloadManager.Request request = new DownloadManager.Request(
                    Uri.parse(url));

            request.allowScanningByMediaScanner();
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //Notify client once download is completed!
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "Name of your downloadble file goes here, example: Mathematics II ");
            DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
            dm.enqueue(request);
            Toast.makeText(getApplicationContext(), "Downloading File", //To notify the Client that the file is being downloaded
                    Toast.LENGTH_LONG).show();

        }
    });

Do not forget to give this permission! This is very important! Add this in your Manifest file(The AndroidManifest.xml file)

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />        <!-- for your file, say a pdf to work -->

Hope this helps. Cheers :)

Henrique de Sousa
  • 5,727
  • 49
  • 55
Sai Z
  • 711
  • 5
  • 9
  • 17
    Thanks it worked!, for using original file name, we can use: `final String filename= URLUtil.guessFileName(url, contentDisposition, mimetype);` – Jawaad Sep 21 '15 at 20:09
  • 10
    @SaiZ your example contains some code about an unused intent, i guess you should remove it. – j.c Oct 30 '15 at 00:09
  • 1
    @j.c i removed the unused code, thanks for reporting it ;) – MatPag Mar 14 '17 at 17:01
  • 3
    This is perfect answer this would launch download from webview directly, which is actually expected... Thanks – Ghanshyam Bagul Aug 13 '17 at 05:29
  • @Jawaad Could you please explain where should I put this native android code? I work with Xamarin.forms which compiles to native and I usually dare not touch native code, but here it's a **must**. TYIA. – s3c Sep 04 '20 at 05:29
  • @s3c, You can put it right above the request.setDestinationInExternalPublicDir And replace "Name of your downloadble file goes here, example: Mathematics II " with filename – Jawaad Sep 04 '20 at 15:00
  • 1
    @Jawaad Thank you for your response. I'm still clueless though. I don't even know which file to open. I tried searching my entire solution for `request.setDestinationInExternalPublicDir` but there were no matches. #xamarin-forms – s3c Sep 05 '20 at 11:16
30
    mwebView.setDownloadListener(new DownloadListener()
   {

  @Override  


   public void onDownloadStart(String url, String userAgent,
        String contentDisposition, String mimeType,
        long contentLength) {

    DownloadManager.Request request = new DownloadManager.Request(
            Uri.parse(url));


    request.setMimeType(mimeType);


    String cookies = CookieManager.getInstance().getCookie(url);


    request.addRequestHeader("cookie", cookies);


    request.addRequestHeader("User-Agent", userAgent);


    request.setDescription("Downloading file...");


    request.setTitle(URLUtil.guessFileName(url, contentDisposition,
            mimeType));


    request.allowScanningByMediaScanner();


    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    request.setDestinationInExternalPublicDir(
            Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(
                    url, contentDisposition, mimeType));
    DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
    dm.enqueue(request);
    Toast.makeText(getApplicationContext(), "Downloading File",
            Toast.LENGTH_LONG).show();
}});
Kulasekar
  • 497
  • 5
  • 6
17

Try using download manager, which can help you download everything you want and save you time.

Check those to options:

Option 1 ->

 mWebView.setDownloadListener(new DownloadListener() {
        public void onDownloadStart(String url, String userAgent,
                String contentDisposition, String mimetype,
                long contentLength) {
 Request request = new Request(
                            Uri.parse(url));
                    request.allowScanningByMediaScanner();
                    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "download"); 
                    DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
                    dm.enqueue(request);        

        }
    });

Option 2 ->

if(mWebview.getUrl().contains(".mp3") {
 Request request = new Request(
                        Uri.parse(url));
                request.allowScanningByMediaScanner();
                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "download"); 
// You can change the name of the downloads, by changing "download" to everything you want, such as the mWebview title...
                DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
                dm.enqueue(request);        

    }
6
webView.setDownloadListener(new DownloadListener()
        {
            @Override
            public void onDownloadStart(String url, String userAgent,
                                        String contentDisposition, String mimeType,
                                        long contentLength) {
                DownloadManager.Request request = new DownloadManager.Request(
                        Uri.parse(url));
                request.setMimeType(mimeType);
                String cookies = CookieManager.getInstance().getCookie(url);
                request.addRequestHeader("cookie", cookies);
                request.addRequestHeader("User-Agent", userAgent);
                request.setDescription("Downloading File...");
                request.setTitle(URLUtil.guessFileName(url, contentDisposition, mimeType));
                request.allowScanningByMediaScanner();
                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                request.setDestinationInExternalPublicDir(
                        Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(
                                url, contentDisposition, mimeType));
                DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
                dm.enqueue(request);
                Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show();
            }});
Techie Vineet
  • 131
  • 3
  • 2
2

If you don't want to use a download manager then you can use this code

webView.setDownloadListener(new DownloadListener() {

            @Override
            public void onDownloadStart(String url, String userAgent, String contentDisposition
                    , String mimetype, long contentLength) {

                String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype);

                try {
                    String address = Environment.getExternalStorageDirectory().getAbsolutePath() + "/"
                            + Environment.DIRECTORY_DOWNLOADS + "/" +
                            fileName;
                    File file = new File(address);
                    boolean a = file.createNewFile();

                    URL link = new URL(url);
                    downloadFile(link, address);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

 public void downloadFile(URL url, String outputFileName) throws IOException {

        try (InputStream in = url.openStream();
             ReadableByteChannel rbc = Channels.newChannel(in);
             FileOutputStream fos = new FileOutputStream(outputFileName)) {
            fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
        }
           // do your work here

    }

This will download files in the downloads folder in phone storage. You can use threads if you want to download that in the background (use thread.alive() and timer class to know the download is complete or not). This is useful when we download small files, as you can do the next task just after the download.

Vijay
  • 1,163
  • 8
  • 22