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

Android - невозможно открыть контент: файл:///storage/emulated/0

У меня есть виджет с фоном с девятью патчами. Изображение было сохранено в /sdcard/mydir/bgs.

Когда я пытаюсь загрузить изображение с помощью метода setImageViewUri, у меня есть эта ошибка:

Unable to open content: file:///storage/emulated/0/sdcard/mydir/bgs

..

затем

...

open failed: EACCES (Permission denied)

Это отображается только на главном экране и только с Nexus 10 и Nexus 7 (с последней версией 4.4 этой ошибки не существует). У меня также есть RemoteView в моем приложении, и все работает правильно.

Я также добавил в манифест либо READ_EXTERNAL_STORAGE, либо WRITE_EXTERNAL_STORAGE.

Как я могу решить?

UPDATE: я проверяю метод setImageViewUri, и я обнаружил, что он меняет путь к моему файлу.

if (value != null) {
            // Resolve any filesystem path before sending remotely
            value = value.getCanonicalUri();
            if (StrictMode.vmFileUriExposureEnabled()) {
                value.checkFileUriExposed("RemoteViews.setUri()");
            }
        }

Этот метод получает мое значение (/sdcard/mydir/bgs) и изменяет его на (storage/emulated/0/sdcard/mydir/bgs). Но этот файл не существует в системе через adb.

4b9b3361

Ответ 1

Похоже, что setImageViewUri больше не безопасно использовать с файлом://uris.

Почему?

Jellybean представила разрешение READ_EXTERNAL_STORAGE. Приложения, которые хотят читать из внешнего хранилища, должны иметь это разрешение. Это не было применено по умолчанию до KitKat.

Пусковая установка не поддерживает это разрешение. На самом деле вам не гарантируется, что любой RemoteView, который вы прикрепляете, содержит это разрешение. Это делает небезопасным использование setImageViewUri, так как вы не знаете, сможет ли удаленный просмотр изображения даже прочитать данный uri.

Что теперь?

Вариант 1: используйте setImageViewBitmap.

Возможно, вы отказались от этой опции из-за неудачных транзакций связующего. Трюк для них - это просто убедиться, что ваше изображение меньше 1 МБ. Это не так сложно, как кажется. Вы можете точно рассчитать, насколько велика ваша картинка. Например, если вы используете изображение ARGB_8888, это означает, что вам нужно 4 байта на пиксель. Мы можем вычислить максимальный размер:

1 Mb = 1048576 bytes = 262144 pixels = 512 x 512 image

Конечно, вы можете выжать больше из него, используя RGB_565, чтобы получить 2x пикселей.

Также обратите внимание, что вам может не понадобиться огромное изображение, если ваш виджет невелик. Ваш appwidget может задать свои конкретные параметры следующим образом:

Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetIds[i]);

int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);

int maxWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
int maxHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);

Просто имейте в виду, что возвращаемые значения находятся в dip-пикселях, поэтому вам нужно будет их преобразовать, чтобы масштабировать растровое изображение.

Вариант 2. Использование поставщика контента

Если по какой-то причине вам все еще не нравится ограничение IPC, вы всегда можете создать пользовательский контент-провайдер. Передайте этот uri в setImageViewUri, и вам должно быть хорошо идти.

Как насчет переключателя пути?

Переключатель пути не является реальной проблемой. Похоже, что это проблема, но эмуляция работает нормально. Попробуйте создать файл внутри //storage/emulated/0/sdcard/mydir/bgs, и файл будет создан просто отлично.

Вы заметите, что в то время как исключением является исключение FileNotFoundException, это сообщение разрешено.

Ответ 2

Как и в случае с Lollipop, Google представил новый способ явно предоставить приложениям разрешение, которое вы хотите использовать на своем устройстве, и отключить те, которые вы хотите отклонить. Если вы заметили, в вашем мониторе Android журнал показывает

java.io.FileNotFoundException: /storage/emulated/0/advert.mp4: open failed: EACCES (Permission denied)

EACCESS permission denied является причиной java пресловутой FileNotFoundException.

Чтобы решить эту проблему, просто перейдите на свое приложение и включите хранилище для своего приложения.

введите описание изображения здесь

Ответ 3

Вам нужно

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

в вашем манифесте.

Ответ 4

Я думаю, что вы вводите путь к SD-карте вручную. Вместо того, чтобы вручную вводить путь к SD-карте, вы должны получить путь к хранилищу следующим образом:

File extStore = Environment.getExternalStorageDirectory();
String mPath = extStore.getAbsolutePath() + "/mydir/bgs";