Android KitKat securityException при попытке чтения из MediaStore

java.lang.SecurityException: Permission Denial: открытие провайдера com.android.providers.media.MediaDocumentsProvider из ProcessRecord {430b1748 29271: com.xxx/u0a88} (pid = 29271, uid = 10088) требует андроида.permission.MANAGE_DOCUMENTS или андроида. permission.MANAGE_DOCUMENTS

Я добавил разрешения MANAGE_DOCUMENTS и READ_EXTERNAL_STORAGE но я все еще получаю эту ошибку. Код нарушения:

  public static String getImagePath(HailoDriverApplication app, Uri uri) { Cursor cursor = null; if (uri == null) { return null; } try { cursor = app.getContentResolver().query(uri, new String[] { MediaStore.Images.Media.DATA }, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); if (cursor.moveToFirst()) { return cursor.getString(column_index); } } finally { if (cursor != null) { cursor.close(); } } return null; } 

В качестве запроса fragmentа манифеста:

                          

Была та же проблема за последние пару дней. Попробовал несколько решений, но почему-то я получал отказ от разрешения на контент провайдера Uri для некоторых изображений, даже когда у меня появилось разрешение android.permission.MANAGE_DOCUMENTS, добавленное в мой манифест.

Вот обходной путь, пока:

 i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, CHOOSE_IMAGE); 

Это заставляет более старую галерею изображений открываться вместо нового представления документов Kitkat.

Теперь вы можете получить Uri, вызвав следующее в вашем onActivityResult:

 Uri selectedImageURI = data.getData(); 

Надеюсь это поможет.

В намерении, используемом для запроса пользователю добавить файл, используйте Intent.ACTION_OPEN_DOCUMENT (в KitKat API 19 или выше) вместо Intent.ACTION_GET_CONTENT или Intent.ACTION_PICK. Затем, когда вы хотите использовать Uri, возьмите предыдущие постоянные разрешения, которые были установлены Intent.ACTION_OPEN_DOCUMENT, как описано в ссылке @ feri ( https://developer.android.com/guide/topics/providers/document-provider.html #permissions ):

 final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // Check for the freshest data. getContentResolver().takePersistableUriPermission(originalUri, takeFlags); 

Вы можете больше узнать о различиях между Intent.ACTION_GET_CONTENT, Intent.ACTION_PICK и Intent.ACTION_OPEN_DOCUMENT здесь: http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT

Хорошо, я нашел рабочий образец, который выходит из проблемы:

  intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); startActivityForResult(intent, myClassConstant.SELECT_PICTURE); 

Вот что я узнал … это изменение в KitKat, и этот код работает только с API 19 и выше. Он не будет работать для более старых версий, поэтому вам также необходимо иметь методы для pre-KitKat. После того, как вы получите файл, используя аргумент Category_Openable, в моем случае это изображение, вы можете использовать его, указав его как URI. В моем случае я сохраняю URIString (путь к файлу), и я могу делать то, что хочу с ним после открытия.

Проблема, которую я сейчас пытаюсь выяснить, заключается в том, как долго сохраняются права доступа к файлам. Похоже, что он истек со вчерашнего дня, так как мой код ищет UriString, а затем пытается открыть файл. Если я использую код выше, чтобы выбрать изображение, он работает – он сохраняет имя, и мне удалось выйти из программы, вернуться и все еще работать … однако, мой первый запуск программы этим утром (после не касаясь его через 12 часов), он действовал так, как будто он не мог найти файл (и я уверен, что если смотреть через отладчик, я увижу, что некритическая ошибка появляется снова.

Итак, теперь возникает вопрос: как мы сохраняем права доступа, как только я узнаю, что такое файл (имя)?

Я предполагаю, что Uri вы хотите показать ссылки на изображение от поставщика, который реализует новую платформу доступа к хранилищу, представленную в Android 4.4 KitKat. Это может быть Галерея, а также Google-Drive. Единственный способ доступа к этим документам, похоже, состоит в использовании системного файла. Если пользователь выбирает файлы для открытия, система предоставляет разрешение на приложение, которое запустило диалог открытия файла. Эти разрешения действительны, пока устройство не перезагружается. Нельзя получить доступ к другим изображениям и привести к исключению безопасности.

Если Ури сохранится, то права, предоставленные для доступа к Ури, также должны сохраняться. Для получения дополнительной информации смотрите здесь: https://developer.android.com/guide/topics/providers/document-provider.html#permissions

Разрешение MANAGE_DOCUMENTS может выполняться только системой:

Разрешение MANAGE_DOCUMENTS. По умолчанию поставщик доступен всем. Добавление этого разрешения ограничивает ваш провайдер системой. Это ограничение важно для безопасности.

(взято из Storage Access Framework )

Таким образом, используя это разрешение в вашем DocumentProvider вы ограничиваете доступ к своему провайдеру только системе. Это означает, что только System UI picker будет иметь доступ к вашим файлам. Поэтому для того, чтобы приложение могло выбрать файл у вашего Provider ему нужно будет запустить Intent с ACTION_OPEN_DOCUMENT , который фактически запустит System UI picker , пользователь выберет из него файл, а затем URI будет возвращен вы.

Похоже, что решение использует http://developer.android.com/guide/topics/providers/document-provider.html#client вместо доступа к изображениям из галереи

Я не уверен, почему другой подход не работает. Но на данный момент это надолго.

Давайте будем гением компьютера.