permission
-
2023年4月12日发(作者:南京证券交易软件下载)AndroidMPermission运⾏时权限学习笔记
AndroidMPermission运⾏时权限学习笔记
从Android6.0开始,⽤户需要在运⾏时请求权限,本⽂对运⾏时权限的申请和处理进⾏介绍,并讨论了使⽤运⾏时权限时新⽼版本的⼀些处理.
Android应⽤权限简要介绍
⼀个Android应⽤默认情况下是不拥有任何权限的,这即是说,在默认情况下,⼀个应⽤是没有权利去进⾏⼀些可能会造成不好影响的操作的.这些不好的
影响可能是对其它应⽤,操作系统,或者是⽤户.
如果应⽤需要⼀些额外的能⼒,则它需要在中静态地声明相应的权限.
如果应⽤没有在manifest中声明权限,却使⽤了相应的功能,在调⽤到相应功能的时候,将会抛出异常.
⽐如程序要发送⼀个请求,却忘记加Internet权限,那么在发送这个请求的时候程序就会抛出异常,⼀般不会catch这个异常,所以程序直接就崩溃了:
Causedby:tyException:Permissiondenied(missingINTERNETpermission?)
在Android6.0(API23)发布之前,所有的权限都在安装应⽤的时候显⽰给⽤户,⽤户选择安装则表⽰全部接受这些权限,之后⽆法撤销对这些权限的授权.
Android6.0开始,⼀部分⽐较危险的权限需要在程序运⾏时显式弹框,请求⽤户授权.
⾄于什么时候弹这个框,由应⽤程序⾃⼰决定.
对于其他权限,认为不是很危险,所以仍然保持原来的做法,在⽤户安装应⽤程序时就予以授权.
还需要注意的是,在设置中,对于应⽤的危险权限,⽤户可以选择性地进⾏授权或者关闭.
Permission的保护等级
permission的保护等级通过protectionLevel属性设置,共有4种:normal,dangerous,signature,signatureOrSystem.
具体可以参见介绍:
签名相关的⽐较不常⽤,剩下的两种是normal和dangerous.
Guides⾥⾯对这两种类型进⾏了讨论:官⽹Guides:
总结下来就是:所有的权限仍然在manifest中静态声明,normal权限的在安装的时候⾃动授权,⽽dangerous的权限需要应⽤明确地请求⽤户授权.
当然对于Android6.0以下的⼿机,或者以前开发的旧应⽤来说,dangerous权限也是安装时授权的,具体看下⼀节的讨论.
DangerousPermissions:
ouspermissionsandpermissiongroups.
PermissionGroupPermissions
想要查看所有dangerous的权限,也可以⽤命令:
adbshellpmlistpermissions-g-d
⼿机版本和程序版本的不同处理
这⾥引⽤⼀段Guides⾥⾯的原⽂:
IfthedeviceisrunningAndroid6.0(APIlevel23)orhigher,andtheapp'sis23orhigher,theapprequestspermissionsfromtheuseratrun-time.
Theusercanrevokethepermissionsatanytime,einformationaboutrequestingpermissionsinyourapp,seethetrainingguide.
IfthedeviceisrunningAndroid5.1(APIlevel22)orlower,ortheapp'sis22orlower,thesystemaskstheusertograntthepermissionswhenthe
ddanewpermissiontoanupdatedversionoftheapp,theuserinstallstheapp,theonlywaytheycanrevokethepermissionisbyuninstallingtheapp.
这⾥头要注意and和or的使⽤,说明了只有满⾜targetSdkVersion和实际使⽤设备的版本都在23及以上的时候,才会采⽤新的动态权限机制.其他情况,跟之
前⼀样,在安装和升级应⽤的时候就授权了所有的权限.
可以总结为:
1.所有的权限都在manifest中声明.
2.如果(1)你的app的targetSdkVersion是23及以上,并且(2)app运⾏在Android6.0及以上的设备,危险权限必须动态请求.
当权限被拒绝,app理应还是能够使⽤的,只不过权限相关的部分功能不能⽤.
3.上⼀条中的两个条件(1)(2)没有同时满⾜,即属于其他情况,所有权限在安装时请求,如果⽤户不接受,则不安装.
特别注意这种情况:旧应⽤新系统.
如果targetSdkVersion⼩于23,即被认为是Android6.0发布之前开发的应⽤,还没有兼容6.0.
这种应⽤即便是被装在Android6.0的机器上,也是采⽤原来的安装即授予权限逻辑,所有权限在应⽤安装时全部被授权.
在Android6.0的设备上安装targetSdkVersion⼩于23的应⽤之后,可以在应⽤的设置中查看,发现所有的dangerous权限状态都是打开.
所以不⽤担⼼⽼的应⽤在Android6.0上会各种乱崩.
但是⽤户仍然可以在系统设置中禁⽤权限:
在模拟器上点击授权开关的时候弹出了以下提⽰:
如果⽤户执意要取消授权,应⽤虽然不会直接崩溃,但是功能变为默默⽆作为状态,返回值可能变为null或者0,进⽽引起⽆法预料的⾏为或者崩溃.
为什么要及时升级targetSdkVersion
这是因为每⼀个版本的API有可能会产⽣新的权限,这些新增的权限,对于targetSdkVersion⽐该API低的应⽤是⾃动获取的.
所以targetSdkVersion最好是能及时写到最新,这样避免应⽤⾃动获取到新API新增的权限.
结论:对targetSdkVersion还不存在的权限是⾃动获取到的.
可以参见:APIGuides:
其中”Automaticpermissionadjustments”那段.
Permissiongroup
所有的权限都有⾃⼰的permissiongroup.
系统弹框请求某⼀个permission时也是只说明了它的类别,当⽤户同意,系统会给予它该条permission.(只有这⼀条).
但是如果app已经有了该group下的另⼀条permission,系统将会⾃动授予权限(也即请求权限的callback直接返回),这过程中不与⽤户交互.
动态权限请求的实现
原⽂:
因为权限动态检查相关的API是Android6.0才加⼊的,所以minSdkVersion不是23时,推荐使⽤SupportLibrary来实现,好处是:程序⾥不必加if来判断当前设
备的版本.
1.检查权限状态
如果执⾏的操作需要⼀个dangerouspermission,那么每次在执⾏操作的地⽅都必须check你是否有这个permission,因为⽤户可以在应⽤设置⾥随意地更
改授权情况,所以必须每次在使⽤前都检查是否有权限.
检查权限的⽅法:两个参数分别是Context和权限名.
返回值是:ifyouhavethepermission,orifnot.
⽐如:
if(SION_GRANTED==elfPermission(,_CONTACTS)){
//haspermission,dooperationdirectly
oneContacts(this);
Log.i(DEBUG_TAG,"userhasthepermissionalready!");
}else{
//donothavepermission
2.动态请求权限
如果上⾯权限检查的结果是DENIED,那么就需要显式地向⽤户请求这个权限了.
Android提供了⼏个⽅法来动态请求权限,调⽤这些⽅法会显⽰出⼀个标准的Dialog,这个Dialog⽬前是不能被定制的.
2.1有时候可能需要解释为什么需要这个权限
有时候你可能会需要跟⽤户解释⼀下权限的⽤途.
注意不是每条权限都需要解释,显⽽易见的那种可以不解释,太多的解释会降低⽤户体验.
⼀种⽅式是,当⽤户拒绝过这个权限,但是⼜⽤到了这个功能,那么很可能⽤户不是很明⽩为什么app需要这个权限,这时候就可以先向⽤户解释⼀下.
为了发现这种⽤户可能需要解释的情形,Android提供了⼀个⼯具类⽅法:
如果app之前请求过该权限,被⽤户拒绝,这个⽅法就会返回true.
如果⽤户之前拒绝权限的时候勾选了对话框中”Don’taskagain”的选项,那么这个⽅法会返回false.
如果设备策略禁⽌应⽤拥有这条权限,这个⽅法也返回false.
注意具体解释原因的这个dialog需要⾃⼰实现,系统没有提供.
2.2请求权限
请求权限的⽅法是:传⼊⼀个Activity,⼀个permission名字的数组,和⼀个整型的requestcode.
这个⽅法是异步的,它会⽴即返回,当⽤户和dialog交互完成之后,系统会调⽤回调⽅法,传回⽤户的选择结果和对应的requestcode.
代码:
if(SION_GRANTED==elfPermission(,_CONTACTS)){
//haspermission,dooperationdirectly
oneContacts(this);
Log.i(DEBUG_TAG,"userhasthepermissionalready!");
}else{
//donothavepermission
Log.i(DEBUG_TAG,"userdonothavethispermission!");
//Shouldweshowanexplanation?
if(ShowRequestPermissionRationale(,_CONTACTS)){
//Showanexplanationtotheuser*asynchronously*--don'tblock
//thisthreadwaitingfortheuser'sresponse!Aftertheuser//seestheexplanation,tryagaintorequestthepermission.
Log.i(DEBUG_TAG,"weshouldexplainwhyweneedthispermission!");
}else{
//Noexplanationneeded,wecanrequestthepermission.
Log.i(DEBUG_TAG,"==requestthepermission==");
tPermissions(,
newString[]{_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
//MY_PERMISSIONS_REQUEST_READ_CONTACTSisan
//lbackmethodgetsthe
//resultoftherequest.
}
}
这个对话框是系统的,不能⾃定义.
经验证,请求权限对话框中的”Don’taskagain”的选项,只有该条权限之前的状态是Denied的时候,才会出现.
以前从未授权(即第⼀次弹框),或者之前的状态是Granted(当然这种情况⼀般不会弹框询问),出现的弹框都是不带该不再询问的选项的.
2.3处理请求权限的响应
当⽤户对请求权限的dialog做出响应之后,系统会调⽤⽅法,传回⽤户的响应.
这个回调中requestcode即为调⽤时传⼊的参数,是app⾃定义的⼀个整型值.
如果请求取消,返回的数组将会为空.
代码:@Override
publicvoidonRequestPermissionsResult(intrequestCode,
Stringpermissions[],int[]grantResults){
switch(requestCode){
caseMY_PERMISSIONS_REQUEST_READ_CONTACTS:{
//Ifrequestiscancelled,theresultarraysareempty.
if(>0
&&grantResults[0]==SION_GRANTED){
//permissionwasgranted,yay!Dothe
//contacts-relatedtaskyouneedtodo.
oneContacts(this);
Log.i(DEBUG_TAG,"usergrantedthepermission!");
}else{
//permissiondenied,boo!Disablethe
//functionalitythatdependsonthispermission.
Log.i(DEBUG_TAG,"userdeniedthepermission!");
}
return;}
//other'case'linestocheckforother
//permissionsthisappmightrequest
}
}
系统⾃动回调的情况:
有⼀些情形下,调⽤
1.⾃动授权:如果⽤户已经允许了permissiongroup中的⼀条A权限,那么当下次调⽤⽅法请求同⼀个group中的B权限时,系统会直接调⽤回调⽅法,并传
回的结果.
2.⾃动拒绝:如果⽤户选择了不再询问此条权限,那么app再次调⽤⽅法来请求同⼀条权限的时候,系统会直接调⽤回调,返回.
Demo地址:
BestPractices
原⽂:
BestPractices总结:
1.⽤Intent启动其他应⽤来完成功能.
2.只⽤真的需要的权限.
3.不要⼀次请求多个权限来烦⽤户,有的权限可以等到要⽤的时候再请求.
4.向⽤户解释为什么需要这个权限.
5.从Android6.0开始,每⼀条权限,都需要测试开关两种状态下是不是都能让应⽤正常运⾏,⽽不是崩溃.
并且相关的权限可能会需要测试不同的组合.
ADB命令
可以⽤命令⾏来管理权限:
Usethetooltomanagepermssionsfromthecommandline:
Listpermissionsandstatusbygroup:
$adbshellpmlistpermissions-d-gGrantorrevokeoneormorepermissions:
$adbshellpm[grant|revoke]...
参考资料:
APIGuides:Training:
Runtimepermissions:
permissionelement:
设计Patterns->Permissions:
博客⽂章:
第三⽅库:
PermissionsDispatcher:
RxPermissions:
Grant:
本⽂地址:
本⽂Demo地址:
-
permission