17

If I have a file made available to a browser through my webapp, I normally just set the URL to something like http://website.com/webapp/download/89347/image.jpg. I then set the HTTP headers Content-Type: application/octet-stream; filename=image.jpg and Content-Disposition: Attachment.

However, on the Android. It seems the only way I can get the file to download is to set Content-Type: image/jpg. Otherwise the file name says <Unknown> and an error comes

Download unsuccessful
Cannot download. The content is not supported on this phone

Is there any way I can get Android to download and open the file through the browser without keeping a list of mime types?

700 Software
  • 85,281
  • 83
  • 234
  • 341
  • Hello George, I am using the same technique to make a download link but I didn't get how can we set "HTTP headers" while preparing a downlink link for an anchor tag? can you explain more on this? – nrsharma Jun 22 '15 at 05:49
  • Setting the HTTP headers is done server-side on the webserver, often using a programming language such as PHP, Java, CGI, etc. How are you serving up your files to download? – 700 Software Jun 23 '15 at 20:05
  • Keep in mind this is an older post referencing some of the earlier android versions, and may have outdated information. Content-Disposition is usually used to indicate a download is requested, instead of just 'viewing'. – 700 Software Jun 23 '15 at 20:06

5 Answers5

28

To make any downloads work on all (and especially older) Android versions as expected, you need to...

  1. set the ContentType to application/octet-stream
  2. put the Content-Disposition filename value in double quotes
  3. write the Content-Disposition filename extension in UPPERCASE

Read my blog post for more details:
http://digiblog.de/2011/04/19/android-and-the-download-file-headers/

Kiquenet
  • 14,494
  • 35
  • 148
  • 243
Jpsy
  • 20,077
  • 7
  • 118
  • 115
  • see StevePayne answer if you're experiencing the device downloading the html page rather than the correct file. I solved this by changing my POST to a GET. – nidal Mar 24 '15 at 12:21
  • hI, If I am downloading image from downloadmanager then again it is not opening with error cannot open file. I have set mimitype of request to jpg. what else I have to do – Akash kumar Jan 23 '16 at 08:13
  • *Android 4, Ice Cream Sandwich*. Example: `Content-Disposition: attachment; filename="MyFileName.ZIP";` will not work correctly because of the semicolon at the end. Any tests (and _summary_) for all Android versions ? Useful: http://stackoverflow.com/questions/6319389/streaming-mime-type-application-pdf-from-asp-app-fails-in-google-chrome `Google Chrome v12 release introduced a bug that triggers the problem you describe. You can fix it by sending the Content-Length header` https://bugs.chromium.org/p/chromium/issues/detail?id=85549 – Kiquenet Jan 25 '17 at 15:45
  • 2
    #3 is definitely needed. I have set my server to send my own mimetype but android is still saving it as application/octet-stream when I changed the file extension to uppercase it worked. – kuchi Apr 22 '17 at 14:18
  • Thanks for the feedback @kuchi. I can't believe this stuff is still relevant. When I wrote this in 2011 we were on Android 2.1 !!! – Jpsy Apr 23 '17 at 00:20
10

Dmitriy (or others looking for a possible solution) if an html page is appearing in your downloaded file, I suspect this is due to the double HttpRequest GET issue. A typical scenario is the following POST, Redirect, GET model:

  • Android browser issues a HttpRequest POST to server (e.g. submit button or link to request a download file, filename.ext say)

  • Server streams the requested filename.ext to bytes, stores in a session variable, and then issues a Response.Redirect to Download.aspx, for example, to handle the response object construction

  • Android browser correctly sends HttpRequest GET to server for Download.aspx

  • Server responds with typical Content-Disposition: attachment; filename="filename.ext" style construct with the response object containing the requested filename.ext, being the bytes in the session variable.

  • Android download manager, I believe, then sends another HttpRequest GET to server for Download.aspx. I suspect that the download manager interprets the previous "attachment" response as a trigger to send this second GET.

  • Server (Download.aspx) again tries to construct the response object to send back to the browser.

  • Android download manager downloads filename.ext, using the response object contents from the second Download.aspx.

In many scenarios this would be fine. But if, for example, the server in the Download.aspx code does some housekeeping and removes the session variable the first time it is called, then the next time around there is no session variable. So, depending on how the code is written it is possible that the response object doesn't get explicity constructed and maybe the Response.End doesn't get called and so only the Download.aspx's html ends up being sent.

This is what we discovered using Wireshark, although I admit I am assuming it is the Android download manager that is the cause for the double GET.

I hope this explanation has been of some help.

StevePayne
  • 101
  • 1
  • 2
  • 3
    Steve, your explanation matches very much with the observations of the commenters of my blog post (mentioned in my answer above). This is a problem that seems to happen even with higher Android versions (at least up to 3.2.1) and seems to depend on the browser in use (Dolphin & Android stock affected, FF and Opera not affected). A possible solution is to replace the first request by a GET or to encode (if possible) all needed data into the URL of the download request. Cheers, Jörg. – Jpsy Feb 08 '12 at 08:37
  • 1
    I found issues [1780](http://code.google.com/p/android/issues/detail?id=1780) and [3948](http://code.google.com/p/android/issues/detail?id=3948) in the Android forum, which describe the inability of the stock browser and the Android download manager to correctly handle downloads initiated through POST requests. Both reports have been acknowledged by forum moderators, but labelled as “enhancements” instead of as bugs. 1780 is over 3 years old, starred by +100 visitors and there is still no indication that it has been resolved, not even in the latest Android version (4.0.4 at this moment). – Jpsy Feb 09 '12 at 07:52
  • did somebody find solution? it's still valid issue. I receive two requests on server during downloading. Is it possible to figure out which request is fake? – Diyko Mar 05 '13 at 14:19
2

As I wrote at downloading files from android:

Android browser will not download file in button Post events. In post events the file will be some .htm garbage file. to over come this do as below.

In download button click

 protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
    {
        Response.Redirect("download-file.aspx");
    }

and on  download-file.aspx file do as below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class mobile_download_file : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string filename = "usermanual.pdf";
        Response.ContentType = "application/octet-stream";
        Response.AppendHeader("Content-Disposition", "attachment; filename=" + "" + filename + "");
        Response.Write(Server.MapPath(Request.ApplicationPath) + "\\" + filename);
        Response.TransmitFile(Server.MapPath(Request.ApplicationPath) + "\\" + filename);
        Response.End();
    }
}

the same can be implemented in php also.
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • Hello Martin, and welcome to StackOverflow. 1. I don't think POST requests are part of the question, but that is not as important, and maybe your answer is helpful to some people. 2. I think that the code sample is not relevant here. **I don't use php or aspx.**. 3. **I recommend** edit replace the code sample with text such as "you would need to create a redirect as a response to the POST, and then have the file download from the URL you redirected to". Those looking for code samples should post a question for their language. – 700 Software Nov 25 '13 at 15:10
  • Which ***Android*** _versions_ you tested ? – Kiquenet Jan 25 '17 at 15:29
0

I have tried all recommendations from Jspy blog and nothing worked so far. Content-disposition brings browser in downloading mode, however nothing gets downloaded except HTML of page from which download got initiated. So my conclusion, it is pure bug from Google and we may only pray for that Google fix it. My work around was to set content type to some type coming from Accept header form mobile browser. It generally works, you can even download zip files as text.

Dmitriy R
  • 613
  • 1
  • 5
  • 12
  • 4
    Dmitriy, if your Android downloads the HTML of your source(!) page, than there is definitely something wrong with your server script logic. If the download fails on side of Android then there would be no possibility to have the source HTML in a file - usually you would get the download content but not written into a file or a general error message. But the source HTML is not available at that point in time. Think about it. – Jpsy Oct 13 '11 at 08:17
0

In theory, the filename parameter should be set on Content-Disposition, not Content-Type. Not sure whether this will help with the Android browser.

Julian Reschke
  • 40,156
  • 8
  • 95
  • 98