Android 11及以上授予文件管理权限

Android 11及以上授予文件管理权限

背景

安卓11改变了此前安卓系统对于文件管理的规则,在安卓11上,文件读写变成了特殊权限。应用默认只能读写自己的目录/android/data/包名

gradle配置

Android11系统对应用写入权限做了严格的限制。本文介绍如何获取文件读写权限。

项目中 build.gradle 的targetSdkVersion >= 29 ,会出现读写问题

当targetSdkVersion = 29,通过设置requestLegacyExternalStorage=“true”,还能解决

当targetSdkVersion = 30后,需要申请所有文件权限才能获取到写入权限

为了能直接usb安装,gradle.properties 需要设置(否则,在安装时会报异常:-15)

android.injected.testOnly=false

AndroidManifest添加权限设置

tools:ignore="ScopedStorage" />

...

android:requestLegacyExternalStorage="true"

...

>

...

语法说明

申请权限,主要用到如下4个函数

检查权限

int checkSelfPermission(String)

申请权限

void requestPermissions(int, String...)

是否应该显示请求权限的说明

boolean shouldShowRequestPermissionRationale(String)

处理权限结果回调

void onRequestPermissionsResult(int,String[],int[])

上述四个方法中,前三个方法在support-v4的ActivityCompat中都有,建议使用兼容库中的方法。最后一个方法是用户授权或者拒绝某个权限组时系统会回调Activity或者Fragment中的方法。

checkSelfPermission的返回值有如下两种

已拒绝 PackageManager.PERMISSION_DENIED

已授权 PackageManager.PERMISSION_GRANTED

动态权限申请

Android 6.0之上Android11以下申请权限

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// 6.0

String[] perms = {

Manifest.permission.READ_EXTERNAL_STORAGE,

Manifest.permission.WRITE_EXTERNAL_STORAGE,

Manifest.permission.READ_PHONE_STATE};

for (String p : perms) {

int ret = ContextCompat.checkSelfPermission(activity, p);

if (ret != PackageManager.PERMISSION_GRANTED) {

//TODO 跳转到权限页,请求权限

return;

}

}

}

Android11申请权限

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

//判断是否有管理外部存储的权限

if (!Environment.isExternalStorageManager()) {

//TODO 跳转到权限页,请求权限

}

}

跳转系统授权页面

跳转到“应用信息”页面

安卓默认只能跳转到 "应用信息"页面,但是国内手机厂商大多支持各自自定义的Intent,直接跳到应用程序权限页面

/**

* 当前应用详情页面(在该页面单击权限,进入的是权限组页面)

*/

public static void goAppDetailsSettings(Context context) {

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

intent.setData(Uri.fromParts("package", context.getPackageName(), null));

context.startActivity(intent);

}

跳转到应用信息页面,页面包含如下内容

存储

电量

流量

通知

权限

默认打开

需要手动点击“权限”按钮,进入“应用权限”页面,然后开始设置相应的数据

跳转到“所有文件访问权限”

谷歌官方的安卓11在“应用权限”页面隐藏了对“存储”权限的设置(当然,很多国产机,即使到了安卓12,依旧支持原先的存储权限;但也存在部分不支持的,比如:OPPO Reno9 Pro+)

取而代之的是“所有文件访问权限”页面,该页面用来授予“所有文件的管理权限”,允许此应用读取、修改和删除此设备或任意已连接存储卷上的所有文件。如果您授予该权限,应用无需明确通知您即可访问文件

/**

* 进入Android 11或更高版本的文件访问权限页面

*/

private void goManagerFileAccess(AppCompatActivity activity) {

// Android 11 (Api 30)或更高版本的写文件权限需要特殊申请,需要动态申请管理所有文件的权限

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

Intent appIntent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);

appIntent.setData(Uri.parse("package:" + getPackageName()));

//appIntent.setData(Uri.fromParts("package", activity.getPackageName(), null));

try {

activity.startActivity(appIntent);

} catch (ActivityNotFoundException ex) {

ex.printStackTrace();

Intent allFileIntent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);

activity.startActivity(allFileIntent);

}

}

}

这里面涉及到两个Settings

当前应用的文件访问权限:ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION

所有需要文件访问权限的应用:ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION

切记,不要在安卓11以下调用该Intent,会导致闪退

测试存储权限是否授权

安卓11及以后,有如下几个函数判断是否赋予存储权限

老版读权限

ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED

老版写权限

ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED

安卓11新出的管理外置存储权限

ActivityCompat.checkSelfPermission(context, Manifest.permission.MANAGE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED

安卓11新出的判断是否是外置存储管理器

Environment.isExternalStorageManager()

具体实验(VIVO Y77,安卓12)

初始化状态

isExternalStorageManager => false

READ_EXTERNAL_STORAGE => false

READ_EXTERNAL_STORAGE => false

MANAGE_EXTERNAL_STORAGE => false

仅在“应用权限”页面,打开存储权限中的“允许管理所有文件”

isExternalStorageManager => true

READ_EXTERNAL_STORAGE => true

WRITE_EXTERNAL_STORAGE => true

MANAGE_EXTERNAL_STORAGE => false

仅在“应用权限”页面,打开存储权限中的“仅允许访问媒体文件”

isExternalStorageManager => false

READ_EXTERNAL_STORAGE => true

WRITE_EXTERNAL_STORAGE => true

MANAGE_EXTERNAL_STORAGE => false

仅在“所有文件访问权限”页面,授予权限

isExternalStorageManager => true

READ_EXTERNAL_STORAGE => false

WRITE_EXTERNAL_STORAGE => false

MANAGE_EXTERNAL_STORAGE => false

因此,可以得出如下结论

不要尝试判断 MANAGE_EXTERNAL_STORAGE 权限,因为其永远为false

isExternalStorageManager、ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION、ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSIONAPI,只能在安卓11及以上版本调用(低版本调用会闪退)

“应用权限”页面,打开存储权限中的“允许管理所有文件”会使得isExternalStorageManager变为true;但反之在“所有文件访问权限”页面授予权限,并不会改变WRITE_EXTERNAL_STORAGE的允许情况

因此,为了兼容 安卓4.4-安卓12,在11以下,建议使用checkSelfPermission方法进行存储权限判断;而安卓11及以上使用Environment.isExternalStorageManager即可

相关阅读

365提现多久能到账 十款口碑最好的纯电动车 纯电动汽车口碑排行 高口碑纯电车推荐→MAIGOO生活榜

十款口碑最好的纯电动车 纯电动汽车口碑排行 高口碑纯电车推荐→MAIGOO生活榜

365bater 备份shsh文件在哪里 如何找到并备份你的SHSH文件:全面指南

备份shsh文件在哪里 如何找到并备份你的SHSH文件:全面指南

members28365-365 世预赛南美区积分榜最新排名一览全部10队完整榜单

世预赛南美区积分榜最新排名一览全部10队完整榜单

365提现多久能到账 原來是美男

原來是美男

365提现多久能到账 Polymaker PolyMax™ PLA Kidendesign 起點設計

Polymaker PolyMax™ PLA Kidendesign 起點設計

365提现多久能到账 excel怎么计算两个日期差年份

excel怎么计算两个日期差年份

members28365-365 烧水壶功率一般都多少瓦(烧水壶多少瓦)

烧水壶功率一般都多少瓦(烧水壶多少瓦)

365bater 什么是咏叹调

什么是咏叹调

365bater 蚂蚁借呗提额真的很难吗? 网友直呼: 那是你们没用对方法!

蚂蚁借呗提额真的很难吗? 网友直呼: 那是你们没用对方法!