We are creating an app which uses the webview and will access a page where the user needs to upload a file. We are experiencing problems with Android 4.4 where the file chooser does not open and clicking the upload button causes nothing to happen. This functionality works with earlier versions using the openFileChooser method like so:
webview.setWebChromeClient(new WebChromeClient() {
//The undocumented magic method override
//Eclipse will swear at you if you try to put @Override here
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
// For Android 3.0+
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MainActivity.this.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE);
}
//For Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), MainActivity.FILECHOOSER_RESULTCODE);
}
});
I have spent a good amount of time searching for a way to do it on 4.4 but have had no luck. Has anyone managed to do this?
Alternatives to WebView If you want to send users to a mobile site, build a progressive web app (PWA). If you want to display third-party web content, send an intent to installed web browsers. If you want to avoid leaving your app to open the browser, or if you want to customize the browser's UI, use Custom Tabs.
This interface was deprecated in API level 12. This interface is now obsolete.
You might often face issues in updating the chrome and Android System Webview. To fix this problem, you can reboot your device, check your internet connection, stop auto-updating all apps, clear Google Playstore cache, and storage, leave the beta testing program, and manually update Android WebView app from Playstore.
This Code worked for me.
private class MyWebChromeClient extends WebChromeClient {
//The undocumented magic method override
//Eclipse will swear at you if you try to put @Override here
// For Android 3.0+
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MainActivity1.this.startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
}
//For Android 4.1+ only
protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
{
mUploadMessage = uploadMsg;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
}
protected void openFileChooser(ValueCallback<Uri> uploadMsg)
{
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
// For Lollipop 5.0+ Devices
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}
uploadMessage = filePathCallback;
Intent intent = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
intent = fileChooserParams.createIntent();
}
try {
startActivityForResult(intent, REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e) {
uploadMessage = null;
Toast.makeText(getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_SELECT_FILE) {
if (uploadMessage == null) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
}
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 = data == null || resultCode != MainActivity.RESULT_OK ? null : data.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
WebView is working as intended
If I understand correctly what the above link says , you (me and probably some hundreds more developers) are looking for a hack
Have a look this. Because api 19 4.4, webview has been migrated to use Chromium, not WebChromeClient anymore.
I was working on this issue too, and the problem and here is my solution
private class MyWebChromeClient extends WebChromeClient {
/**
* This is the method used by Android 5.0+ to upload files towards a web form in a Webview
*
* @param webView
* @param filePathCallback
* @param fileChooserParams
* @return
*/
@Override
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
if (mFilePathCallback != null) {
mFilePathCallback.onReceiveValue(null);
}
mFilePathCallback = filePathCallback;
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("image/*");
Intent[] intentArray = getCameraIntent();
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Seleccionar Fuente");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
return true;
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
mProgressBar.setVisibility(View.VISIBLE);
WebActivity.this.setValue(newProgress);
super.onProgressChanged(view, newProgress);
}
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
/**
* Despite that there is not a Override annotation, this method overrides the open file
* chooser function present in Android 3.0+
*
* @param uploadMsg
* @author Tito_Leiva
*/
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = getChooserIntent(getCameraIntent(), getGalleryIntent("image/*"));
i.addCategory(Intent.CATEGORY_OPENABLE);
WebActivity.this.startActivityForResult(Intent.createChooser(i, "Selecciona la imagen"), FILECHOOSER_RESULTCODE);
}
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent i = getChooserIntent(getCameraIntent(), getGalleryIntent("*/*"));
i.addCategory(Intent.CATEGORY_OPENABLE);
WebActivity.this.startActivityForResult(
Intent.createChooser(i, "Selecciona la imagen"),
FILECHOOSER_RESULTCODE);
}
/**
* Despite that there is not a Override annotation, this method overrides the open file
* chooser function present in Android 4.1+
*
* @param uploadMsg
* @author Tito_Leiva
*/
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadMessage = uploadMsg;
Intent i = getChooserIntent(getCameraIntent(), getGalleryIntent("image/*"));
WebActivity.this.startActivityForResult(Intent.createChooser(i, "Selecciona la imagen"), FILECHOOSER_RESULTCODE);
}
private Intent[] getCameraIntent() {
// Determine Uri of camera image to save.
Intent takePictureIntent = new Intent(WebActivity.this, CameraActivity.class);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
} catch (IOException ex) {
// Error occurred while creating the File
Log.e(TAG, "Unable to create Image File", ex);
}
// Continue only if the File was successfully created
if (photoFile != null) {
mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
} else {
takePictureIntent = null;
}
}
Intent[] intentArray;
if (takePictureIntent != null) {
intentArray = new Intent[]{takePictureIntent};
} else {
intentArray = new Intent[0];
}
return intentArray;
}
private Intent getGalleryIntent(String type) {
// Filesystem.
final Intent galleryIntent = new Intent();
galleryIntent.setType(type);
galleryIntent.addCategory(Intent.CATEGORY_OPENABLE);
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
return galleryIntent;
}
private Intent getChooserIntent(Intent[] cameraIntents, Intent galleryIntent) {
// Chooser of filesystem options.
final Intent chooserIntent = Intent.createChooser(galleryIntent, "Seleccionar Fuente");
// Add the camera options.
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents);
return chooserIntent;
}
}
One problem that I solved is the uri delivered for the onActivityResult()
method does not have extension. To solve this I use this method
public static Uri savePicture(Context context, Bitmap bitmap, int maxSize) {
int cropWidth = bitmap.getWidth();
int cropHeight = bitmap.getHeight();
if (cropWidth > maxSize) {
cropHeight = cropHeight * maxSize / cropWidth;
cropWidth = maxSize;
}
if (cropHeight > maxSize) {
cropWidth = cropWidth * maxSize / cropHeight;
cropHeight = maxSize;
}
bitmap = ThumbnailUtils.extractThumbnail(bitmap, cropWidth, cropHeight, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
File mediaStorageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
context.getString(R.string.app_name)
);
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile = new File(
mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"
);
// Saving the bitmap
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
FileOutputStream stream = new FileOutputStream(mediaFile);
stream.write(out.toByteArray());
stream.close();
} catch (IOException exception) {
exception.printStackTrace();
}
// Mediascanner need to scan for the image saved
Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri fileContentUri = Uri.fromFile(mediaFile);
mediaScannerIntent.setData(fileContentUri);
context.sendBroadcast(mediaScannerIntent);
return fileContentUri;
}
Finally, onActivityResult()
method is
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if (resultCode == RESULT_OK) {
// This is for Android 4.4.4- (JellyBean & KitKat)
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage) {
super.onActivityResult(requestCode, resultCode, intent);
return;
}
final boolean isCamera;
if (intent == null) {
isCamera = true;
} else {
final String action = intent.getAction();
if (action == null) {
isCamera = false;
} else {
isCamera = action.equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
}
}
Uri selectedImageUri;
if (isCamera) {
selectedImageUri = mOutputFileUri;
mUploadMessage.onReceiveValue(selectedImageUri);
mUploadMessage = null;
return;
} else {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), intent.getData());
selectedImageUri = intent == null ? null : ImageUtility.savePicture(this, bitmap, 1400);
mUploadMessage.onReceiveValue(selectedImageUri);
mUploadMessage = null;
return;
} catch (IOException e) {
e.printStackTrace();
}
}
// And this is for Android 5.0+ (Lollipop)
} else if (requestCode == INPUT_FILE_REQUEST_CODE) {
Uri[] results = null;
// Check that the response is a good one
if (resultCode == Activity.RESULT_OK) {
if (intent == null) {
// If there is not data, then we may have taken a photo
if (mCameraPhotoPath != null) {
results = new Uri[]{Uri.parse(mCameraPhotoPath)};
}
} else {
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), intent.getData());
} catch (IOException e) {
e.printStackTrace();
}
Uri dataUri = ImageUtility.savePicture(this, bitmap, 1400);
if (dataUri != null) {
results = new Uri[]{dataUri};
}
}
}
mFilePathCallback.onReceiveValue(results);
mFilePathCallback = null;
return;
}
} else {
super.onActivityResult(requestCode, resultCode, intent);
return;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With