Средство выбора галереи возвращает Uri со схемой файлов на Android 10, как его прочитать?

#android #kotlin #android-contentresolver #android-10.0 #android-external-storage

#Android #kotlin #android-contentresolver #android-10.0 #android-external-storage

Вопрос:

В моем приложении targetSdkVersion = 29 (новая политика хранения с ограниченной областью действия) и в манифесте не включен флаг requestlegacyexternalstorage (я не хочу его включать).

Способы, которыми я пытался составить намерение:

 Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE);
  

Также пробовал это

 val galleryIntent = Intent(Intent.ACTION_PICK).apply {
    type = PICK_INTENT_TYPE
}
flowInterruptBlocker?.blockFlowInterruption()
startActivityForResult(galleryIntent, GALLERY_INTENT_REQUEST_CODE)
  

Также пытался добавить a CATEGORY_OPENABLE в intent. Ни одна из этих работ.

Итак, когда я отправляю намерение выбрать изображение из галереи, некоторые приложения из play Market возвращают мне Uri с файловой схемой, например: file:///storage/emulated/0/Download/sample.jpg

Когда я пытаюсь преобразовать его в растровое изображение (для настройки в ImageView), я получаю исключение EACCES (отказано в разрешении).

Я попытался прочитать его с помощью:

 java.File Api

contentResolver.openInpuStream()

contentResolver.openFileDescriptor()

ImageDecoder
  

Ничего не помогает. Как я вижу, я не могу прочитать Uri с файловой схемой на Android 10 (нацеленный на 29 sdk) без флага requestlegacyexternalstorage, включенного в моем манифесте.

Если я ошибаюсь, пожалуйста, помогите мне разобраться, как это прочитать.

Загадочная вещь в том, что эмулятор Android 11 с приложением, ориентированным на 29 sdk, МОЖЕТ считывать Uri такого типа без флага requestlegacyexternalstorage.

И да, я предоставил разрешения на ЧТЕНИЕ / ЗАПИСЬ в EXTERNAL_STORAGE.

Комментарии:

1. Пожалуйста, начните свой пост с блока кода, в котором используется код для используемого намерения.

2. file:///storage/emulated/.../image.jpeg Пожалуйста, укажите полный путь.

3. s i can see i can not read Uri with a file scheme on android 10 Да, вы можете, но это зависит от полного пути. Вот почему я спросил,

4. Действительно: Android 11 менее строгий. Тогда у вас будет большой доступ. Google сделал шаг назад.

5. Такие приложения из play marked используют что-то вроде getRealPathFromUr() или являются старыми приложениями для просмотра файлов.. В основном эта функция недоступна на Android 10, но, по-видимому, они запросили разрешение на устаревшее хранилище или придумали какой-то код для определения пути к файлу. К сожалению, не используется на Android 10. Виноваты авторы этих приложений. (Вы можете отправить их по почте). Пожалуйста, назовите их!

Ответ №1:

некоторые приложения из play Market возвращают мне Uri со схемой файлов, например: file:///storage/emulated/0/Download/sample.jpg

Некоторые приложения написаны неопытными разработчиками.

Если я ошибаюсь, пожалуйста, помогите мне разобраться, как это прочитать.

На Android 10 вы не сможете прочитать это Uri без android:requestLegacyExternalStorage="true" .

Загадочная вещь в том, что эмулятор Android 11 с приложением, ориентированным на 29 sdk, МОЖЕТ считывать Uri такого типа без флага requestlegacyexternalstorage.

Функция «необработанные пути», представленная в Android 11, означает, что READ_EXTERNAL_STORAGE она снова работает нормально. Итак, рекомендуемый подход — запросить READ_EXTERNAL_STORAGE plus use android:requestLegacyExternalStorage="true" для согласованности между версиями Android.

Ответ №2:

Это отлично работает для меня (я тестировал его на Android 8, 10, 11 с targeting sdk 29). Не требует android:requestLegacyExternalStorage="true" и каких-либо разрешений.

 private static Bitmap readImage(Uri uri, Context context){
   InputStream inputStream = context.getContentResolver().openInputStream(uri);
   Bitmap res = BitmapFactory.decodeStream(inputStream);
   inputStream.close();
   return res;
}
  

и вы используете его так:

 @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
       
    if(data == null || data.getClipData().size() == 0)
       return;

    myImageView.setImageBitmap(readImage(data.getClipData().getItemAt(0).getUri(), this));
                    
}