Gallery picker returns Uri with a file scheme on Android 10、如何读取它?

Gallery picker returns Uri with a file scheme on Android 10, how to read it?

我的应用有 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)

还尝试在意图中添加 CATEGORY_OPENABLE。 None 这些作品。

因此,当我发送意图从图库中挑选图像时,一些来自游戏市场的应用 return 给我一个带有文件方案的 Uri,例如:file:///storage/emulated/0/Download/sample.jpg

当我尝试将其转换为位图(用于设置到 imageView)时,出现 EACCES(权限被拒绝)异常。

我试着用:

阅读它
java.File Api

contentResolver.openInpuStream()

contentResolver.openFileDescriptor()

ImageDecoder

没有任何帮助。如我所见,如果清单中未启用 requestlegacyexternalstorage 标志,我无法使用 android 10(目标 29 sdk)上的文件方案读取 Uri。

如果我错了,请帮我看看怎么读。

关于它的神秘之处,android 11 模拟器与应用程序目标 29 sdk 可以读取这些类型的 Uri 而无需 requestlegacyexternalstorage 标志。

是的,我已经授予 READ/WRITE_EXTERNAL_STORAGE 权限。

some apps from play market return me a Uri with a file scheme, for example: file:///storage/emulated/0/Download/sample.jpg

有些应用是由经验不足的开发人员编写的。

If i am wrong, please help me to figure out how to read it.

在 Android 10,如果没有 android:requestLegacyExternalStorage="true",您将无法阅读 Uri

Mysterious thing about it, that android 11 emulator with app targeting 29 sdk CAN read these type of Uri without requestlegacyexternalstorage flag.

Android11 中引入的“原始路径”功能意味着 READ_EXTERNAL_STORAGE 再次正常工作。因此,推荐的方法是请求 READ_EXTERNAL_STORAGE 加上 使用 android:requestLegacyExternalStorage="true",以确保 Android 版本之间的一致性。

这非常适合我(我已经在 Android 8、10、11 上针对 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));
                    
}