【Bug】因为Android13新特性拿不到访问音频权限
描述
时间点:
2022年8月我换了红米K50,它当时是MIUI13(基于Android12)。
项目演示的录制时间是2022年5月
Android13发布是2022年8月
然后我就更新了MIUI14,从Android12 -> Android13
做一个音乐APP的时候,需要扫描本地音乐。
需要扫本地资源仓库,然后找mp3音乐文件。
但是代码写好后,一直扫不到。
分析
锁定代码问题:
手机自带音乐播放器可以扫描到这些文件 -》说明已经由
外存文件
变为系统资源库文件
然后准备看数据库,但是因为手机没有root,没权限看。
虚拟机有权限,app运虚拟机,ok。
然后问老师,是本来就有的Bug,还是我的代码有问题。
然后直接下成品的app,发现这个功能可以。
说明是我自己的代码有问题。
-
刚开始以为代码写错了
-
然后定位到本地音乐模块
-
再定位到
ScanLocalMusicAsyncTask
这个【扫描本地音乐异步任务】类 -
再定位到
doInBackground
方法(没有那个扫目录的动画) -
再定位到某块代码没有执行
1
while (cursor != null && cursor.moveToNext()) {
-
通过打日志,发现cursor不为null,但是没有数据。
-
然后查cursor的实例化方法
1
2Cursor cursor = contentResolver.query(
... -
代码没问题
-
后来被指点是权限问题,然后对着
AndroidManifest。xml
以及那个动态申请权限的框架和动态申请代码
一顿实验。 -
偶然间,看手机app后台的时候发现:我出Bug的app相对成品app少了一个
访问音频
的访问权限。 -
问题就到:为什么有访问资源库的权限就访问音频没了?
-
还是在那两个文件死磕了很久,不断的搜索和尝试
-
最后在这样搜:
READ_EXTERNAL_STORAGE 不能访问音频
找到答案:是Android13的新特性。
-
实现
1, 配置文件中申明
(13只用下面那个,但是低于13只要上面那个)
2,然后在动态申请加上这个
总结
-
Android新版版特性对Android开发很重要,搞不好就是一个卡好几天的坑
-
要根据Bug样子,尽量定位到关键所在。
-
多用日志和一些辅助信息去判断问题到底出在哪里
后续
当时改了之后,在Android13的手机上可以运行了。
但是在13版本一下的手机就进入不了界面。
是这里的权限处理。
就是13:用新权限
12以及一下:用老权限
所以这里要加权限判断:
先简单处理了一下。
纠正2
这个地方我还是没有搞懂,他的本质是Android不同版本之间的权限处理问题。
从【总结】开始处理错了。
没有弄明白这个动态处理权限框架的用法。
正确的bug修复是这样的:
我们应该根据当前手机版本的不同去申请不同的权限。
Android13申请:
android.permission.READ_MEDIA_IMAGES
android.permission.READ_MEDIA_VIDEO
android.permission.READ_MEDIA_AUDIO
Android12以及一下用:
android.permission.READ_EXTERNAL_STORAGE
权限申明
AndroidManifest 里面加上所有要用的权限
1 | <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> |
不管老版新版。都要写
具体代码
1 | /** |
注意,如果之前这个已经用过一次的话,会生成一个SplashActivityPermissionsDispatcher
类。
要去这个类的磁盘目录删了,然后出来先把带有这个类的代码注释掉。
然后运行以下,就生成了新的这个类。
然后再把之前注释的代码打开就可以了。
我的坑经验:
这个动态请求权限的框架,如果想实现:
Android13申请权限A,Andorid14申请权限B。
就要用两个
@NeedsPermission
,然后下面写两个onPermissionGranted
来处理不同版本的权限申请结果。比如一个 onPermissionGrantedOld 一个 onPermissionGrantedNew
这样就会生成两个权限请求方法。
然后我们在
checkPermission
中判断:
1
2
3
4
5
6
7 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// 请求权限new
SplashActivityPermissionsDispatcher.onPermissionGrantedNewWithPermissionCheck(this);
} else {
// 请求权限old
SplashActivityPermissionsDispatcher.onPermissionGrantedOldWithPermissionCheck(this);
}如果是Android13以及高版本,就用
SplashActivityPermissionsDispatcher.onPermissionGrantedNewWithPermissionCheck
如果是Android12以及低版本,就用
SplashActivityPermissionsDispatcher.onPermissionGrantedOldWithPermissionCheck
二次总结
用别人的框架一定要弄懂到底应该怎么用。