一、Android权限背景知识
在Android 6.0之前,所申请的权限只需要在AndroidManifest.xml列举就可以了,从而容易导致一些安全隐患,因此,在Android 6.0时,Google为了更好的保护用户隐私提出了新的权限管理机制,同时将其分为两大类:
(1)Normal Permissions
Normal Permission一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动,访问网络等。
(2)Dangerous Permission
Dangerous Permission一般是涉及到用户隐私的,需要用户进行授权(动态申请),比如读取SIM卡状态、访问通讯录、SD卡读写等。
通过adb shell pm list permission -d -g可以查看Dangerous Permission。
Dangerous Permission一般以Permission group形式存在,只要Permission Group中某一个permission被Granted(授予),则整个Permission group下的权限均被Granted。
二、权限检查及权限兼容
1.targetSdkVersion>=23,终端设备是6.0(api 23)以上系统。
安装的时候不会获得权限,在运行时向用户申请对应权限。这部分权限检查比较简单,不涉及权限兼容,使用官方方案就可以,使用Context:checkSelfPermission,建议使用ContextCompat:checkSelfPermission检查权限即可,一般检查流程如下:
(1)判断是否有对应权限
(ContextCompat::checkSelfPermision)
(2)判断是否需要解释对应权限用途(ActivityCompat::shouldShowRequestPermissionRationale)
如果需要解释,则显示自定义权限界面即可
(3)不需要解释的话,直接请求对应权限
(ActivityCompat::requestPermission)
2.targetSdkVersion<23.终端设备是6.0(api 23)以上系统
使用的是老的权限机制,在app安装时会询问AndroidManifest.xml文件中的权限,但是用户可以在设置列表中关闭相关权限,这种情况可能会对app正常运行造成一定影响。
3.终端设备系统小于6.0(api 23)
老的权限管理机制是,在app安装时会询问AndroidManifest.xml文件中的权限,用户关闭不了,但是目前有不少国产Rom手机在6.0之间就有关闭权限的开关。
适配过程:
1.使用try-catch来检查权限是否关闭
使用READ_PHONE_STATE权限的方法内部已经try-catch,外面无法捕获,所以如果该权限被用户禁止了,报异常时,在catch中做文章的方法根本没有用。
2.ContextCompat::checkSelfPermission
在6.0可以使用Context::checkSelfPermission进行权限检查,在api 23那使用support v4中的ContextCompat::checkSelfPermission方法失效,只要权限在AndroidManifest.xml中注册过,均会认为该权限granted,因此方法在api 23以下失效。
3.PermissionChecker
PermissionChecker内部实际上使用的是AppOpsManagerCompat,而AppOpsManager是在api 19加入进去的。
在api 23以下,AppOpsManagerImpl::permissionToOp直接返回为null,这直接导致api 23以下权限检查将会返回granted,因此,该方法在api 23下,权限检查方法也会失效。
4.AppOpsManager
API 19以上,Google官方提供了AppOpsManager类来检查权限,里面有两个比较重要的方法: AppOpsManager::checkOp(int op,int uid,String packageName)(hide方法,需要反射)和AppOpsManager::checkOp(String op,int uid,String packageName)(public方法,api 23以上可用)。
但是,当api低于23时,OP_READ_PHONE_STATE=51找不到,导致AppOpsManager::checkOp方法反射失败,导致的原因是每个版本的_NUM_OP不同,OP_READ_PHONE_STATE = 51在6.0(API 23)以下,通过反射是找不到的,因此对于READ_PHONE_STATE权限检查仅限于6.0及6.0以上。
三、跳转到app管理权限界面
1.直接跳转系统设置页
Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.fromParts("package",getPackageName(), null)); try { startActivity(intent); }catch (Exception e){ e.printStackTrace(); }
记得要添加try-catch,不加可能会crash(崩溃)。这种方式就不需要适配各个厂商的不同版本rom,缺点是,用户只能跳转到系统设置页,然后去找对应app的权限管理。
2.站在前人的肩
对于不同的手机或手机系统,跳转权限管理页面的activity或者有所不同,如果没有加上try-catch,就会直接crash。
对于这种变化,作为开发者一般都是不知道的,即便通过反馈发现了这个问题,也有可能不知道actiivty是什么,此刻要么搜索网上有没有类似解决方案,要么求助于对应rom开发厂商的开发者论坛。
3.查看某个rom的某个版本的权限管理界面的activity
(1)通过设置找到对应app的权限管理页面
(2)找到对应页面的activity
方法一:通过add工具查看栈顶Activity
adb shell dumpsys activity | grep "mFocusedActivity"
方法二:使用Activity Tracer工具
本文只是将看到的文章进行了学习整理记录,详细的还请查看原文。
原文:http://mp.weixin.qq.com/s/OQRHEufCUXBA3d3DMZXMKQ