7
votes

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?

2
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: 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
@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
I haven't specifically tried it in a WebView, no (I was just using the Browser app). The Android Browser uses WebViews though: android.git.kernel.org/?p=platform/packages/apps/… - Charlie Collins
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?: developer.android.com/reference/android/webkit/… -- I'm going to write a test real quick and see (it's an interesting problem ;).) - Charlie Collins
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

2 Answers

7
votes

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.

2
votes

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.