Невозможно загрузить изображение при выборе из галереи на Android 4.4 (KitKat) с помощью PhoneGap Camera Plugin
Я пытаюсь установить источник тега img в своем приложении на основе изображения, выбранного из галереи изображений устройства, используя плагин камеры PhoneGap/Cordova.
Он работал ранее, как предполагалось, в более старых версиях Android (3.3) и отлично работает на iOS, но теперь не удается разрешить путь изображения в 4.4 (KitKat).
Возвращаемый путь для возвращаемого URL-адреса изображения выглядит примерно так:
content://com.android.providers.media.documents/document/image%3A352
Когда я использую этот путь для установки в качестве изображения src через JavaScript, URL-адрес не может быть разрешен и, следовательно, создает ошибку загрузки. При съемке с камерой нет проблем, похоже, что это происходит при выборе существующего изображения из галереи.
Я попытался кодировать base64, а также попробовал метод, упомянутый в документах resolveLocalFileSystemURI();
, но мне не повезло с ними. Я также попытался удалить плагин камеры и восстановить приложение, но не радость.
Я предполагаю, что что-то изменилось с тем, как KitKat обрабатывает галерею, а плагин PhoneGap/Camera еще не обновлен, чтобы разместить его для этого.
Ответы
Ответ 1
Что-то сломалось в Android 4.4 с кодировкой URI изображений.
В Кордове была подана ошибка: https://issues.apache.org/jira/browse/CB-5398
В документах для getPicture в разделе "Быстрый поиск Android" обсуждается эта проблема и указывает на вопрос StackOverflow с обходным решением (отредактируйте плагин java камеры чтобы заставить его открывать приложение Gallery вместо приложения Storage Access Framework.)
Кажется, еще одна вещь, которую вы могли бы сделать, - установить тип назначения DATA_URL.
Ответ 2
Для меня эта проблема очень похожа на очень грязную обходную проблему. Используйте в случае крайней необходимости:)
if (imageURI.substring(0,21)=="content://com.android") {
photo_split=imageURI.split("%3A");
imageURI="content://media/external/images/media/"+photo_split[1];
}
Ответ 3
Adobe уверяет меня, что эта проблема будет исправлена в версии 3.5.0. Это не зафиксировано в 3.4. Поскольку 3.5.0 планируется выпустить в середине мая, я просто буду ждать до тех пор.
Adobe утверждает, что это не было изменение, которое может быть сделано на уровне плагина. Это было принципиальное изменение в коде кордовы. Слишком плохо, что им потребовалось столько времени, чтобы они придумали это исправление.
UPDATE: Кордова 3.5.0 была выпущена 9 мая. Вы можете скачать ее bia node и посмотреть, действительно ли проблемы решены.
Ответ 4
Вот простое решение этой проблемы:
замените это:
content://com.android.providers.media.documents/document/image%3A352
:
content://com.android.providers.media.documents/document/image%253A352
если вы используете JavaScript, вы можете использовать этот код:
var path = content://com.android.providers.media.documents/document/image%3A352;
path = path.replace("%", "%25");
этот метод заставляет uri пропускать "% 3A" как есть, не меняя его на ":", надеюсь, что он сработает для вас!
Ответ 5
Не намного надежнее всего несколько проверок для особых условий, таких как "контент:" без расширений и т.д. Кроме того, поскольку мне нужно загрузить его, я обнаруживаю расширение или создаю расширение .jpg, если файл не имеет одного:
// Android 4.4 cordova workarounds ... returns new kind or URL for content from chooser
//if (imageUrl.substring(0,21)=="content://com.android") {
if(imageUrl.indexOf('content://') != -1 && imageUrl.indexOf("%3A") != -1){
//"PlainFileUrl = content://com.android.providers.media.documents/document/image%3A14",
photo_split=imageUrl.split("%3A");
imageUrl="content://media/external/images/media/"+photo_split[1];
}
// workaround end
var fileName = imageUrl.substr(imageUrl.lastIndexOf('/') + 1);
var extension;
// check for content: protocol to make sure is not
// a file with no extension
if (imageUrl.indexOf('content://') != -1) {
if(imageUrl.lastIndexOf('.') > imageUrl.lastIndexOf('/')){
extension = imageUrl.substr(imageUrl.lastIndexOf('.') + 1);
}else{
extension = "jpg";
fileName = fileName + ".jpg";
LogService.log("Created File Extension jpg");
}
} else {
if (imageUrl.lastIndexOf('.') == -1 || (imageUrl.lastIndexOf('.') < imageUrl.lastIndexOf('/')) ) {
extension = "invalid";
} else {
extension = imageUrl.substr(imageUrl.lastIndexOf('.') + 1);
}
}
Ответ 6
Всякий раз, когда часть uri
передается в <img src="uri" />
, она неявно декодируется из
content://com.android.providers.media.documents/document/image%3A9888 (1)
в
content://com.android.providers.media.documents/document/image: 9888 (2)
Однако после возврата из Intent.ACTION_OPEN_DOCUMENT
или Intent.ACTION_GET_CONTENT
Android предоставляет вам разрешение на чтение для (1), а не (2). В этом случае WebView
будет выжидать с ошибкой:
java.lang.SecurityException: отказ в разрешении: чтение com.android.providers.media.MediaDocumentsProvider uri Содержание://com.android.providers.media.documents/document/image: 9888 от pid = 13163, uid = 10165 требует android.permission.MANAGE_DOCUMENTS или grantUriPermission()
или
Не удалось открыть URL-адрес контента
Фрагмент кода
Все, что вам нужно для решения проблемы,
String uriToUseInWebView = transformForWebView(uri.toString());
private String transformForWebView(String uri) {
for (int i = 0; i < timesDecodingWebView(); i++)
uri = uri.replace("%", Uri.encode("%"));
return uri;
}
private int timesDecodingWebView() {
if (Build.VERSION.RELEASE.equals("4.4.2")) {
return 2;
} else {
return 1;
}
}
в вашем Java-коде перед передачей uri
в HTML/JS, чтобы обеспечить загрузку (1).
Я тестировал это на 4.4.2, 4.4.4 и 5.0. Самое забавное, что Android 4.4.2 дважды декодирует uri
.