系统权限

来源:互联网 发布:集贤第一中学网络空间 编辑:程序博客网 时间:2024/06/05 14:09

整理自:https://developer.android.google.cn/training/permissions/index.html
每个Android app都是运行在访问受限的沙盒中,如果需要使用到外部的资源信息,则需要在Manifest中添加权限表明本应用需要的权限。只需要声明直接使用到的权限,间接使用到的权限不必声明。
取决于权限的敏感程度,即对用户的隐私的影响程度,系统可能会自动授权,或者需要用户授权。比如打开手电筒系统自动授权,读取联系人则需要用户授权。
权限可分为正常权限和危险权限。
正常权限不会给用户隐私带来风险,所以如果Manifest中声明了正常权限,系统会自动授权。
危险权限使app可以访问用户的隐私信息,所以如果Manifest中声明了危险权限,用户需要主动同意。
权限声明的效果,也是用户授权的方式,与设备系统版本和API版本有关。如果系统版本是5.1及以下,或者target SDK是22及以下,声明危险权限而需要的用户授权发生在安装app时,如果用户不同意授权,则app无法安装。
如果系统版本是6.0及以上,或者target SDK是23及以上,声明每一项危险权限而需要的用户授权发生在app运行时。用户可以同意或者拒绝授权,即使拒绝授权,app仍可以有限的权限继续运行。
但是从6.0开始,即使target SDK比较低,用户仍可以随时撤销(revoke)任何应用的权限,所以无论目标SDK是多少,都必须保证自己的app在缺少相应权限时可以正常运行。
本教程使用support library来检测并请求权限,6.0也有相应方法,但是使用support库就不必检测系统版本了。
如果你的app有用到危险权限的操作,则每次进行该操作都必须确保拥有该权限,因为用户随时可以撤销授权,所以即使昨天使用到了相机,也不能保证今天还拥有该权限。

检测权限

示例:

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

如果app拥有此项权限,则返回值是 PackageManager.PERMISSION_GRANTED,如果app没有该项权限,则返回值是 PERMISSION_DENIED,此时需要明确要求用户授权。

请求权限

如果Manifest中声明了危险权限,则必须请求用户授权,可以调用下面的方法请求授权,调用这些方法会弹出无法定制的标准Android对话框。

解释为什么需要权限

如果app请求了不太符合用户期望的权限,则可以考虑向用户解释原因,但是也不能过度解释导致用户反感。比如相机类应用请求相机权限十分正常,但是请求位置或者联系人权限就可能得不到用户理解。
一种适合解释的场景是用户一直尝试使用某项需要权限的功能,但是又一直拒绝权限请求,表明用户可能不太理解需要某权限才能使用该功能,此时适合向用户弹出解释。
Android提供了一个方法shouldShowRequestPermissionRationale()帮助判断,如果app申请了该权限,但是被用户拒绝了,则该方法会返回true。但是如果用户拒绝时勾选了Don’t ask again,或者设备策略禁止app获取该权限,这个方法就会返回false。

发出请求

如果app没有相应权限,则需要调用 requestPermissions()方法申请权限,这是个弹出对话框后马上返回的异步方法,请求结果在用户点击了对话框才会返回到回调方法中。注意对话框无法定制,所以如果要提供任何信息或者解释,应该在调用 requestPermissions()之前操作。

if (ContextCompat.checkSelfPermission(thisActivity,                Manifest.permission.READ_CONTACTS)        != PackageManager.PERMISSION_GRANTED) {    // 判断是否需要弹出解释    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,            Manifest.permission.READ_CONTACTS)) {        // 异步显示解释,注意不能将线程阻塞在这里等待用户回应,应该等到        // 用户看见解释了,才再次尝试请求。    } else {        // 不必解释,直接请求        ActivityCompat.requestPermissions(thisActivity,                new String[]{Manifest.permission.READ_CONTACTS},                MY_PERMISSIONS_REQUEST_READ_CONTACTS);        // MY_PERMISSIONS_REQUEST_READ_CONTACTS是自定义常量    }}

处理请求回调

@Overridepublic void onRequestPermissionsResult(int requestCode,        String permissions[], int[] grantResults) {    switch (requestCode) {        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {            // 如果请求被取消了,结果数组为空            if (grantResults.length > 0                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                // 请求被允许了,使用该功能            } else {                // 请求被拒绝了,不使用依赖于该权限的功能            }            return;        }        // 其他可能需要的权限检测    }}

弹出的请求对话框显示的是某项权限对应的权限组,比如申请 READ_CONTACTS的权限,显示的是需要访问设备的联系人。每个权限组只需要授权一次,组内所有权限都会自动得到系统授权。如果你申请了组内某个其他权限,则系统会自动调用 onRequestPermissionsResult()然后返回PERMISSION_GRANTED,就跟用户通过对话框明确授权这项请求一样。
比如Manifest中列出了READ_CONTACTS和WRITE_CONTACTS,如果请求 READ_CONTACTS而且用户授权了,那么接着请求WRITE_CONTACTS则系统就不会要求用户授权,自动授权过去。
但是你仍然要为每项需要的权限申请授权,权限的分组可能会随着新版本的发布改变。
注意用户可以在弹出对话框中选择Don’t ask again,则app调用 requestPermissions()方法时,系统自动拒绝授权,在onRequestPermissionsResult()回调方法中返回PERMISSION_DENIED,跟用户再次明确拒绝一样。所以要记得,调用requestPermissions()申请权限并不能保证一定会弹出对话框。

权限申请的最佳实践

注意申请权限要谨慎,如果申请权限太多导致用户反感或者担心隐私安全,则app就可能会被弃用

使用intent实现操作

intent打开的组件所使用的权限相对于本应用来说是间接使用,只要没有直接使用就不必申请了。比如拍照可以通过intent打开系统相机,也可以申请权限操作自定义相机。或者拨打电话,查看联系人,都可以通过适合的intent完成,也可以请求权限直接获取
* 使用权限的优缺点:可以完全根据需求实现界面和操作,但是比较复杂。权限的申请分析同上,需要考虑用户取消权限的情况。
* 使用intent的优缺点:无法定制ui,ui体验由intent打开的app决定,可能是你从没见过的app。如果用户没有设置intent默认打开app,则每次都要弹出对话框选择。

只请求需要的权限

尽可能少请求权限。如果某项功能不是核心功能,则可以通过intent避免申请权限。
* 不一次性过度请求,只在需要时发出相应请求。比如相机应用一启动就申请相机权限是符合用户期望的,但是读取联系人用来分享可以等到
* 分享操作进行的时候才请求。或者也可以提供一个使用向导,在向导后请求所需权限会比较合理。
* 在请求前解释:请求对话框只能显示请求,但是无法显示为什么需要请求,所以可以显示解释。或者甚至提供使用向导展示给用户。

考虑api版本

6.0之前如果app正常安装运行,则表示拥有所有需要的权限,但是6.0开始用户可以运行时允许和取消授权,即使目标API低于23

List permissions and status by group:

$ adb shell pm list permissions -d -g

Grant or revoke one or more permissions:

$ adb shell pm [grant|revoke] <permission-name> ...
0 0
原创粉丝点击