Android 10 MediaStore 文件权限

问题描述

我仅在 Android 10 中遇到图像权限问题。我声明该问题仅适用于 android 10,实际上在 android 11 和 android 9 及更早版本中启用了写入和读取权限。
如文档所述,在清单中我有 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxsdkVersion="28"/> 和应用程序 android:requestLegacyExternalStorage="true"
我的编译版本是 30,目标是 30。即使将目标版本恢复到 29,我也得到了相同的结果。
通过意图插入文件

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
      photoUri = activity.getContentResolver().insert(
          MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL),contentValues
      );
    else
      photoUri = activity.getContentResolver().insert(
         MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues
      );

    final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT,photoUri);
    activity.startActivityForResult(intent,REQUEST_CAMERA_KEY);

取而代之的是这样的:

@Override
  protected void onActivityResult(int requestCode,int resultCode,Intent data) {
super.onActivityResult(requestCode,resultCode,data);
if (requestCode != REQUEST_CAMERA_KEY || resultCode != RESULT_OK)
      return;
    // use imagedecoder.decodeBitmap >= Build.VERSION_CODES.P
    final Bitmap bitmap =BitmapProvider.getBitmap(contentResolver,photoUri);
    Cursor cursor = contentResolver.query(photoUri,null,null);
    String value = null;
    if (cursor == null) {
      value = photoUri.getPath();
    } else {
      cursor.movetoFirst();
      int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
      value = cursor.getString(idx);
    }
    cursor.close();
    File file = new File(value);
    // Android 9 and < true true
    // Android 10 false false
    // Android 11  true true
    System.out.println(file.canRead() + " " + file.canWrite());
    try {
      final FileOutputStream fileOutputStream = new FileOutputStream(file); // Android 10 generate open Failed: EACCES (Permission denied) exception
      bitmap.compress(Bitmap.CompressFormat.JPEG,90,fileOutputStream);
    } catch (FileNotFoundException e) {
      e.printstacktrace();
    }
}

获取位图:

public Bitmap getBitmap(
      final ContentResolver contentResolver,final Uri photoUri){
    Bitmap bitmap = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
      final imagedecoder.source source = imagedecoder.createSource(contentResolver,photoUri);
      try {
        bitmap = imagedecoder.decodeBitmap(source);
      } catch (IOException e) {
        e.printstacktrace();
      }
    } else {
      InputStream inputStream = null;
      try {
        inputStream = contentResolver.openInputStream(photoUri);
        bitmap = BitmapFactory.decodeStream(inputStream);
      } catch (FileNotFoundException e) {
        e.printstacktrace();
      } finally {
        if (inputStream != null) {
          try {
            inputStream.close();
          } catch (IOException e) {
            e.printstacktrace();
          }
        }
      }
    }
    return bitmap;
  }

尽管遵循了文档,但我仍需要对此进行解释,也许还需要解释。谢谢。

解决方法

如果您请求旧存储,则还必须获得存储许可: android:requestLegacyExternalStorage="true"
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

如果您面向 API 30 requestLegacyExternalStorage 不起作用。您需要将目标 SDK 设置为 29 或使用媒体存储 API。