Android WebView and File Input

While working on a web app that I wanted to embed in a WebView on Android to create a native app (hybrid), I encountered some problems with file input. The app is a simple one that allows users to upload photos, and shows a list of friends photos. (Instagram anyone?)

These days file input on mobile devices works pretty ok on iOS and Android devices. Adding <input type=’file’ /> will create a file input, and clicking it will let the user pick a file from your phone. At least from Chrome or Safari. However, when putting this in a WebView, it is currently not handled for you automatically.

Googling around to figure out what is going on reveals that this is something that has to be implemented by yourself by overriding a couple of functions in an instance of WebChromeClient. Unfortunately there are still a couple of issues with this. First of all, the functions that has to be overridden har undocumented. Second of all, returning the files seem to be devoid of file type, which is not necessarily a problem for everyone, but that was a problem for me.

First of all, the functions that has to be overridden are:

mWebView.setWebChromeClient(new WebChromeClient() {

@SuppressWarnings(“unused”)

public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType, String capture) {

this.openFileChooser(uploadMsg);

}

@SuppressWarnings(“unused”)

public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType) {

this.openFileChooser(uploadMsg);

}

public void openFileChooser(ValueCallback<Uri> uploadMsg) {

mUploadMessage = uploadMsg;

pickFile();

}

});

The three functions illustrate a progression of Android, where the last one is for early versions of android, and the last one is for Android 4.1+. Potentially then, this might change in the future.

The use of this then is to return the value in mUploadMessage by calling its callback.

Picking the file is easy enough using an intent call.

Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT);

chooserIntent.setType(“image/*”);

startActivityForResult(chooserIntent, RESULTCODE);

 

And you return the file in onActivityResult:

protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

mUploadMessage.onReceiveValue(intent.getData());

mUploadMessage = null;

}

 

(Note: There’s not error handling here, so remember to include that!)

So far so good. This will cause the file input data set, so we can submit it from a form, or access it from javascript.

What I needed this image for, was to both update a picture on the web page, and also to upload this data later on. The way I solved this was to use HTML5 local file reading through a FileReader object, and then reading the data using readAsDataURL

var reader = new FileReader();

reader.readAsDataURL(file);

reader.onload = function(e) {

var dataurl = e.target.result;

}

So we got dataurl as a URI object, which will be on the form “data:image/png;base64,…”. Or so is it normally. Problem is that from at least Android 4.2.2 (On my Nexus 4), the file object that is returned to javascript from Android does not have the file type set. (file.type===undefined). This makes the data URI to be invalid as it only describes binary data: “data:base64,…”. This caused major problems for me, but I managed to fix it. Fortunately the filename is set correctly, and so I can use the file ending. From that I can reform the dataurl to create a correct one

dataurl = “data:image/” + file.name.split(‘.’).slice(-1)[0] + “;base64,” + dataurl.split(‘,’)[1];

The rest of the script then works. You can use the dataurl to set the image src ($(“#theimage”).attr(‘src’,dataurl); and you can upload it as a string.

I’m guessing there might be a fix for this to get Android to pass a file with the correct type set, but without that fix, this one seems to work.

 

Posted in Uncategorized

Steve Jobs 1983

All talk about Steve Jobs can sometimes be quite tiring. It is however hard to dismiss his insight into the domain in which he was working. Here is a speech from 1983, in which it is clear that he had a firm grasp on what was about to come. He gets many things wrong, such as the idea of the hand held iPad kind of device within the 1980s (it took 20 more years). But it is extremely interesting to listen to many of the things he got right.

I especially like how he wants computers to beautiful and that industrial designers must pay attention to the computer industry to start working towards more beautiful artifacts, and more beautiful experiences. He says that these things (the computers) will inevitable be all around us, in our home and in our offices, and so we now (1983) have the time to make sure they are beautiful. Unfortunately the IBM desktops kind of took over for a long time and we had those gray boring things for a long long time. But I think we can see how that is changing with companies putting more efforts into doing beautiful devices (computers, mobile phones, tablets). If only they would have started doing that already in 1983…

Listen to it here.

 

Posted in Uncategorized

How to choose between web and native

Forbes has an article on how to choose between mobile web and native apps. It has a simple overview of pros and cons of the two, and what intermediate versions there are. Their claim is that it is more complicated than two ends of a spectrum, but you can choose in between. Most interestingly is what they name a dedicated web app

Dedicated web app, which is a mobile web site tailored to a specific platform or form factor, like the LinkedIn web app which was designed for Android and iOS, but not for other smartphones or feature phones.

as opposed to a generic mobile app “which are mobile web sites designed to match every web-enabled phone, like the Wikipedia mobile page.”. I have definitely gone for the dedicated web app more times than the generic mobile web app.

I agree in principle with their end points, which state that you should build whatever solution you decide on, on the data. Create an API for the data, and build the app to use the API. This is really just good development style, but can definitely help when building mobile (web) apps if you need to try different solutions later on. As some people advocate “web first, native second” (e.g. this guy), having the API and data in place, you have laid the ground work.

 

Posted in Uncategorized | Leave a reply