File Upload from Webview on Android

You have a form on WebView, with input type as “file”, and want to allow the user to upload a file from his device. Prior to Lollipop, this was not very straightforward, and you had to resort to using private APIs, which has always been discouraged. But, you had to do it. With Lollipop, there’s a new public API, which still isn’t very straight-forward to use, but at-least, should be reliable and compatible with newer Android/WebView versions. So, how do you implement File Upload from WebView on Android with the new public API? 

This has been a long pending request, and people have implemented workarounds by using various versions of some private API’s for various older versions of Android.


Steps to Implement (3 steps)

  • Attach WebViewChromeClient, and override method callback for a click event on and input field of type file.
mWebView.setWebChromeClient(new WebChromeClient() {

        @Override
         public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,              FileChooserParams fileChooserParams) {
                 mFilePathCallback = filePathCallback;
                // Launch Intent for picking file
                return true;
         }
});
  • Launch Intent for picking the file
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
startActivityForResult(intent, PICKFILE_REQUEST_CODE);
  • Pass the Uri of the selected file to WebView
@Override
protected void onActivityResult(int requestCode, int resultCode,
     Intent intent) {
     if (requestCode == PICKFILE_REQUEST_CODE) {
          Uri result = intent == null || resultCode != RESULT_OK ? null
              : intent.getData();
          Uri[] resultsArray = new Uri[1];
          resultsArray[0] = result;
          mFilePathCallback.onReceiveValue(resultsArray);
     }
}

 

I have created a small sample project with all the required code to achieve a simple input field taking in an image. You can get the source on Github.

Improved Copy/Paste in Gingerbread

It’s really important for the copy/paste feature to work on a mobile even if you don’t have a mouse to select text you want to copy. Apple’s implementation is nice. Till Froyo, there wasn’t a unified concept of copy/paste feature implemented. But, the Gingerbread has actually changed a few things 🙂 . Copying phone numbers from your mails and email addresses from web pages should be trivial and should involve the least amount of button presses. Prior to Gingerbread, this wasn’t the case, but Gingerbread has this “New Feature now”.

Here’s the link where you can find out more about this.

Some images and videos

Official documentation

You need to double-tap on the text before you can bring up the text selection controls. Once you are done with the selection, single tap on the text copies the selected text to the clipboard, and then you can extract the data from the clipboard. This is really nice. Else, you would have to write a bit of extra code to trigger text selection mode first. This copy/paste selector works on an EditText and on the Browser. I haven’t tested it further.

Gingerbread Stuff!!!! **It works on the emulator**.

Android WebView, Javascript and CSS

Using WebViews on Android is pretty interesting. I have come across some situations where I had to use a WebView to display some HTML content. Displaying HTML content is pretty straight-forward. But when it comes to controlling the web view, it gets a little complex. Things like showing alerts, manipulating divs and controlling the activity (closing/finishing). This example shows a few techniques that will get you going with Javascript and CSS with WebView.

1. CSS: Applying CSS is just the same as you would do with normal HTML pages. The sample_page.html in the assets folder refers to the sample_style.css file in the same folder. One thing you might notice is how we get the rounder corners for the divs. This CSS attribute does the trick.

             -webkit-border-radius: 5px;

2. Javascript: To make it simpler, I have used the JQuery library. The mobile version released recently gave some errors. So, I have used the normal library available. The jquery-1.4.2.min.js also resides in the assets folder and is referenced in the sample_page.html.

3. All together: In the sample_page.html I have a header, a body and the controls. The controls have four buttons
      a: JToggle: This toggles the visibility of the body section. This is a pure javascript method call from the html.
      b: NToggle: This also toggles the visibility of the body section. But it does it differently. The javascript calls to the JSInterface.java method, which in turn calls the same Javascript method.
      c. Exit: This button basically closes/exits the app, by calling the JSInterface.java method which is bound to the HomeActivity.java via OnExitAppListener.java
      d. Alert: This shows an alert which is basically an AlertDialog in Android.

Calling a Javascript method from your Java code:
webView.loadUrl(“javascript:jsToggle()”);

Calling a Java method from Javascript:
window.jsinterface.nativeToggle();
/*
  // Before using the above code, you have to inject the interface object which
  // has a name “jsinterface”
  webView.addJavascriptInterface(jsInterface, “jsinterface”);
*/

Controlling the Alerts from Javascript:
The SampleChromeClient.java which extends the WebChromeClient has several methods which provide hooks which allow you to customize their behaviour. For an example, you can override the behaviour of the alert function and do whatever you want. You can show your own dialog with Yes/No buttons and depending on the input, you can send back the result to your Javascript code.
 @Override
 public boolean onJsAlert(WebView view, String url, String message, JsResult result)
 {
     url = “Sample App Alert”;
     return super.onJsAlert(view, url, message, result);
 }

You can checkout the whole source code here. It’s ready to run. Let me know if you have any issues.