Android (6.0) M 请求权限


Android M发布有一段时间了,AndroidM在API上和代码中有不少改动,并不比AndroidL小。我们只能感谢Google又给android程序员带来的新的研究课题,相比之下Android 6.0 优化做的相对好的一个版本。

一、权限请求变更

动态权限请求是Google在对Android的安全问题进行一次非常有效的提升,对用户是非常有用的,类似苹果,用户可以很任性在Setting的关掉App一些权限,比如打电话,发短信。然而,对Android程序员来说,却是非常致命,曾经天经地义可以使用的API尽然会抛异常导致程序crash了。这让我们的代码逻辑完全不适用了。 
    权限的分类:
首先Google把Android的权限分为了两类,一类叫正常权限(Normal Permission),另一类叫危险权限(Dangerous Permisson );
   (1)正常权限:当你的应用程序访问外部数据或操作的行为对用户的隐私暴露风险很小,这种类型的权限定义为正常权限,比如打开闪光灯,访问网         络,对用户没啥大影响。这类权限使用方式和以前一样,只要在manifest中声明了,系统就会自动赋予权限。
   (2)运行时权限就是我上面说的危险权限,需要手动申请
      危险权限:当应用程序需要访问用户的个人数据,或是影响用户已保存的数据时发生的权限。当使用这类权限时,那就必须显式的让用户同意(iOS也是这么做的)。危险权限本身是分组的,每一组之内的权限只需要申明一次。 
    权限组: (运行时权限,使用到如下权限,必须进行判断是否有申请权限)
   1.Calendar
   2.Camera
   3.Contacts
   4.Location
   5.MICROPhone
   6.Phone
   7.Sms
   8.Sensors
   9.Storage
  Android (6.0) M 请求权限_第1张图片

 比如上表中ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION是同属于LOCATION这个权限组,那么只要在申请ACCESS_FINE_LOCATION时,用户同意了,则系统自动会赋与ACCESS_COARSE_LOCATION的权限,不需要重新申请了。

 (3)相对应 Android 6.0权限的Code Path :

Packages/apps/packageInstaller/src/com/android/packageInstaller/permisson/      //管理install 是权限
                           Framework/base/services/core/java/com/android/server/pm
  (1)DefaultPermissionGrantPolicy.java   给某些预制的apk,给予权限,也可以撤销
  (2)PermissionsState.java               管理权限的状态

(4)谷歌会在第一次开机时,默认打开一些特定的app 运行权限
   具体代码在DefaultPermissionGranPolicy.java 中
   (1)App Permission 管理对应的类
      1.ManagePermissonsActivity
 2.Manage_APP_Permission
 3.AppPermissionsFragment
   (2)ManagePermissionsActivity
      Manage_Permission_Apps
      PermissionAppsFragment

二、权限检查和申请

当你确定你需要申请权限(在检查权限方法返回PERMISSION_DENIED),你就可以调用申请权限的api。这个API支持批量申请,但是不建议一次申请太多,一般都是用到什么权限申请什么权限,因为用户需要对每一个权限做确认。 
这个API也是在ActivityCompat中,他的函数签名是这样的。

(1)必须注意:每次访问时 都需要检查权限,用户可以自己撤销权限,而且不会通知app
   Context.checkSelfPermission(READ_CONTACTS)==PackageMANAGER.PERMISSION_GRANTED{
      //存在

   }else{
     //不存在  需要去申请  

 requestPermissions(new String[]{""},int)
   }

2.用户响应权限请求后,系统会调用Activity.OnRequestPermissionResult(int requestCode ,String[] args,int [] resulst)
    在app里面重写Call Back回调
    swich(requestCode){       
  case  READ_CONTACTS :                                                              //如果用户取消,permissions可能为null.
   if(results[0]==PackageMANAGER.PERMISSION_GRANTED &&grantResults.length > 0){  //有权限
  // 可以安全的调用api。
}else{
//拒绝
}
  braak;
}

这个方法的参数中requestCode用于对应你之前requestPermission中的值,grantResults中的结果与permissions中的权限按顺序一一对应。grantResults的结果是PackageManager.PERMISSION_GRANTED或PackageManager.PERMISSION_DENIED之一

(3)告诉用户为什么要申请权限,在弹出系统框之前,先给客户提示下为什么用这个权限。 当第一次请求或是用户关闭了这个权限时,返回true,其他情况下返回False,当然sdk 23以下的手机总是返回false   .如果收到true, 那么你需要提示用户你为什么需要权限。
ActivityCompat .shouldShowRequestPermissionRationale (context, Manifest .permission .SEND _SMS)

放在去申请权限前来弹个Toast

if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_CONTACTS)) {

//做点什么,弹个Toast

}

(4)简单说下检查权限的流程
  App->context.checkSelfPermission-->ContextImpl-->AMS>ActivityManagerNative.getDefault().checkSelfPermission--->
  PMS->AppGlobals.getPackageManager().checkUidPermission(permisson,uid)--->PMS通过调用PermissionState.hasPermission判断某个uid是否
  拥有某个permission

5)简单说下请求权限的流程

  App-->Activity.requestPermissions-->然后startActivityForResult-->然后调到PackageInstaller里面的GrantPermisslonsActivity,然后show给用户看,你需要不需要申请权限。如果同意->就调用PMS的grantRuntimePermission获取到权限并且调用setResuletAndFinsh函数CallBack返回给
  App--app只要需要在Activity中重写OnRequestPermissionResult方法。
  (2)Activity Intent的内容Action就是ACTION.Request_permissionS 数据包就是permission.name


6.Apk安装时会判断权限类型,对于dangerous的权限,会判定为runtimePermission,安装时不会对User赋予此权限.
  其他类型的权限,则安装时赋予给所有的User
  grantPermissionsLpw    --获取权限的接口
     -writeRuntimePermissionsForUserLpr  写入xml
  对应的runtime-permissionos.xml 每个user维护一份

以上分析流程大家可以对照源码继续进行分析更深入,这里只是简单说下笔者的流程,可能还有地方说的不到位,或者错误,请大家留言,分享给大家,谢谢


你可能感兴趣的:(Android)