7

I am supposed to display a web page in a webview in an app. The page contains a html form where one of the fields is file. So it goes something like...

<input type="file" name="file">

If I open the page in the browser and press the Choose File button, file chooser pops up and everything is good, but when I press the Choose File button in the webview nothing happens :/

Any ideas how to make this work?

m0s
  • 4,250
  • 9
  • 41
  • 64
  • What version of Android are you working with? I believe prior to FroYo (2.2) the built-in Android browser didn't support file upload: http://code.google.com/p/android/issues/detail?id=2519 (as of 2.2 it should work though, works fine on my N1 running 2.2). – Charlie Collins Feb 09 '11 at 14:49
  • @Charlie Collins I am trying this on 2.1, 2.2, 2.3 and it would be ok if it worked on any of these. It works fine in browser even on 2.1(Galaxy S), but I need this to work in a WebView in a custom app. Are you saying it works fine in your app with a WebView on 2.2? – m0s Feb 09 '11 at 15:02
  • I haven't specifically tried it in a WebView, no (I was just using the Browser app). The Android Browser uses WebViews though: http://android.git.kernel.org/?p=platform/packages/apps/Browser.git;a=blob_plain;f=src/com/android/browser/BrowserActivity.java;hb=HEAD – Charlie Collins Feb 09 '11 at 18:46
  • One other thing, as I said I haven't tried it, so I am just guessing here, but maybe you need to enable "file access" to make it happen?: http://developer.android.com/reference/android/webkit/WebSettings.html#setAllowFileAccess%28boolean%29 -- I'm going to write a test real quick and see (it's an interesting problem ;).) – Charlie Collins Feb 09 '11 at 18:53
  • Nope, doesn't work for me in a WebView either. I know for a long time WebKit mobile didn't support it (so neither did Android, and people were pissed about that, but not Android's fault), and it then it was deemed a "security" issue, and as of 2.2 it became available in the regular Browser. I'm not sure why it doesn't work in WebView (I've never before tried to do it). – Charlie Collins Feb 09 '11 at 20:01
  • @Charlie Collins Thanks for the effort. I got the Browser sources from the git repository, and what I found out is they override openFileChooser method of WebChromeClient to handle choose file event, but there is no such method in any of their released SDKs D: – m0s Feb 09 '11 at 21:19

2 Answers2

7

WebView by default doesn't open file chooser. However it is possible to make this work. WebChromeClient has hidden method openFileChooser, which needs to be overridden to pop up a file chooser and then return the result to WebView. According to gurus one should never use hidden methods of Android SDK so this is not a good solution, and probably shouldn't be used in enterprise apps. However Android's stock Browser does exactly this way. Little more information how I overrode this method is in my this question. If anyone needs the source let me know Ill post it somewhere.

Community
  • 1
  • 1
m0s
  • 4,250
  • 9
  • 41
  • 64
  • Hi, i need to do the exact same thing.. can u post the example code somewhere?? – ghostCoder Oct 02 '11 at 13:19
  • @ghostCoder Hey, I posted it http://m0s-programming.blogspot.com/2011/02/file-upload-in-through-webview-on.html If you'll have further questions, ask here I don't check that blog very often. – m0s Oct 03 '11 at 18:08
  • Thanks for the post m0s, it seems to work in 2.2 but not honeycomb. Any ideas how to get it to work in honeycomb? – odiggity Oct 27 '11 at 20:33
  • Is this still the only way to go in 2014? – matteo Apr 21 '14 at 15:42
  • 1
    @matteo I don't know whether this is the only way, but it is still a working way that didn't cause problems to the best of my knowledge. In newer versions of android sdk you'd only have to override all overloads of the open chooser method to make it work. – m0s Apr 22 '14 at 03:58
  • 1
    Yeah it still works. Full working code here: http://stackoverflow.com/questions/5907369/file-upload-in-webview#answer-15423907 (at least it worked for me in 2.3 and 4.1 and 4.2). I have found code snippets simpler than that but none of them worked (perhaps they work only on some specific Android version) ... (note: I commented out the progress bar stuff) – matteo Apr 22 '14 at 12:56
  • 1
    You were right by saying that you shouldn't override undocumented methods. In Android 4.4, solutions that used `openFileChooser` stopped working see this [bug](https://code.google.com/p/android/issues/detail?id=62220) and it was closed as "WorkingAsIntended". – Alfredo Osorio Sep 01 '14 at 17:40
  • @Alfredo Osorio Yes. But... if you want to, this is still easy to implement in 4.4. Method 1) look at how it's done in stock android browser for 4.4. The signature for the callback is changed, you fix the signature, do some tweaks and it will work again. Method 2) handle javascript callback that you bind on input, and then use custom http upload code. – m0s Sep 01 '14 at 20:15
2

Is it possible to upload files via webview?

This feature is available in version 1.3.0 and newer. For older versions of the app, yes it is possible, but you need to add some extra code to make it work. Add following code into your AndroidManifest.xml file. Place it below other uses-permission elements:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Copy/paste this java class MediaUtility.java into the project. Place it into com/robotemplates/webviewapp/utility directory.

Open MainFragment.java in fragment package. Find renderView() method and replace “webView.setWebChromeClient(new WebChromeClient());” by following code:

webView.setWebChromeClient(new WebChromeClient()
{
    public void openFileChooser(ValueCallback<Uri> filePathCallback)
    {
        mFilePathCallback4 = filePathCallback;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(Intent.createChooser(intent, "File Chooser"), REQUEST_FILE_PICKER);
    }

    public void openFileChooser(ValueCallback filePathCallback, String acceptType)
    {
        mFilePathCallback4 = filePathCallback;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(Intent.createChooser(intent, "File Chooser"), REQUEST_FILE_PICKER);
    }

    public void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType, String capture)
    {
        mFilePathCallback4 = filePathCallback;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(Intent.createChooser(intent, "File Chooser"), REQUEST_FILE_PICKER);
    }

    @Override
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
    {
        mFilePathCallback5 = filePathCallback;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(Intent.createChooser(intent, "File Chooser"), REQUEST_FILE_PICKER);
        return true;
    }
});

Finally add following code somewhere inside the MainFragment object (for instance below this line “private boolean mLocal = false;”):

private static final int REQUEST_FILE_PICKER = 1;
private ValueCallback<Uri> mFilePathCallback4;
private ValueCallback<Uri[]> mFilePathCallback5;

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent)
{
    if(requestCode==REQUEST_FILE_PICKER)
    {
        if(mFilePathCallback4!=null)
        {
            Uri result = intent==null || resultCode!=Activity.RESULT_OK ? null : intent.getData();
            if(result!=null)
            {
                String path = MediaUtility.getPath(getActivity(), result);
                Uri uri = Uri.fromFile(new File(path));
                mFilePathCallback4.onReceiveValue(uri);
            }
            else
            {
                mFilePathCallback4.onReceiveValue(null);
            }
        }
        if(mFilePathCallback5!=null)
        {
            Uri result = intent==null || resultCode!=Activity.RESULT_OK ? null : intent.getData();
            if(result!=null)
            {
                String path = MediaUtility.getPath(getActivity(), result);
                Uri uri = Uri.fromFile(new File(path));
                mFilePathCallback5.onReceiveValue(new Uri[]{ uri });
            }
            else
            {
                mFilePathCallback5.onReceiveValue(null);
            }
        }

        mFilePathCallback4 = null;
        mFilePathCallback5 = null;
    }
}

Don’t forget to add necessary imports: “import android.webkit.ValueCallback;”, “import com.robotemplates.webviewapp.utility.MediaUtility;”, “import java.io.File;”. If you still have a problem, try to add a rule in Proguard script: https://code.google.com/p/android/issues/detail?id=62220#c120.

aven
  • 21
  • 1