Android 11 范围存储权限

新手上路,请多包涵

我的应用程序使用 Environment.getExternalStorageDirectory() 提供的图像文件路径来创建照片相册,但在 Android 11 中我将无法直接访问文件

根据 Android 开发人员文档,他们最近引入了 MANAGE_EXTERNAL_STORAGE 权限,但我不明白添加此权限是否能够继续通过环境访问文件。

我在 Android 11 虚拟设备上尝试了我的应用程序,即使没有请求 MANAGE_EXTERNAL_STORAGE 权限,它似乎也能完美运行!

阅读有关 Android Developers 的文档,似乎使用 File API 访问照片和媒体仅位置的应用程序可以继续工作,但 我不确定

有没有人更了解Android文档???

原文由 Rob B 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

安卓 11

如果您的目标是 Android 11 ( targetSdkVersion 30 ),那么您需要 AndroidManifest.xml 中的以下权限才能进行修改和文档访问。

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

对于 Android 10,您在 AndroidManifest.xml 标记中放置以下行

android:requestLegacyExternalStorage="true"

下面的方法检查权限是被允许还是被拒绝

private boolean checkPermission() {
    if (SDK_INT >= Build.VERSION_CODES.R) {
        return Environment.isExternalStorageManager();
    } else {
        int result = ContextCompat.checkSelfPermission(PermissionActivity.this, READ_EXTERNAL_STORAGE);
        int result1 = ContextCompat.checkSelfPermission(PermissionActivity.this, WRITE_EXTERNAL_STORAGE);
        return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
    }
}

以下方法可用于在 android 11 或更低版本中请求权限

private void requestPermission() {
    if (SDK_INT >= Build.VERSION_CODES.R) {
        try {
            Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
            intent.addCategory("android.intent.category.DEFAULT");
            intent.setData(Uri.parse(String.format("package:%s",getApplicationContext().getPackageName())));
            startActivityForResult(intent, 2296);
        } catch (Exception e) {
            Intent intent = new Intent();
            intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
            startActivityForResult(intent, 2296);
        }
    } else {
        //below android 11
        ActivityCompat.requestPermissions(PermissionActivity.this, new String[]{WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
    }
}

Android 11及以上版本权限回调处理

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 2296) {
        if (SDK_INT >= Build.VERSION_CODES.R) {
            if (Environment.isExternalStorageManager()) {
                // perform action when allow permission success
            } else {
                Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

处理 Android 11 以下操作系统版本的权限回调

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            if (grantResults.length > 0) {
                boolean READ_EXTERNAL_STORAGE = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                boolean WRITE_EXTERNAL_STORAGE = grantResults[1] == PackageManager.PERMISSION_GRANTED;

                if (READ_EXTERNAL_STORAGE && WRITE_EXTERNAL_STORAGE) {
                    // perform action when allow permission success
                } else {
                    Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
                }
            }
            break;
    }
}

注意: MANAGE_EXTERNAL_STORAGE 是一种特殊权限,仅允许少数应用程序,如防病毒、文件管理器等。您必须在将应用程序发布到 PlayStore 时说明原因。

原文由 Thoriya Prahalad 发布,翻译遵循 CC BY-SA 4.0 许可协议

private fun loadFilesFromSharedStorage() {
    try {
        val projection = arrayOf(
            MediaStore.MediaColumns._ID,
            MediaStore.MediaColumns.DISPLAY_NAME
        )
        val selection = when (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
            true -> "${MediaStore.MediaColumns.RELATIVE_PATH} LIKE ?"
            else -> MediaStore.Images.Media.DATA + " like ? "
        }
        val selectionArgs = arrayOf("%test%")
        val uriExternal = MediaStore.Files.getContentUri("external")
        contentResolver.query(
            uriExternal,
            projection,
            selection,
            selectionArgs,
            null
        )?.use {
            val idColumn = it.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)
            while (it.moveToNext()) {
                try {
                    val contentUri: Uri = ContentUris.withAppendedId(
                        uriExternal,
                        it.getLong(idColumn)
                    ) /*Use this URI for next*/
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }

}

Android11中使用block获取文件Shared Storage并使用

原文由 Yasir Tanveer 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题