File upload on android for JavaScript app

Nicolas Goy
The missing bit
Published in
2 min readJan 29, 2017

--

Originally published on August 4 2016.

Disclaimer: I had to implement this solution because of some imperatives (coder life…), but this is not good programming practice. Hopefully Android 5 will let us do it properly.

I have a web application that shares the code on desktop, iOS and Android.

Everything works fine, except that Android does not support <input type="file"> in WebView out of the box. While iOS will happily show an image picker if the accept attributes is set to image types, Android’s WebView will just do nothing.

After some investigations, I found out that while it was possible to make it works on some version of Android, it would be broken on 4.4 and before 5 it’s by using a private API.

Even with the code I found, which is below, the returned File object in javascript land would be missing the type. Also, sending this file withxhr.send(file) would send an empty body because of an other bug.

I was not satisfied by this solution. After some thought, I decided to use a custom javascript interface. It would require some work on the JS side but I have control on that side of the app as well, so it’s not a problem.

Java side

The Java side must declare a new JavaScript interface, like so:

The interface class must live inside your activity to expose startActivityForResultand the two variables I use, imagePath and imageData. (SELECT_PICTURE is also a constant I declared)

This is quite simple (even if it is ugly Java):

  • Handle the activity result
  • Do some voodoo to find the imagePath
  • Read the image to base64
  • Call the javascript method that will read the base64 data MyApp.readFile()

JavaScript side

First you must capture the click event on your <input type="file"> or, as I did, render another react component on android. In this event handler, call our android interface: Android.opengallery(). This will trigger the Java code and open the gallery.

Then, you need to implement MyApp.readFile() like so:

And “voilà”.

It has some caveats:

  • You don’t get a real JavaScript File object, but the other solution gives you a broken file object with no type.
  • It might not work with large files, I only needed to support image < 10MB.
  • Even if it works with small files, it is inefficient as fuck.
  • You have to modify the JavaScript side.

If you cannot modify the JavaScript side, you might be able to work around it by injecting so JavaScript into your WebView, but as you don’t get a realFile object, it might not be possible.

If you need to upload large files, you could either do the full upload on the Java side, or write a JavaScript API like we did to read the file in chunks.

--

--