Anda di halaman 1dari 13

Stack Overflow

Questions

Tags

Users

sign up
Badges

Unanswered

log in

Ask

Read this post in our app!

File Upload in WebView


74

android

android-emulator

webview

I have been struggling to upload files from WebView since last few days and there is no
progress. I googled and implemented all suggested solutions but none works, like: solutions
suggested here - Android webview, file input field filechooser doesn't show up....,
http://blog.tourizo.com/2009/02/how-to-display-local-file-in-android.... and so on.
Problem: I have a HTML page with the following code to upload a file. It works fine in a desktop
browser like Firefox and built-in browser of emulator / AVD i.e., when I click "Browse..." button
rendered by element, browser opens a Dialog box where I can choose a file to upload.
However, in the android 3.0 emulator / AVD, when I click on "Choose file", nothing happens, no
file dialog is opened!!!
<form method="POST" enctype="multipart/form-data">
File to upload: <input type="file" name="uploadfile">&nbsp;&nbsp;
<input type="submit" value="Press to Upload..."> to upload the file!
</form>

Could anyone please suggest a possible solution at the earliest.

share

improve this question


user741148
374 1 4
Bill the Lizard
204k 129

Asked
May 6 '11 at 5:59

435 722

Edited
May 9 '11 at 12:19

You may use this Webview subclass which handles file uploads etc. automatically: github.com/delightim/Android-AdvancedWebView Marco W. Jan 8 '15 at 2:37
@MarcoW. I tried the AdvancedWebView, but still cannot upload files. jiashie Jun 17 '15 at 3:04
@jiashie File uploads work on all Android versions except Android 4.4, where there's no chance to get it
working. Maybe you're on that version? Otherwise, you can check with AdvancedWebView.isFileUploadAvailab
le() if uploads are supported. And you can share your code and ask for help in the issues: github.com/delightim/Android-AdvancedWebView/issues Marco W. Jun 17 '15 at 13:57

add a comment

order by votes

13 Answers

81

This is a full solution for all android versions, I had a hard time with this too.
public class MyWb extends Activity {
/** Called when the activity is first created. */
WebView web;
ProgressBar progressBar;
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;
}
}

Also I want to add that the "upload page" like the one in this example, wont work on < 4
versions, since it has an image preview feature, if you want to make it work use a
simple php upload without preview.
Update:
Please find the solution for lollipop devices here and thanks for gauntface

share

improve this answer


Hiram
1,067

Ramesh Akula
4,344 2 24

52

Edited
Mar 9 '15 at 7:01

Thank you very muck for save my time! Ramesh Akula Apr 3 '13 at 9:08

Answered
Mar 15 '13 at 2:56

6 10

@hifarrer you are a lifesaver. This worked nicely. PLUS, for us noobs, COMPLETE code helps
understand the placement and how it works rather than just pasting a bunch of functions and then we
not know where to put and use them. Thank you for your detailed response. Panama Jack Apr 8 '13
at 7:31
How to handle this method after obfuscation ? I am using same method without obfuscation it works
fine but when my app is deployed with obfuscation this methods is never called. I have keeps this
method in proguard anyone seen this issue? Harshawardhan Jun 25 '13 at 9:52
It works, but how come the value doesn't update as it should be? That's my test on Eclipse Android
API17 emulator. Jeffrey Neo Jan 15 '14 at 4:48

The progressBar seems unused there. I can see its hiding only, but not where it's activated. I think
you'd need to add onProgressChanged(...) to the custom WebChromeClient variant for that. (And
something like getWindow().setFeatureInt( Window.FEATURE_PROGRESS, Window.PROGRESS_VISIB
ILITY_ON); into onCreate.) Sz. Jan 22 '14 at 16:08

show 12 more comments

29

this is the only solution that i found that works!


WebView webview;

+50

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;
}

// Next part

share

improve this answer


Jbane
349

Roman Black
2,425 1

11 25

Edited
Jul 10 '14 at 10:01

Can you clarify please where should I place this code? and How should I use it? CAMOBAP Dec 19
'12 at 10:11

20

Answered
Aug 12 '11 at 14:53

3 3

As of 4.4 (KitKat), openFileChooser is no longer available, hence approaches that make use of it do
not work. Steve N Apr 24 '14 at 13:06

@SteveN what is the work arround of this for 4.4(KitKat) ? nadeem gc May 12 '14 at 6:55

@nadeemgc In my case, I control the web server too, so I am detecting Android 4.4+, using a different
URL scheme (aka "my-app://some/other/arguments") for the upload link, intercepting these URLs in
shouldOverrideUrlLoading(), and then showing a picker & doing the upload in native code for that
case. It's not exactly a lightweight workaround. Steve N May 12 '14 at 13:06

Can I upload an image in android 4.4.2 using webview? BABU K Jul 31 '14 at 6:28

show 3 more comments

16

I found that I needed 3 interface definitions in order to handle various version of


android.
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
FreeHealthTrack.this.startActivityForResult(Intent.createChooser(i,"Image Chooser"), F
ILECHOOSER_RESULTCODE);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String
capture) {
openFileChooser(uploadMsg);
}

share

improve this answer


Yaakov
191 1

Answered
Nov 27 '12 at 19:50

Thanks, the last one is required for Jelly Bean, which was the one not working for me. shalafi Mar 13
'13 at 8:09

How to handle this method after obfuscation ? I am using same method without obfuscation it works
fine but when my app is deployed with obfuscation this methods is never called. I have keeps this
method in proguard anyone seen this issue? Harshawardhan Jun 25 '13 at 9:51

It would be better to do it the other way round, i.e. put the code in the last one one which has the
richest signature, and make use of its parameters to choose which kind of intent to launch. Then have
the other two call the last one with default values for those parameters. matteo May 10 '14 at 21:46

add a comment

14

This solution also works for Honeycomb and Ice Cream Sandwich. Seems like Google
introduced a cool new feature (accept attribute) and forgot to to implement an
overload for backwards compatibility.

protected class CustomWebChromeClient extends WebChromeClient


{
// For Android 3.0+
public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType )
{
context.mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
context.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MainActivity.FILECH
OOSER_RESULTCODE );
}

share

// For Android < 3.0


public void openFileChooser( ValueCallback<Uri> uploadMsg )
{
openFileChooser( uploadMsg, "" );
}

improve this answer


Michel Olivier
141 1 3

Answered
Jan 3 '12 at 13:56

Edited
Jan 3 '12 at 14:03

Can you clarify please where should I place this class? and How should I use it? Thanks CAMOBAP
Dec 18 '12 at 21:24

place this class anywhere in your activity & use this code webview.setWebChromeClient(new
CustomWebChromeClient()); Vishal Pawar Dec 20 '12 at 8:58

m0s-programming.blogspot.in/2011/02/ Edmar Miyake Aug 20 '13 at 19:28

As of 4.4 (KitKat), openFileChooser is no longer available, hence approaches that make use of it do
not work. Steve N Apr 24 '14 at 13:07

add a comment

11

In 5.0 Lollipop, Google added an official method,


WebChromeClient.onShowFileChooser. They even provide a way to automatically
generate the file chooser intent so that it uses the input accept mime types.

public class MyWebChromeClient extends WebChromeClient {


// reference to activity instance. May be unnecessary if your web chrome client is member c
lass.
private MyActivity activity;
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
// make sure there is no existing message
if (myActivity.uploadMessage != null) {
myActivity.uploadMessage.onReceiveValue(null);
myActivity.uploadMessage = null;
}
myActivity.uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
try {
myActivity.startActivityForResult(intent, MyActivity.REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e) {
myActivity.uploadMessage = null;
Toast.makeText(myActivity, "Cannot open file chooser", Toast.LENGTH_LONG).show();

For Android versions before KitKat, the private methods mentioned in the other
answers work. I have not found a good workaround for KitKat (4.4).

share

improve this answer


weiyin
2,419

2 19 39

Answered
Apr 9 '15 at 17:37

Edited
Jan 5 at 17:00

in my situation, uploadMessage.onReceiveValue() works,and has a close ) Ninja Jan 5 at 11:26

add a comment

10

share

I found it necessary to define public void openFileChooser(ValueCallback<Uri> uploadMsg,


String acceptType, String capture), in Android 4.1. Then I followed Michel Olivier's solution.

improve this answer


stalepretzel
5,015 10

58 82

Answered
Jul 23 '12 at 3:00

Can you clarify please where should I define this method? and How should I use it? CAMOBAP Dec 19 '12 at
10:46

add a comment

10

hifarrer's full solution is very helpful to me.

but, I met many other problems - supporting other mime type, listing capture
devices(camera, video, audio recoder), opening capture device immediately(ex: <input
accept="image/*;capture"> )...
So, I made a solution that works exactly same as default web browser app.
I used android-4.4.3_r1/src/com/android/browser/UploadHandler.java. (thanks to
Rupert Rawnsley )
package org.mospi.agatenativewebview;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;

additional string resoruce of res/values/string.xml :


<string name="uploads_disabled">File uploads are disabled.</string>
<string name="choose_upload">Choose file for upload</string>

If you are using proguard, you may need below option in proguard-project.txt :
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void openFileChooser(...);
}

UPDATE #1 (2015.09.09)
adds code for Android 5.0.1 compatability.

share

improve this answer


UnknownStack
461 5 14

Answered
Jun 18 '14 at 8:22

Edited
Sep 9 '15 at 2:49

Can not get it to work in 4.4.2. Have you test it on android 4.4.2 Ana Jan 12 '15 at 11:10

@Anna openFileChooser function is not called on Android 4.4, 4.4.1, 4.4.2. This bug was fixed on
Android 4.4.3. ref.) http://code.google.com/p/android/issues/detail?id=62220 but, saddly, many

people uses 4.4.2. I think you may use your own java script interface(see DanelK's answer) or other
hybrid framework(cordova, phonegap, agate...). In my case, I can't modify HTML files on server. So I
used Agate WebView Java Script Plugin. AgateWebViewFileUpload_AndroidEclipse UnknownStack
Jan 13 '15 at 7:48

How to do in 4.4.2 tushar narang Apr 21 '15 at 10:49

@UnknownStack I am also trying to implement agate Webview Fil upload. Instead of htm page I want
to set a url to the webview,. How do i do that? tushar narang Apr 21 '15 at 11:36

@tusharnarang Open "assets/moml/ui/webView.xml" file. Then, find AGATEWEBVIEW.src attribute


and replace "index.htm" value to your URL. (ref. github.com/applusform/WebViewFileUploadFix )
UnknownStack Apr 23 '15 at 5:10

show 1 more comment

Google's own browser offers such a comprehensive solution to this problem that it
warrants it's own class:
openFileChooser implementation in Android 4.0.4
UploadHandler class in Android 4.0.4

share

improve this answer


Rupert Rawnsley
1,138 10 23

Answered
Jul 10 '12 at 13:43

Ive actually managed to get the file picker to appear in Kitkat, to select a image and to
get the filepath in activity result but the only thing that im not able to "fix" (cause this
workaround) is to make the input filed to fill out with file data.
Does anyone know any way how to access the input-field from a activity ? Am using
this example comment. Is just this last piece, the last brick in the wall that i just have to
put into right place (tho i could trigger upload of image file directly from code.

UPDATE #1
Im no hardcore Android dev so i'll show code on newbie level. Im creating a new
Activity in already existing Activity
Manifest part
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:label="TestApp">
<activity android:name=".BrowseActivity"></activity>
</application>

Am creating my BrowseActivity class from this example answer. The


WebChromeClient() instance basically looks the same, except last piece, triggering the

picker UI part...
private final static int FILECHOOSER_RESULTCODE=1;
private final static int KITKAT_RESULTCODE = 2;
...
// The new WebChromeClient() looks pretty much the same, except one piece...
WebChromeClient chromeClient = new WebChromeClient(){
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) { /* Default code */ }
// For Android 3.0+
public void openFileChooser( ValueCallback uploadMsg, String acceptType ) { /* Default code
*/ }
//For Android 4.1, also default but it'll be as example
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String captur
e){
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);

And some more stuff


web = new WebView(this);
// Notice this part, setting chromeClient as js interface is just lazy
web.getSettings().setJavaScriptEnabled(true);
web.addJavascriptInterface(chromeClient, "jsi" );
web.getSettings().setAllowFileAccess(true);
web.getSettings().setAllowContentAccess(true);
web.clearCache(true);
web.loadUrl( "http://as3breeze.com/upload.html" );
web.setWebViewClient(new myWebClient());
web.setWebChromeClient(chromeClient);
@Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
Log.d("Result", "("+requestCode+ ") - (" +resultCode + ") - (" + intent + ") - " + mUploadMessage);
if (null == intent) return;
Uri result = null;
if(requestCode==FILECHOOSER_RESULTCODE)
{
Log.d("Result","Old android");
if (null == mUploadMessage) return;
result = intent == null || resultCode != RESULT_OK ? null : intent.getData();

}
Lastly, some more code to get the actual file path, code found on SO, ive added post url
in comments as well so the author gets credits for his work.

/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
* @source http://stackoverflow.com/a/20559175
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");

Lastly, the HTML page needs to trigger that new method of showPicker (specificaly
when on A4.4)
<form id="form-upload" method="post" enctype="multipart/form-data">
<input id="fileupload" name="fileupload" type="file" onclick="javascript:prepareForPicker();"/>
</form>
<script type="text/javascript">
function getAndroidVersion() {
var ua = navigator.userAgent;
var match = ua.match(/Android\s([0-9\.]*)/);
return match ? match[1] : false;
};
function prepareForPicker(){
if(getAndroidVersion().indexOf("4.4") != -1){
window.jsi.showPicker();
return false;
}
}
function CheckImage(name)
{
//Check to see if user wants to save I used some ajax to save the file if necesarry
}
</script>

share

improve this answer


Deko
172

3 17

JacoT
18 3

Can we get a working demo of this ??? tushar narang Apr 21 '15 at 9:51

add a comment

Answered
Aug 31 '14 at 11:50

Edited
Oct 22 '14 at 13:32

Working Method from HONEYCOMB (API 11) to Lollipop (API 23)


static WebView mWebView;
private ValueCallback<Uri> mUploadMessage;
public ValueCallback<Uri[]> uploadMessage;
public static final int REQUEST_SELECT_FILE = 100;
private final static int FILECHOOSER_RESULTCODE = 1;

Modified onActivityResult()
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent)
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
if (requestCode == REQUEST_SELECT_FILE)
{
if (uploadMessage == null)
return;
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resu
ltCode, intent));
uploadMessage = null;
}
}
else if (requestCode == FILECHOOSER_RESULTCODE)
{
if (null == mUploadMessage)
return;
// Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
// Use RESULT_OK only if you're implementing WebView inside an Activity
Uri result = intent == null || resultCode != MainActivity.RESULT_OK ? null : intent.getData();

Now in onCreate() or onCreateView() paste the following code


WebSettings mWebSettings = mWebView.getSettings();
mWebSettings.setJavaScriptEnabled(true);
mWebSettings.setSupportZoom(false);
mWebSettings.setAllowFileAccess(true);
mWebSettings.setAllowFileAccess(true);
mWebSettings.setAllowContentAccess(true);
mWebView.setWebChromeClient(new WebChromeClient()
{
// For 3.0+ Devices (Start)
// onActivityResult attached before constructor
protected void openFileChooser(ValueCallback uploadMsg, String acceptType)
{
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCOD
E);
}

share

improve this answer


zackygaurav
485 7 19

Answered
Jul 24 '15 at 9:22

Dudupoo
28 5

Edited
Dec 15 '15 at 6:46

Found a SOLUTION which works for me! Add one more rule in the file proguardandroid.txt:
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void openFileChooser(...);
}

share

improve this answer


ViliusK
4,442

2 32 49

computingfreak
341 2 11

Answered
Nov 27 '14 at 10:29

Edited
Feb 24 at 7:00

Which version of Android are you using? Punchlinern Dec 22 '14 at 12:08
4.4.4 CyanogemMode 11 ViliusK Dec 23 '14 at 14:29
Perfect thanks. Clive Jefferies Jan 20 '15 at 15:03

add a comment

have you visited this links? http://groups.google.com/group/androiddevelopers/browse_thread/thread/dcaf8b2fdd8a90c4/62d5e2ffef31ebdb


http://moazzam-khan.com/blog/?tag=android-upload-file
http://evgenyg.wordpress.com/2010/05/01/uploading-files-multipart-post-apache/
Concise example of file upload via Java lib Apache Commons
i think you will get help from this

share

improve this answer


Android
3,834

5 36 72

Answered
May 9 '11 at 12:27

Thanks for your suggestions Pragna. The actual issue is - the webview is not presenting me the file upload
dialog box where I can choose a file to upload. So, first I need a solution which enables me to display the file
upload dialog box, then I can refer to the links you have suggested. user741148 May 10 '11 at 4:35
stackoverflow.com/questions/5617388/browse-button-required once see this link Android May 10 '11 at
6:06

thx 4 ur suggestions Pragna. None works... actually one thing I have observed is, overriding
openFileChooser(ValueCallback<Uri>) method of WebChromeClient works in android 2.2, wherein clicking on a
<input type="file"> field in the UI, facilitates file selection from gallery, however, same does not work in android
3.0... there4, I thought of trying file upload in webview with flash file upload, but in the android 3.0 emulator
flash is not installed by default and to install it market app is not available and so on complications...
concluding, solution seems impossible with givens! user741148 May 20 '11 at 10:44

add a comment

share

In KitKat you can use the Storage Access Framework.


Storage Access Framework / Writing a Client App

improve this answer


NDC035
1 3

Answered
May 26 '14 at 9:52

Edited
May 26 '14 at 12:47

"Maybe"? Can you provide more context for your post? Please, read How to Answer. brasofilo May 26 '14 at
10:05
Is there sample code to implement it in android 4.4.2 using webview? BABU K Jul 31 '14 at 6:29

add a comment

meta chat tour help blog privacy policy legal contact us full site
Download the Stack Exchange Android app
2016 Stack Exchange, Inc

Anda mungkin juga menyukai