Tuesday, February 22, 2011

File upload in through WebView on Android

Getting <input type="file" /> to work on Android in WebView of custom app is pain, but doable. I have googled for hours and found nothing about this, eventually I got Android's stock browsers source from their git repository, and found out they are using undocumented method of WebCrhomeClient to support this functionality. Note this method is hidden with @hide annotation which means it is not supposed to be used. It works well on 2.2 and 2.3, and I had limited success on 2.1. So here is the code which should give you idea:


public class MyAwesomeActivity extends Activity {
    
 private WebView wv;
 
 private ValueCallback<Uri> mUploadMessage;
 private final static int FILECHOOSER_RESULTCODE=1;
 
 @Override
 protected void onActivityResult(int requestCode, int resultCode,
                                    Intent intent) {
  if(requestCode==FILECHOOSER_RESULTCODE)
  {
   if (null == mUploadMessage) return;
            Uri result = intent == null || resultCode != RESULT_OK ? null
                    : intent.getData();
            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;
            
  }
 }
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  wv = new WebView(this);
  wv.setWebViewClient(new WebViewClient());
  wv.setWebChromeClient(new WebChromeClient()
  {
         //The undocumented magic method override
         //Eclipse will swear at you if you try to put @Override here
         public void openFileChooser(ValueCallback<Uri> uploadMsg) {
         
          mUploadMessage = uploadMsg;
          Intent i = new Intent(Intent.ACTION_GET_CONTENT);
          i.addCategory(Intent.CATEGORY_OPENABLE);
          i.setType("image/*");
          MyAwesomeActivity.this.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE);
   
         }
  });

  setContentView(wv);
 }
  


Edit (response to comments): 


Since there are still so many people interested in implementing this, and I am not very often on here, I'll try to respond the comments here:


1) I don't have a full code package with this that I can share. I don't do Android development lately (unfortunately) so I don't even have eclipse on my workstation at moment. Maybe I will do that some day. But I can assure you that this snippet worked and the apps I developed using this technique are still on the market.


2) Step by step process? Probably not... If you dig basics of how Activities and Intents work this code should be pretty self explanatory.


3) I am not 100% sure what file types would work using this technique. I used it for images only. I assume that everything that would work through the Browser app should work through here as well. Try experimenting with the types, follow the standards. Most likely the problem is on the web-server end rather than on Android, you could use Wireshark to see what's really going on.


4) The warning about openFileChooser never used locally is normal, in fact I'm pretty sure it is supposed to give you the warning. If it's not working out for you the problem is somewhere else.


5) I'd be surprised it'd work out of box on honeycomb. There is no source code for honeycomb available as far as I know so I guess no way to check out how the Browser app does it there. But the SDK is still available and someone with reverse engineering skills could quickly determine what methods are they calling there and give it a try.

15 comments:

  1. Hi,

    Can you please share the complete code?

    I'm getting an error at "MyTab"

    Thank you.

    ReplyDelete
  2. @Zeus, my apologies, instead of MyTab it should be MyAwesomeActivity. Corrected. Unfortunately I don't have a full code that I can share at moment, if you are still running into problems, message me again.

    ReplyDelete
  3. Hello,

    Can you suggest a step-wise process as to how can I use the above code to upload a file using WebView.

    Would really appreciate your help if you can help me with this.

    Thanks in advance.

    ReplyDelete
  4. Awesome! Works like a charm for me-- a real time saver.

    ReplyDelete
  5. Tested this code for attachment to email and noticed that it works well for image type. But, if trying to send other types like .html or .zip, it is not attaching properly or not sending properly. Is there an issue with attachment for other types? I used i.setType("*/*") but only works well for image type.

    ReplyDelete
  6. This is the only solution I've found that appears to have worked for anyone, but I can't get it to work for me.

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. I don't know the reason, but it didn't worked for me, It was showing an warning message -> The method openFileChooser(ValueCallback) from the type new WebChromeClient(){} is never used locally

    Do we need to call it explicitly somewhere??

    ReplyDelete
  9. Hi, I have problem with this... Eclipse i saying "openFileChooser(ValueCallback uploadMsg) is never used locally" WHY ???? :(

    ReplyDelete
  10. Como seleciono multiple arquivos no webview?

    ReplyDelete