Подтвердить что ты не робот

Невозможно загрузить изображение при выборе из галереи на 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 еще не обновлен, чтобы разместить его для этого.

4b9b3361

Ответ 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.