当前位置: 首页 > 科技观察

Android动态权限总结

时间:2023-03-19 15:47:53 科技观察

从Android6.0开始,Android系统提供了动态申请权限的机制。APP使用危险权限时,需要用户授权才能进行进一步操作。权限申请方式在Android系统中申请权限有两种方式,如下图:Android6.0(API<23)之前的系统静态申请采用这种方式。APP之后,默认获取这些权限。这种授权方式的安全性极低。如果用户在安装后没有关闭相应的权限,用户的隐私数据很容易被一些垃圾应用窃取。为了解决这类问题,国内各大手机厂商都对Android5.0以下系统的某些权限做了一定的限制。这在一定程度上提高了安全性,但由于缺乏统一的标准,也存在各种兼容性问题。动态应用随着系统的升级,谷歌也意识到了静态应用权限的弊端,所以在Android6.0中,对权限进行了重新整理,分为正常权限和危险权限:正常权限:不会给用户隐私危险权限,开发者只要在AndroidManifest.xml中注册,系统就会自动授权;危险权限:可以访问用户隐私数据的权限,必须征得用户同意后才能获得授权;Android开发中总结的危险权限我们应该尽可能使用隔离的应用权限,只有在用户没有授权的情况下才屏蔽相应的功能。现在很多内容类APP都需要各种权限,让用户进去什么都看不到,没有权限就不能用。这可能会引起用户的反感。用户可能觉得他们应该授权应用程序使用它,从而给一些恶意应用程序提供了作恶的空间。动态申请权限的流程核心API介绍检查是否已经获得权限://ContextCompat.javapublicstaticintcheckSelfPermission(@NonNullContextcontext,@NonNullStringpermission)//PermissionChecker.javapublicstaticintcheckSelfPermission(@NonNullContextcontext,@NonNullStringpermission)这两个方法是检查是否获得的方法获取到权限,但是ContextCompat.checkSelfPermission在某些系统(比如基于Android8.0的MIUI10在检查短信权限时)存在bug,无法准确判断是否获取到权限。这时候可以结合PermissionChecker.checkSelfPermission进行判断,所以可以判断是否获得了权限可以使用如下实现:permission)!=PackageManager.PERMISSION_GRANTED||PermissionChecker.checkSelfPermission(context,permission)!=PackageManager.checkSelfPermission_GRANTED||PermissionChecker.checkSelfPermission(context,permission)!=PackageManager.permisfreGranse;}申请权限当你没有获得权限时,你需要向系统请求,请求时使用requestPermissions方法://ActivityCompat.java//在Activity中申请权限publicstaticvoidrequestPermissions(final@NonNullActivityactivity,final@NonNullString[]permissions,final@IntRange(from=0)intrequestCode)//Fragment.java//在Fragmentpubl中申请权限icfinalvoidrequestPermissions(@NonNullString[]permissions,intrequestCode)当Fragment使用ActivityCompat.requestPermissions申请权限时,如果用户拒绝请求(勾选该行不再提示),则不会回调Fragment中的onRequestPermissionsResult,无法引导用户打开。权限所以在Fragment中,应该使用Fragment的成员方法requestPermissions来请求权限。检查APP是否显示申请权限说明//ActivtyCompat.java//检查APP是否显示申请权限说明publicstaticbooleanshouldShowRequestPermissionRationale(@NonNullActivityactivity,@NonNullStringpermission);该方法返回值解释如下:当APPNever申请指定权限或申请指定权限被用户拒绝,并勾选【NeverPrompt】,返回false;当app申请指定权限时,被用户拒绝了,但是没有勾选【NeverPrompt】,返回true所以在使用该方法的时候,首先要判断APP是否申请过权限,否则很难判断返回false的两种情况。申请权限的结果回调publicvoidonRequestPermissionsResult(intrequestCode,@NonNullString[]permissions,@NonNullint[]grantResults)这是Activity和Fragment中申请权限的结果回调方法,其中permissions表示申请的权限数组,grantResults表示每个权限的请求结果。值为://授权publicstaticfinalintPERMISSION_GRANTED=0;//未授权publicstaticfinalintPERMISSION_DENIED=-1;通常申请权限后的处理逻辑都是在这个方法中实现的。动态权限申请实现动态申请权限的条件:targetSdkVersion>=23;安卓系统版本为6.0及以上;如果不能同时满足以上条件,则默认采用静态申请权限方式,但为了安全起见使用不同的ROM。它的机制可能已被修改,因此它可能因ROM而异。了解了申请权限的核心API之后,我们来介绍一下在Activity中申请权限的实现过程。我们以点击申请拍照权限为例:privatevoidstartPhoto(){if(hasPermission(this,newString[]{Manifest.permission.CAMERA})){//执行拍照逻辑}else{ActivityCompat.requestPermissions(context,rnewString[]{Manifest.permission.ACCESS_FINE_LOCATION}),PERMISSION_REQUEST_CODE);}}然后在onRequestPermissionsResult中监听权限申请结果:@OverridepublicvoidonRequestPermissionsResult(intrequestCode,@NonNullString[]permissions,@NonNullint[]grantResults){super.onRequestPermissionsResult(requestCode,permissions,grantResults);if(hasPermission(permissions)){//执行拍照逻辑}else{if(ActivityCompat.shouldShowRequestPermissionRationale(context,permissions[refusedPermissionIndex])){//向用户显示reasonforapplyingpermission}else{//参考用户是否开启权限}}}以上只是申请权限的基本流程。在实际实现的时候,必须考虑多重权限。版本兼容性问题,ROM兼容性问题等。当然在开发中,没必要在每个需要申请权限的Activity/Fragment中都写这段代码。即使封装成工具类,也需要在每个Activity/Fragment中引用,耦合度太高。通常,权限申请可以在一个透明的Activity中实现,这样在申请权限的时候,可以直接跳转到Activity中。下面推荐一个动态申请权限的库供参考。PermissionManagerPermissionManager是一个开源的基于AOP动态申请权限的库,目的是让申请权限的过程更加简单。当然也可以作为学习Aspectj的参考项目。具有以下优点:支持多权限申请;简单易用,一行注解实现权限申请提供可扩展的权限描述和引导设置方法;提供阻塞/非阻塞的应用方式;具体介绍可以参考其源码地址:PermissionManager总结由于Android碎片化严重,国内各大厂商对权限的处理也各不相同,所以在动态应用中肯定会出现故障。如果您在使用PermissionManager时发现问题,请随时提出问题和拉取请求。