Android 4.4 WebView файл chooser не открывается?
мы создаем приложение, которое использует webview и получит доступ к странице, где пользователю необходимо загрузить файл. Мы испытываем проблемы с Android 4.4, где выбор файла не открывается, и нажатие кнопки загрузки ничего не происходит. Эта функция работает с более ранними версиями с помощью метода openFileChooser следующим образом:
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);
}
});
Я потратил много времени на поиск способа сделать это на 4.4, но не повезло. Кому-нибудь удалось это сделать это?
8 ответов
WebView работает по назначению
Если я правильно понимаю, что говорит приведенная выше ссылка, вы (я и, вероятно, еще несколько сотен разработчиков) ищете Хак
этот код работал для меня.
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;
}
}
я тоже работал над этим вопросом, и проблема, и вот мое решение
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;
}
}
одна проблема, которую я решил, - это uri, поставляемый для onActivityResult()
метод не имеет расширения. Чтобы решить эту проблему, я использую этот метод
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;
}
наконец, onActivityResult()
метод
@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;
}
}
посмотреть этой. Поскольку api 19 4.4, webview был перенесен для использования Chromium, а не WebChromeClient больше.
нашел решение, которое работает для меня. Я добавил еще одно правило в proguard-android.txt
:
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void openFileChooser(...);
}
Что я сделал, чтобы исправить эту проблему, это реализовать пешеходный переход в мой проект. Я знаю, что размер пешеходного перехода значителен (добавляет хром в ваш проект), но мне действительно нужно было это, чтобы хорошо работать внутри родного приложения. Я задокументировал, как я реализовал это здесь: http://maurizionapoleoni.de/blog/implementing-a-file-input-with-camera-support-in-android-with-crosswalk/
вам нужно реализовать WebviewClient
класса. Вы можете проверить эти пример .
webview.setWebViewClient(new myWebClient());
The web.setWebChromeClient(new WebChromeClient() {
//
}
создайте класс mywebClient и добавьте следующий код для реализации ,
Я попробовал Выбрать файл в webview, используя последнюю версию Android 4.4.3, и он работает нормально. Я думаю, Google исправил проблему.