Android 11作用域存储权限

117

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

根据Android开发者文档,他们最近引入了MANAGE_EXTERNAL_STORAGE权限,但我不确定添加此权限是否能够继续通过Environment访问文件。

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

根据Android Developers的文档,似乎仅使用File API访问照片和媒体库位置的应用程序仍然可以继续工作,但是我不确定

是否有人更好地理解了Android文档?


2
@blackapps 目前还没有 Android 11 的模拟器或手机。 - Numan Karaaslan
1
哦,是的。已经有几个月了。Android Studio为所有Pixel模拟器提供了此功能。更新您的SDK。在Android 11上,默认情况下再次可以访问外部存储。 - blackapps
小心:它在模拟器上可以运行,但在实际设备上可能会出问题!非常危险。 - Violet Giraffe
请查看以下链接:https://stackoverflow.com/a/66534787/3904109,https://dev59.com/ZbXna4cB1Zd3GeqPEAqF#62601219和https://dev59.com/LFMI5IYBdhLWcg3wFXWg#57116787,不要使用管理外部存储权限。 - DragonFire
16个回答

0
我也寻找了几个小时的解决方案并尝试了一些方法。在我的应用程序中,用户可以发送带有PDF文档附件的电子邮件,但自从Android 11权限更改后,附件为空。为了获取文件,我使用了FileProvider。我在这里和其他线程中找到的建议方法都没有起作用,直到我自己测试并偶然地像Monu Meena一样在我的Android清单文件中添加了以下内容:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />

在我的情况下,这是唯一可行的解决方案。我没有删除读或写权限,也没有将目标SDK设置为29或更低,我的目标SDK仍然是30,并且它也适用于API低于30的设备。我已经在Android Studio模拟器上成功地测试了几个具有不同API版本的设备。

所以试着去尝试一下吧,有时候最简单的解决方案就是最好的。


1
谷歌强烈限制此权限的使用,因此如果您想在Play商店上架应用程序,这很可能会使您的应用程序被标记:https://support.google.com/googleplay/android-developer/answer/10467955?hl=en - Al Ro

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共享存储中的文件并使用它。

2
Android是多么的混乱无序啊。 - Richard Hammond

0
在我的情况下,我只需要创建一个 .csv 文件,然后将其发送到服务器,我遵循了这个文档。 此文档。
 File folder  = new File(getBaseContext().getFilesDir(), "/test/CSV");
 filepath = folder.toString() + "/" + id + ".csv";

0

在文件位置(无论您在哪里使用它)使用

mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);

替代

Environment.getExternalStorageDirectory();

在权限中使用(请参见注释中的权限)

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            // return Environment.isExternalStorageManager();
            return true;
        }

0

在Android 11+上访问非媒体文件

在Android 11+上,只有当以下条件满足时,才能访问非媒体文件(如txt、pdf、csv等):

文本文件位于→ ASD目录或→ Private目录(即保存在这些目录中),或者 文本文件位于共享文件夹/Documents或/Download之一,并且这些文件是应用程序自己创建的,或者 使用了SAF(Storage Access Framework),或者 请求并获得了MANAGE_EXTERNAL_STORAGE*权限。 *这实际上不是一个选项,因为请求此权限的应用程序(很可能)不会被允许在Google Play商店中。

注意:当然,可以读取assets中的所有文件。但是这些文件是只读的。

在Android 11+上访问媒体文件

没有READ权限的情况下,只有当以下条件满足时,才能读取媒体文件(如jpg、png、mp3、mp4等):

这些文件位于其中一个共享文件夹(/Pictures,/DCIM,/Documents,/Download,/Music,/Movies)中,并且是由应用程序本身创建的,或者 这些文件位于ASD中,或者 这些文件位于私有目录中。 具有读取权限的情况下,所有媒体文件都可以从外部存储的所有区域读取(包括根目录)。 没有写入权限的情况下,媒体文件只能保存在Android 11+上,如果且仅当: 这些文件存储在ASD中,或者 这些文件存储在私有目录中,或者 这些文件存储在其中一个共享文件夹中。 私有目录位于内部存储中:
/data/user/0//files/ 注意:由于Android 11+上不再存在WRITE_EXTERNAL_STORAGE权限,没有MANAGE_EXTERNAL_STORAGE权限,就无法在ASD、私有目录或共享文件夹之外保存文件。或者您必须使用SAF。

-3

简单来说,我们只需要启用以下权限:

$<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />

然后我们就可以使用旧代码执行任何操作了。


4
如果您想让这个应用被Google Play Store接受,那么在提交时可能会遇到一些问题,所以这只是部分解决方案。请参考https://support.google.com/googleplay/android-developer/answer/10467955?hl=en。 - Al Ro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接