这篇文章,想来发布的有些晚了,安卓11已经发布多时了,关于安卓11上的存储权限变更的文章数不胜数,所以这篇文章只做为自己的一个简单的记录吧!

在说11之前,我们先回忆以下10上存储权限的变更:每个应用会生成自己对应的沙盒文件路径,自己的应用只能访问自己的文件路径,以及系统提供的公共资源文件夹,而无法访问其它文件夹!

在当targetApi=29时,你有两种选择:

1.适配安卓10的权限变化,判断手机系统版本号,>=29的使用自己的沙盒路径,<29的还按原来的路径(sd卡根目录下自己创建的文件夹路径);

2.不适配安卓10,不修改代码的方式兼容安卓10,有两种方法:
(1)targetApi<29;
(2)targetApi=29,AndroidManifest.xml中的application加入属性:

android:requestLegacyExternalStorage="true"

安卓10上,自己的沙盒路径不需要申请存储权限就可以访问,但如果你的应用内有类似文件管理器(需要访问其它文件夹的能力)的功能时,就仍然要申请存储权限:

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

安卓11上的存储权限变更,进一步收紧对设备上的文件访问权限,如果你的targetApi>29,那么你之前设置的android:requestLegacyExternalStorage="true"将无效,此时你必须适配自安卓10上的权限变更。

并且在安卓11上,即便你申请了READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE,你仍然是无法访问其它文件夹的,那么类似文件管理器的功能将全部失效,那如果应用所需的功能必须要浏览sd卡内的文件就没有任何办法了吗?

有! 谷歌在安卓11上增加了一个权限MANAGE_EXTERNAL_STORAGE:

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>

但如果你这么写,会有一个警告:

Android SD卡读写权限 android11 sd卡权限_android

意思是,你需要添加一个属性:tools:ignore=“ScopedStorage”,忽略ScopedStorage,其实谷歌的本意是安卓10以后,必须要适配ScopedStorage的,11以后进一步限制你对不属于自己应用的文件夹的访问权限的,但你一定要访问,那你就忽略以下我这个强制适配的属性吧,说直白点就是,非必要不申请(非必要,不xx,听着就可怕)!

但MANAGE_EXTERNAL_STORAGE不会像存储权限一样,只要你申请就会弹权限申请框,用户可以方便的选择同意或拒绝!MANAGE_EXTERNAL_STORAGE权限申请不会弹框,在你申请之前,你需要先判断用户是否已经开启了MANAGE_EXTERNAL_STORAGE权限:

Environment.isExternalStorageManager()

已开启则已,未开启时,先用代码申请MANAGE_EXTERNAL_STORAGE权限,申请后会跳转到系统一个单独的页面让用户开启:

Android SD卡读写权限 android11 sd卡权限_Android SD卡读写权限_02

用户如果拒绝,则可以通过intent的action:Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION,跳转至权限授予页请求用户同意!

当然,如果已经开启了MANAGE_EXTERNAL_STORAGE权限,你想访问所有文件,依然要申请READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE。

当targetApi>29时,未添加MANAGE_EXTERNAL_STORAGE权限时,权限设置页是这样的:

Android SD卡读写权限 android11 sd卡权限_存储权限_03

当targetApi>29时,添加了MANAGE_EXTERNAL_STORAGE权限时,权限设置页是这样的:

Android SD卡读写权限 android11 sd卡权限_Android SD卡读写权限_04

这就是MANAGE_EXTERNAL_STORAGE的作用,当用户授予了“所有文件”的权限时,你就可以随意访问其它文件夹了!当然,用户不给这个权限,那就没有办法了…