谈谈Android 6.0运行时权限理解[转]

谈谈Android 6.0运行时权限理解

前言

 谷歌在2015年8月份时候,发布了Android 6.0版本,代号叫作“棉花糖”(Marshmallow ),其中的很大的一部分变化,是在用户权限受权上,或许是感受以前默认受权的不合理,如今6.0出来,使得用户权限受权变得合理。这可能也是参考IOS系统的,只有在用户须要使用权限的时候,才去受权请求,这样作的目的是提升用户体验,固然,用户感受好了,受苦的是咱们开发人员,原来的规则不适用了,如今咱们去适应新的规则,毕竟是靠谷歌这颗大树吃饭的嘛。html

原来权限模型

 在Android 6.0版本以前,权限都是一条龙服务的,只要用户安装完AndroidManifest清单上申请的权限都会被系统默认受权,而且受权后也撤销不了。这样的弊端在哪里呢?有些权限可能用户以为不须要,好比他不想有通知的权限,不想受到通知的干扰,那么他就不能屏蔽通知,就是不须要的权限,他去不掉,自主权不在他那边。还有一些状况是,一些恶意程序,会利用这个权限默认受权,进行恶意获取用户数据和攻击。因此Android 6.0版本,一方面让用户更加容易的控制本身的隐私,一方面须要从新适配应用权限。android

Android 6.0权限模型

  采用新的权限模型,只有在须要权限的时候,才告知用户是否受权,是在runtime时候受权,而不是在原来安装的时候 ,同时默认状况下每次在运行时打开页面时候,须要先检查是否有所须要的权限申请。这样的用户的自主性提升不少,好比用户能够给APP赋予摄像的权限,可是能够拒绝记录设备位置的权限,就是怕位置信息上传等等。git

权限流程

  在API 23中,权限知足的标准流程:github

但这里有个问题,那就是在系统受权弹窗环节,提醒框会有个再也不提示的复选框,若是用户点击不太提示,并拒绝受权,那么再下次受权的时候,系统受权弹窗的提示框就不会在提示,因此咱们颇有必要须要自定义权限弹窗提示框,那么流程图就变成以下了。app

 

权限类型

 在图中,咱们能够看到整个权限里,能够分为系统权限和特殊权限受权。系统权限中,又分为normal和dangerous类型。async

 normal:这个权限类型并不直接威胁到用户的隐私,能够直接在manifest清单里注册,系统会帮咱们默认受权的。ide

 dangerous:这个能够直接给app访问用户一些敏感的数据,不只须要在manifest清单里注册,同时在使用的时候,须要向系统请求受权。ui

 值得注意一点,这里有特殊权限受权的区别,分别是SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS,虽然这两个权限也是属于dangerous权限类型,可是这两个受权请求方式和其余dangerous权限是不同的,须要特殊处理 。this

   normal列表:spa

 

dangerous列表:

 

Permission Group Permissions
CALENDAR
CAMERA
CONTACTS
LOCATION
MICROPHONE
PHONE
SENSORS
SMS
STORAGE

 

版本兼容

 固然,谷歌也是考虑到若是是以API 23以前的版本编译的APP,在6.0的系统上运行,仍是能兼容的。若是是23以前的版本编译的APP,则权限模型走的是老的模式,也就是在一条龙的模式,在manifest清单注册,系统会帮咱们默认受权,而且也能运行。

   但若是是以API 23的版本编译的APP,那走的的必须是新的权限模型,在遇到dangerous权限的时候,必须进行受权的,若是没有进行受权话,系统则会提示崩溃信息。因此,基于6.0系统的开发的程序, 在打开页面的时候,必需要考虑这个页面是否用到须要受权的权限,页面检测是否已经受权过了没。

 

实现方式

   第一步:检测权限

// Assume thisActivity is the current activityint permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);

    第二步:请求权限

复制代码

// Here, thisActivity is the current activityif (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)        != PackageManager.PERMISSION_GRANTED) {    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {        // Show an expanation to the user *asynchronously* -- don't block        // this thread waiting for the user's response! After the user        // sees the explanation, try again to request the permission.
    } else {        // No explanation needed, we can request the permission.
        ActivityCompat.requestPermissions(thisActivity,                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an        // app-defined int constant. The callback method gets the        // result of the request.    }
}

复制代码

 第三步:处理权限请求结果

复制代码

@Overridepublic void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {    switch (requestCode) {        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                // permission was granted, yay! Do the                // contacts-related task you need to do.
            } else {                // permission denied, boo! Disable the                // functionality that depends on this permission.            }            return;
        }        // other 'case' lines to check for other        // permissions this app might request    }
}

复制代码

 

其中要特别注意的是,若是是针对

“android.permission.SYSTEM_ALERT_WINDOW”
“android.permission.WRITE_SETTINGS”

这两个权限,实现方式跟上以前在工做中,碰到一种状况,若是是运行在6.0的版本上是须要走新的权限模型,若是是运行在老的版本上,则须要进行一个判断,此时碰到一个问题是,在谷歌官方推荐中,在判断app运行的系统是否在Android M上时,它的判断是以下:  Build.VERSION.CODENAME.equals("MNC"); 但是在我实际适配中,发现这句却无效的,就改用Build.VERSION.SDK_INT >= 23。的,须要另外特殊处理。

针对SYSTEM_ALERT_WINDOW权限,须要向系统发送一个ACTION_MANAGE_OVERLAY_PERMISSION.这样一个动做,同时能够用Settings.canDrawOverlays() 方法进行判断以前是否已经受权过了。

针对WRITE_SETTINGS权限,须要向系统发送一个ACTION_MANAGE_WRITE_SETTINGS 这样一个动做,同时能够用Settings.System.canWrite().方法进行判断以前是否已经受权过了。

具体代码:

Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

注意点

 以前在工做中,碰到一种状况,若是是运行在6.0的版本上是须要走新的权限模型,若是是运行在老的版本上,则须要进行一个判断,此时碰到一个问题是,在谷歌官方推荐中,在判断app运行的系统是否在Android M上时,它的判断是以下:  Build.VERSION.CODENAME.equals("MNC"); 但是在我实际适配中,发现这句却无效的,就改用Build.VERSION.SDK_INT >= 23。

 

 

 总结

  1. 首先要知道6.0版本权限模型跟原来版本是不一样的,再也不是统一在manifest中默认系统受权,而是有须要的时候,向系统请求受权,提升用户体验。

  2. 了解权限检测流程,一点注意点是若是系统权限弹窗提示框被再也不提醒了,须要咱们自定义提示弹窗,引导用户去受权。

  3. 明白权限类型,分为normal和dangerous类型,同时,在dangerous中还须要注意一点,SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS这两个特殊受权请求方式,跟通常受权请求方式不一样。

  4. 在判断APP是否运行在Android M上,能够用版本号来判断,能够准确点。

 参考

    有个具体demo:https://github.com/SpikeKing/wcl-permission-demo

    流程图:http://blog.csdn.net/caroline_wendy/article/details/50587230

相关文章
相关标签/搜索