Skip to content
webtoapkfree

Why are file downloads not working in my Android WebView app?

WebView file download not working? A WebView needs a DownloadListener to save files, and blob links, missing cookies and storage rules break it.

GuidesNookesh Karri

Light cover card with the title 'Why are file downloads not working in my Android WebView app?' in dark text and a green accent bar

A WebView file download not working almost always means the app has no download handler, or the handler can’t reach the file. Android WebView doesn’t save files on its own: the app must catch the download and pass it to something like DownloadManager. Blob links, missing login cookies and storage rules are the other usual causes.

Why WebView doesn’t save files by itself

Android WebView only renders pages, so a tap on a file link does nothing until the app registers a handler. The WebView reference says setDownloadListener registers the interface used when content can’t be handled by the rendering engine and should be downloaded instead.

That listener gets one callback. Per the DownloadListener docs, onDownloadStart tells the app “that a file should be downloaded” and passes five values:

  • url: the file’s address
  • userAgent: the user agent to use for the download
  • contentDisposition: the server’s Content-Disposition header, if present
  • mimetype: the type the server reported
  • contentLength: the size the server reported

The listener saves nothing. The app still has to fetch the file, usually by building a DownloadManager.Request.

WebView file download not working? Match the symptom to the cause

The fastest way to fix a broken download is to look at what actually happens when you tap the link. Each symptom points to a different cause.

What you see Likely cause Fix
Nothing happens on tap No DownloadListener registered Add a listener and enqueue a DownloadManager request
A small .html file instead of the PDF Request sent without the login cookies Copy cookies from CookieManager into the request
Crash or nothing on “Export” buttons The page made a blob: link Read the data in JavaScript and pass it to the app
File saved as download or file.bin Name taken from the URL only Build the name from Content-Disposition and MIME type
Listener never fires The page downloads through its own script Check how the site starts the download

The last row is the confusing one. In one Stack Overflow question, JavaScript started the download and the listener never fired.

Fix 1: Register a download listener

A download listener is the first thing to add, because without one no file link works. Inside onDownloadStart, create a request from the URL and hand it to the system’s DownloadManager.

The DownloadManager.Request docs say the URI “is the only required parameter” and must be an HTTP or HTTPS address. Two settings help users find the file:

  1. VISIBILITY_VISIBLE_NOTIFY_COMPLETED keeps the download in notifications “while in progress and after completion”.
  2. A destination and a title put the file somewhere the user expects.

The same page warns that the default destination is a shared volume where the system might delete the file to reclaim space.

Fix 2: Send the login cookies with the request

A protected file fails because DownloadManager makes its own request, separate from the WebView’s session. If your site keeps users signed in with a cookie, the server sees an anonymous visitor and returns its sign-in page. The phone then saves that HTML page with a .pdf name.

The fix is two lines. CookieManager.getCookie returns the cookies for a URL in the format of the Cookie request header. Pass that string to addRequestHeader("Cookie", ...), and pass the userAgent value from the listener too, since some servers check it.

A blob: download fails because the file only exists inside the web page, not on any server. Sites create these links when they build a file in the browser, such as a CSV export or a generated invoice.

MDN’s blob URL page explains that browsers release these object URLs when the document is unloaded. DownloadManager can’t fetch them, because it only accepts HTTP or HTTPS. Developers using react-native-webview report blob downloads that fail or crash the app.

The common workaround is a JavaScript bridge:

  1. In the page, read the blob into Base64 with FileReader.
  2. Call a method the app exposed with addJavascriptInterface.
  3. In the app, decode the data and write the file.

Per the JavascriptInterface docs, only methods marked with that annotation are visible to JavaScript. Expose only the one save method, and only to your own site.

Fix 4: Get the file name right

A wrong file name happens when the app builds the name from the URL alone. Links like /export?id=abc give no useful name.

URLUtil.guessFileName uses the URL and the Content-Disposition header, and adds an extension from the MIME type when one is missing. Pass all three values from the listener. On the web side, MDN notes that the filename in Content-Disposition overrides the download attribute, so the server header is the place to set it.

Fix 5: Check storage permissions on newer Android

Storage permissions matter less than older tutorials suggest. Android’s shared storage guide says devices on Android 10 or higher don’t need storage permissions to access media files the app owns. Its legacy WRITE_EXTERNAL_STORAGE example uses android:maxSdkVersion="29".

A permission request copied from an old answer is rarely the fix on a current phone. Test on the oldest Android version you support and on a new one.

What if you used a no-code WebView builder?

With a no-code builder, you can’t add Java code, so the fix has to come from the website or the builder. My take: change the website first. Serve files from a normal HTTPS link with a Content-Disposition header, and drop blob-only exports. That works in any WebView wrapper.

WebToAPK Free has the same limit. It builds a WebView app, and it doesn’t promise that every site behaves as it does in Chrome: downloads, sign-in, permissions and external links can differ. Its how-it-works page tells you to test downloads on the devices you plan to support before you publish. If your site serves files behind a login, test that flow first.

More on what a wrapper can and can’t do: which apps use WebView and how to convert a website into an Android app. If your files need to open offline, read whether a WebView app works without internet. Before submitting, check whether Google Play rejects WebView apps.

FAQ

Android WebView doesn’t save files by itself. The app must register a DownloadListener and hand the link to something that saves it, such as DownloadManager. Without that code, the tap goes nowhere.

Why does my WebView app download an HTML page instead of the PDF?

The file sits behind a login and the download request went out without the WebView’s cookies. The server then returns its sign-in page. Pass the cookies from CookieManager with the request.

Can DownloadManager download a blob: URL?

No. DownloadManager.Request takes an HTTP or HTTPS address, and a blob: URL only exists inside the page that created it. The page or a JavaScript bridge has to read the data and pass it to the app.

Do I need storage permission to save downloads in a WebView app?

Usually not on newer phones. Android’s documentation says devices on Android 10 or higher don’t need storage permissions for media files the app owns. Older versions follow the legacy permission rules.

How do I test downloads in a WebView app?

Install the APK on a real phone, sign in, and try every kind of file your site offers: a public file, a protected one and anything generated in the page. Check the notification and the Downloads folder each time.

Sources