7、权限模型演变:从Marshmallow运行时权限到Android 13细粒度媒体权限,升级中的权限适配
权限这个话题,每次Android大版本升级都会让我头疼一阵子。说实话,从Android 6.0到现在,权限模型已经改了好几轮了。每次改动都意味着我们这些做系统升级的人,得重新审视一遍代码。
今天我就把这几年的权限演变脉络理一理。你想想看,从最早的「安装时授权」到现在的「运行时申请」,再到Android 13的细粒度媒体权限,这条路其实挺曲折的。
7.1 运行时权限:一个分水岭
Android 6.0(Marshmallow)引入运行时权限,这是个标志性事件。在那之前,用户安装应用时看到一长串权限列表,基本就是「要么全给,要么别装」。
我记得当时有个项目,客户要求把老款平板从Android 5.1升级到7.1。那会儿我们团队最头疼的就是权限适配。老应用里到处都是READ_CONTACTS、ACCESS_FINE_LOCATION这种敏感权限,升级后直接崩溃。
- 权限被分为「正常权限」和「危险权限」两类
- 危险权限必须在运行时动态申请
- 用户可以选择「拒绝」或「不再询问」
适配的关键点其实就一个:别假设权限已经有了。每次使用敏感API前,都得检查一下权限状态。
// 检查权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
// 申请权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_CODE);
} else {
// 已有权限,直接操作
openCamera();
}
嗯,这里要注意一点:requestPermissions是异步的,结果会回调到onRequestPermissionsResult里。我见过不少新手直接在回调外面继续执行代码,结果权限还没拿到就崩了。
7.2 Android 10-11:分区存储与权限收紧
到了Android 10(Q),Google开始搞分区存储(Scoped Storage)。说白了,就是不让应用随便访问外部存储了。每个应用只能读写自己的专属目录,或者通过MediaStore访问公共媒体文件。
我在项目中遇到过一个问题:某款文件管理器升级到Android 10后,用户反馈「看不到SD卡里的文件了」。查了半天,发现是READ_EXTERNAL_STORAGE权限在分区存储模式下,只能读到媒体文件,其他文件类型根本看不到。
MANAGE_EXTERNAL_STORAGE权限(Android 11引入)。但这个权限审核很严,Google Play上架时得说明用途。
Android 11进一步收紧了权限。比如「一次性权限」——用户可以选择「仅本次允许」,下次再用还得重新申请。还有「自动重置权限」——如果应用长时间没用,系统会自动撤销它的权限。
7.3 Android 13:细粒度媒体权限
Android 13(Tiramisu)把媒体权限拆得更细了。以前一个READ_EXTERNAL_STORAGE就能读所有媒体文件,现在不行了。
| 旧权限 | 新权限(Android 13) | 说明 |
|---|---|---|
| READ_EXTERNAL_STORAGE | READ_MEDIA_IMAGES | 只读图片 |
| READ_EXTERNAL_STORAGE | READ_MEDIA_VIDEO | 只读视频 |
| READ_EXTERNAL_STORAGE | READ_MEDIA_AUDIO | 只读音频 |
为什么要这么改?说白了,用户隐私保护越来越严格。以前你申请一个权限就能看所有照片、视频、音乐,现在用户可以选择「只给看照片」,视频和音乐不给看。
适配的时候,我建议这样处理:
// Android 13 适配示例
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// 分别申请三种媒体权限
String[] permissions = {
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_VIDEO,
Manifest.permission.READ_MEDIA_AUDIO
};
requestPermissions(permissions, REQUEST_MEDIA_CODE);
} else {
// 低版本用旧权限
requestPermissions(
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_STORAGE_CODE
);
}
READ_EXTERNAL_STORAGE映射成三个新权限。但Google Play从2023年开始要求新应用必须target 33+,所以别指望这个兼容机制能一直用。
7.4 权限适配的避坑指南
我曾经踩过一个坑:某款相机应用在Android 13上拍照后无法保存图片。查了半天,发现是只申请了CAMERA权限,没申请WRITE_EXTERNAL_STORAGE。但在Android 13上,WRITE_EXTERNAL_STORAGE已经没用了,得用MediaStore的API来保存。
这里我总结几个常见问题:
- 权限被拒绝后怎么办?别直接退出应用。可以引导用户去设置里手动开启,或者降级功能(比如没有定位权限就不显示地图,但其他功能正常用)。
- 「不再询问」的处理:如果用户勾选了「不再询问」,
shouldShowRequestPermissionRationale会返回false。这时候再弹申请对话框也没用,得跳转到系统设置页面。 - 权限组的概念:同一个权限组里的权限,只要有一个被授予,其他也会自动授予。比如
CAMERA和RECORD_AUDIO同属MICROPHONE组,申请相机权限时,麦克风权限也会被带出来。
7.5 知识体系总览
下面这张图是我自己整理的权限模型演变路线,从Android 6.0到13,每个版本的关键变化一目了然:
从这张图可以看出来,Google的权限策略是越来越严的。每次升级,我们都要检查一遍应用里用到的所有权限,看看有没有被废弃或者拆分的。
最后说一句:权限适配没有捷径。老老实实把每个权限的申请流程走一遍,该检查的检查,该降级的降级。别想着偷懒,用户隐私保护这条红线,碰不得。
公众号:蓝海资料掘金营,微信deep3321