手机移动程序开发Android开发Android知识

Android6.0新应用权限管理机制详解

2017-01-20  本文已影响0人  冰鉴IT

随着Android系统的不断升级,Android系统在系统安全这一块也有了一定的提升,比如在Android5.0之前,用户安装任何应用都必须无条件接受该应用在AndroidManifest.xml文件中声明的权限,否则就只能不安装此应用,这也给了一些别有用心的应用可乘之机,用户的隐私也没法得到保证。到了Android5.0开始,用户在安装应用时会出现一个复选框,让用户选择授予该应用的一些权限,不选择则该应用不会拥有该权限。进入Android6.0以后,Google进一步对权限进行了控制,对于一些危险权限,必须在使用时动态申请,由用户授权之后,应用才会拥有该权限,这更加加强了应用的安全性。但这个变化也使得我们以前可以正常运行的应用受到了一定的影响,我们必须对其做一定的适配才能保证我们的应用正常运行,下面我们就来一起学习一下Android6.0的权限管理机制。

一、正常权限和危险权限

下面是Android官网对正常权限危险权限的解释:

除了上面说的正常权限和危险权限,还有一个权限组的概念需要了解,权限组简单点理解就是讲权限进行分组,比如READ_CALENDAR权限和WRITE_CALENDAR权限属于CALENDAR这个组。任何权限都可属于一个权限组,包括正常权限和应用定义的权限。但权限组仅当权限危险时才影响用户体验。可以忽略正常权限的权限组,所以可以说所有危险的 Android 系统权限都属于权限组。

下面列出危险权限及其所属的组:

权限组 权限
CALENDAR READ_CALENDAR
WRITE_CALENDAR
CAMERA CAMERA
CONTACTS READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
LOCATION ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
MICROPHONE RECORD_AUDIO
PHONE READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
SENSORS BODY_SENSORS
SMS SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
STORAGE READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

除了上面的表,我们还可以在命令行中查看危险权限及其所属的组,在命令行中输入以下内容即可得到结果:

adb shell pm list permissions -g -d

二、应用请求危险权限的处理

下面我们说说应用在请求危险权限时系统的处理,如果设备运行的是 Android 6.0(API 级别 23),并且应用的 targetSdkVersion 是 23 或更高版本,则当用户请求危险权限时系统会发生以下行为:

上面是Android官网的介绍,从中可以看到很重要的一点 系统只告诉用户应用需要的权限组,而不告知具体权限

三、代码实战权限管理机制

上面说了那么多理论,现在就开始真正的实战,其实就简单的下面几步即可完成,我们下面以申请打电话权限为例:

1 . 在AndroidManifest.xml文件中添加需要的权限(适配Android6.0以下的系统)

AndroidManifest.xml文件中添加如下权限

<uses-permission android:name="android.permission.CALL_PHONE"/>

2 . 检查危险权限

我们在开始打电话之前必须先要检查我们是否拥有打电话的权限,对于正常的权限,系统默认是授予的,但对于打电话这种危险权限我们就必须先进行检查,此处调用ContextCompat.checkSelfPermission()方法进行检查,如果检查的结果是用户已经授予了我们此权限,那我们就可以直接调用打电话的逻辑,如果没有,那我们必须进行权限申请。

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
        != PackageManager.PERMISSION_GRANTED){
    //做权限申请处理
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, CALL_PHONE_REQUEST_CODE);
}else{
    //用户已经授权,直接处理业务逻辑打电话
    doCallPhone();
}

3 . 申请授权

可以看出我们上面使用ActivityCompat.requestPermissions()方法申请权限,此方法的第二个参数可以传入一个权限数组,我们可以一次性申请多个权限,第三个参数是一个请求码,用于我们在下一步中根据申请的结果做回调处理。

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, CALL_PHONE_REQUEST_CODE);

4 . 处理申请回调

我们通过重写onRequestPermissionsResult()方法来处理回调结果

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode){
        case CALL_PHONE_REQUEST_CODE:
            //打电话权限回调处理
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
                //打电话权限被授予
                doCallPhone();
            }else {
                //本次拒绝了权限请求,提示用户权限未被授予
                Toast.makeText(this, "权限申请失败", Toast.LENGTH_SHORT).show();
            }
            break;
        default:
            break;
    }
}

上面的requestCode就是我们在申请权限时提供的请求码,grantResults中存放着我们每个权限所对应的申请结果,由于我们只申请了一个权限,所以grantResults[0]即可。

当然,如果你向用户申请一个权限,而用户又拒绝了你的权限,等下次用户申请的时候还是会弹出用户授权窗口,这个时候你或许想更加清楚地给用户解释一下你为什么使用该权限,这个时候就需要用到ActivityCompat.shouldShowRequestPermissionRationale()这个方法。

这个方法会在应用首次安装时返回false,当用户拒绝了一次你的权限后也会返回true

注:当用户点击了授权窗口上的不再询问复选框时,该方法会返回false,你可以根据用户的行为来做出一些反应,但一般的权限申请窗口都对所申请的权限有一定的说明,除非特别情况,我们没有必要自己进行权限的说明解释。

四、更加优雅的实现权限申请及管理

说了上面那么多,你会发现权限申请最主要的就那么几步,但我们不能总是在每次需要申请的时候重复写代码,这个时候我们就可以去看看别人封装的库,其实也可以自己进行封装,下面推荐两个PermissionGenMPermissions

上面的两个库都有详细的使用方法,这里不再赘述,第一个库是基于运行时注解,使用时会影响性能,第二个库是基于编译时注解,对性能不会有影响。

上一篇 下一篇

猜你喜欢

热点阅读