APKs Won’t Download In Android Browser

If you, like me, are attempting to setup a download end point for Android APK files that doesn’t include a .apk in the URL, you have probably butted your head against a myriad of issues. It’s worth noting that downloading APKs in Dolphin, Firefox Mobile, or Opera all work fine with respect to using Content-Disposition headers alone. It’s just the native browser that gives us grief. For the native browser, my first pass at the endpoint’s download code was the naive approach:

header('Content-Disposition: attachment; filename='.$apk_name);
echo file_get_contents($web_inaccessible_dir.'/'.$apk_name);

Testing this code in any desktop browser, I get the expected download notification and the file downloads like a champ. When I test drive this in the Android browser the result is different. Rather than getting a file download, I get the correct filename downloading but instead of using the necessary APK extension, the file is magically transformed into an HTM file, which is completely useless. This seems like a painfully bad decision for the content handling mechanisms of the browser, perhaps even a bug. Looking for some sign in the Android logs, I see this:

D/MediaScannerService( 1386): IMediaScannerService.scanFile: /mnt/sdcard/download/that_apk_file.htm mimeType: text/html

So while this is completely bad behavior, at least there’s a trail of hope in it — MIME type. Text/HTML is not the MIME type an APK file should have and apparently the browser is making us play by the rules. I can understand that. After all, if the MIME type is the source of truth then an APK file extension is only going to make the OS confused about what to do with the file. So, the question becomes what file type should an Android APK file have?

Doing some Googling about it, I find Wikipedia has the answer. The APK file format entry explains that Android APK files should have a MIME type of application/vnd.android.package-archive. Armed with this knowledge, I tried modifying my endpoint to send the MIME type I want:

header('Content-Disposition: attachment; filename='.$apk_name);
header('Content-Type: application/vnd.android.package-archive');
echo file_get_contents($web_inaccessible_dir.'/'.$apk_name);

Hitting the endpoint now, I find that the browser gets the APK file with the APK extension. Booyah. Just for rigor, I check logcat, and see what I was hoping to see:

D/MediaScannerService( 1386): IMediaScannerService.scanFile: /mnt/sdcard/download/that_apk_file.apk mimeType: application/vnd.android.package-archive

This is good, but I notice there are still flaws in the pearl. Namely, the file downloads without an indication of filesize or progress. The downloads page shows only that the download is “in progess” all the way up to completion. On a slow connection, this will seem like the file is stuck. Not ideal.

So, knowing a little about the HTTP spec, it seems like what the browser might need is a Content-Length header to get a handle on the progress towards completion. This is a straight-forward change, requiring just a single line.

header('Content-Disposition: attachment; filename='.$apk_name);
header('Content-Type: application/vnd.android.package-archive');
header('Content-Length: '.filesize($web_inaccessible_dir.'/'.$apk_name));
echo file_get_contents($web_inaccessible_dir.'/'.$apk_name);

Giving this a whirl in the browser, I find that I now have both the correct file extension and a progress bar during the download. Huzza.

I believe I’ve got what I want, but with Android it’s not guaranteed to be that simple. Due to fragmentation, I can only assume this works on the devices I’ve tested. So far, that includes the T-Mobile G2X (2.3.3 + T-mo’s bloatware), the x86 Android Emulator running 2.2 (by the way, if you haven’t tried out the x86 Emulator for Android and are still using the ARM emulator, you need to check out http://www.android-x86.org/ — it will change your whole perspective on shit), and the HTC Sensation 4G running 2.3.4 + Sense UI. I feel like that’s a good enough start to write this post. Please comment if you have an OS version/phone that doesn’t work with this setup.

Here We Go Again

This is the first post of the newest iteration of my corner of the web. Enjoy and converse. In case you’re curious, this is a WordPress blog. I’m not a WordPress fanboy, but it is the best tool for the job as far as I’m concerned. I rebuilt most of the blog twice before switching to WP. The first time, I wrote a directory parser/cacher system that would let me statically generate the blog from flat files. The second time, I wrote an even more sophisticated version that was still file-backed rather than database backed. I was doing a lot of fancy caching, minimizing, and dog fooding. Still, I wasn’t getting it done fast enough. Who cares who fast a blog loads if it isn’t done enough to launch. Exactly no one, including me. After spending probably fifteen hours on each I had the epiphany that just using WordPress will deliver significantly more bang for the time I spend. At the time of this writitng I have approximately 7 hours in the project and it’s nearly complete in terms of desired layout and features for desktops and tablets. The handheld mobile view sucks, but I haven’t spent any time optimizing for that yet. I’ll get there. Anyway, now that this bad boy is up and running, look for frequent updates with interesting things.

When I Get All Steamed Up

(Originally posted on a 3rd party blog site)

You don’t need to tip me over. You don’t need to pour me out. I’ll handle that myself. This should be posted on my site, but I like to break things up. If nothing else, it will increase my search engine visibility and make it even more likely that when someone searches for “jackson gabbard” they get nothing but me. No dead Kentuckians, no products or companies. No elementary school kids from North Carolina. Just the freelance web developer and designer.

This post comes as an interlude between work and work. Paula Dean is tasting hot peppers on TV across the room and commenting about how if he picks her nose right now, the front of her face will catch on fire. One would think her face would incur chemical burns first and probably never actually catch fire. For skin, and most things, to burn, they have to be completely desiccated. Nothing about Paula Dean seems to be that way, aside from her hair that is.

Today I encountered some word use I hadn’t heard in a long time (circumspect, assiduous, etc.). Uncommon words with highly specific meanings are treasures. As such, you can’t just go flaunting them around in mixed company. For one, doing so marks you as an elitist, a show off. Secondly, most people can’t understand you. Like Dave Chappelle once overstated in a skit, “I cain’t understaaand yoooo. Go back where you came from.” Or something like that. When you present someone with something they can’t understand that they also recognize they can’t understand because they aren’t as educated as you, well, you get a reaction.

That said, I was happy to hear that some people keep the other 90% of the English lexicon alive. The dictionary is a bit like a word museum. Once something gets pulled from public view and placed in a museum, it becomes dated and unfamiliar. Pulling the words out of their glass display cases and jamming them in there with the vocabulary of the peanut gallery once in a while does everyone some good.

It reminds the speaker of the boundaries in communication and reminds the listener that there are words beyond what the average person hears that can achieve communication more quickly. Of course, if the person doesn’t know the word then it becomes a stumbling point. Like my friend Laurie mentioned, if you have to label it (in this case, explain it), you have failed. I don’t know that I agree with that 100% though. You have failed at communicating at 100% efficiency, but you have succeeded in exposing someone to something new. There is value is broadening people’s horizons.

Speaking of altering perspectives, I’m becoming a sociopath. Actually, I suppose I should say I’m returning to sociopathy. I’m probably overstating, but the practicing sociopath in me doesn’t care how you feel about it. It’s not my concern whether you take away a perfect understanding or not. Succeeding in business requires this of me. I spent years breaking myself of the inclination to disregard the way other people feel about things I affect only to find that many of the people I work for are disregarding the way I feel. To them I say, be a wolf, get a wolf. Or, in less metaphorical terms, get a smart guy interested in not getting eaten to the point of being willing to eat you first. Sorry, compassion complicates my sociopathy, so it has to be conditionally applied.

There’s personal growth inherent in the process, of course. Controlling my emotional reaction to threats and dealing with things on a professional plane only is tricky for me. According to research, it’s tricky for everyone since we’re irrational, emotional creatures. However, I want to be a commercially successful irrational creature, so I’m having to learn to feign rationality when things heat up so I don’t do something impulsive that costs me in the long run. When someone tries to take advantage of me, I have to see the opportunity in the adversity (thanks for the reminder Einstein) and make the situation work for me. If I can’t make it work at all, I have to walk away.

The compassionate person in me wants to help the advantage-taker see what they are doing, the victim in me wants to defend myself Malcolm X style, and the eager beaver in me wants to make the person happy, even if that means giving everything away. The business man in me has to win and find the solution that resolves the situation as much as possible without sacrificing me, my time, or any money. Then, after I get the check, I can revisit thoughts of any means necessary and education.

This is very unlike me. If you’re doing something awful, I want to help you see how and why. I don’t want to just make you behave how I want you to. However, I’m dealing now with adults whom it’s not my responsibility to raise. Or at least, whom it’s not my business’ responsibility to raise. So, the wolf gets to call the shots. I suppose a better metaphor is the fox though, they’re much cleverer. Maybe some sort of hybrid–the brains of the fox, the body and bite of the wolf. Wolfox? Folf? Wolx? I suppose a clever conjoining of the nouns isn’t requisite for the idea to sink in, but it would be funner.

Whether it takes a wolf, a fox, or a manatee, I have to keep my eyes open, my pulse level, and my sociopath switch ready to flip. You might want something, but if you didn’t pay for it, you’re not getting it. Even if that means I have to fire you. Lesson learned there.

I realize now that I’ve just made a faux pas (fox paws?). ‘Whether’ followed by three options? What sort of self-respecting English degree holder am I? Every Tom, Dick, and Harry knows the etymology of ‘whether’ hearkens back to the phrase ‘which of two,’ much like ‘either’ and ‘neither.’ ‘Whether’ followed by three options. What’s next–dilemma with four alternatives? Sheesh. Please accept my deepest apologies for the error. Though, if you desire some sort of recompense jingling in hand for the mistake, you might instead find a brief and brisk application of the canines.