Android 6.0运行时权限

来源:互联网 发布:fuse linux 编辑:程序博客网 时间:2024/06/11 14:19

一、运行时权限的变化及特点

在6.0以下的系统,安装的时候有一个权限列表,一般情况下点了安装就都给应用授权了相应的权限。在6.0以上,我们安装APP也是直接安装了,不用管权限,一些比较隐私的权限,安装的时候是自己设置成询问的,比如定位啊,录音,摄像头之类的,在我们应用运行的途中,需要某一个隐私权限,就要弹窗询问,让用户授权,这就是运行时权限。
新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。

  • Normal Permissions:
ACCESS_LOCATION_EXTRA_COMMANDSACCESS_NETWORK_STATEACCESS_NOTIFICATION_POLICYACCESS_WIFI_STATEBLUETOOTHBLUETOOTH_ADMINBROADCAST_STICKYCHANGE_NETWORK_STATECHANGE_WIFI_MULTICAST_STATECHANGE_WIFI_STATEDISABLE_KEYGUARDEXPAND_STATUS_BARGET_PACKAGE_SIZEINSTALL_SHORTCUTINTERNETKILL_BACKGROUND_PROCESSESMODIFY_AUDIO_SETTINGSNFCREAD_SYNC_SETTINGSREAD_SYNC_STATSRECEIVE_BOOT_COMPLETEDREORDER_TASKSREQUEST_INSTALL_PACKAGESSET_ALARMSET_TIME_ZONESET_WALLPAPERSET_WALLPAPER_HINTSTRANSMIT_IRUNINSTALL_SHORTCUTUSE_FINGERPRINTVIBRATEWAKE_LOCKWRITE_SYNC_SETTINGS
  • Dangerous Permissions:
group:android.permission-group.CONTACTS  permission:android.permission.WRITE_CONTACTS  permission:android.permission.GET_ACCOUNTS  permission:android.permission.READ_CONTACTSgroup:android.permission-group.PHONE  permission:android.permission.READ_CALL_LOG  permission:android.permission.READ_PHONE_STATE  permission:android.permission.CALL_PHONE  permission:android.permission.WRITE_CALL_LOG  permission:android.permission.USE_SIP  permission:android.permission.PROCESS_OUTGOING_CALLS  permission:com.android.voicemail.permission.ADD_VOICEMAILgroup:android.permission-group.CALENDAR  permission:android.permission.READ_CALENDAR  permission:android.permission.WRITE_CALENDARgroup:android.permission-group.CAMERA  permission:android.permission.CAMERAgroup:android.permission-group.SENSORS  permission:android.permission.BODY_SENSORSgroup:android.permission-group.LOCATION  permission:android.permission.ACCESS_FINE_LOCATION  permission:android.permission.ACCESS_COARSE_LOCATIONgroup:android.permission-group.STORAGE  permission:android.permission.READ_EXTERNAL_STORAGE  permission:android.permission.WRITE_EXTERNAL_STORAGEgroup:android.permission-group.MICROPHONE  permission:android.permission.RECORD_AUDIOgroup:android.permission-group.SMS  permission:android.permission.READ_SMS  permission:android.permission.RECEIVE_WAP_PUSH  permission:android.permission.RECEIVE_MMS  permission:android.permission.RECEIVE_SMS  permission:android.permission.SEND_SMS  permission:android.permission.READ_CELL_BROADCASTS

可以通过adb shell pm list permissions -d -g进行查看。

看到上面的dangerous permissions,会发现一个问题,好像危险权限都是一组一组的,恩,没错,的确是这样的,

那么有个问题:分组对我们的权限机制有什么影响吗?

的确是有影响的,如果app运行在Android 6.x的机器上,对于授权机制是这样的。如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。

不过需要注意的是,不要对权限组过多的依赖,尽可能对每个危险权限都进行正常流程的申请,因为在后期的版本中这个权限组可能会产生变化。

二、相关API

注意:还是需要在AndroidManifest文件中添加应用需要的权限。
1.检查权限

if (ContextCompat.checkSelfPermission(thisActivity,                Manifest.permission.READ_CONTACTS)        != PackageManager.PERMISSION_GRANTED) {}else{    //}

这里涉及到一个API,ContextCompat.checkSelfPermission,主要用于检测某个权限是否已经被授予,方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。当返回DENIED就需要进行申请授权了。

2.申请权限

 ActivityCompat.requestPermissions(thisActivity,                new String[]{Manifest.permission.READ_CONTACTS},                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

该方法是异步的,第一个参数是Context;第二个参数是需要申请的权限的字符串数组;第三个参数为requestCode,主要用于回调的时候检测。可以从方法名requestPermissions以及第二个参数看出,是支持一次性申请多个权限的,系统会通过对话框逐一询问用户是否授权。

3.处理权限申请回调

@Overridepublic void onRequestPermissionsResult(int requestCode,        String permissions[], int[] grantResults) {    switch (requestCode) {        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {            // 如果询问授权被取消,这个results数组就为空.grantResults存放的是授权结果            if (grantResults.length > 0                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                // GRANTED就是被授权了            } else {                // 否则权限被拒绝            }            return;        }    }}

ok,对于权限的申请结果,首先验证requestCode定位到你的申请,然后验证grantResults对应于申请的结果,这里的数组对应于申请时的第二个权限字符串数组。如果你同时申请两个权限,那么grantResults的length就为2,分别记录你两个权限的申请结果。如果申请成功,就可以做你的事情了~

4.当第一次被拒绝后,需要调用的API

if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,        Manifest.permission.READ_CONTACTS))    //如果第一次授权用户拒绝了,再次需要授权的时候就进到这里,进行解释,这里第一次不会进入   //这里一般用个dialog进行解释,为什么要用这个权限,然后可以帮助用户跳转到系统设置界面   //开启权限}

这个API主要用于给用户一个申请权限的解释,该方法只有在用户在上一次已经拒绝过你的这个权限申请。也就是说,用户已经拒绝一次了,你又要弹个授权框,你需要给用户一个解释,为什么要授权,则使用该方法。

三、结合起来

// 检查权限if (ContextCompat.checkSelfPermission(thisActivity,                Manifest.permission.READ_CONTACTS)        != PackageManager.PERMISSION_GRANTED) {    //判断用户拒绝过没有,拒绝过,就进到这里面    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,            Manifest.permission.READ_CONTACTS)) {        //如果第一次授权用户拒绝了,再次需要授权的时候就进到这里,进行解释,这里第一次不会进入        //这里一般用个dialog进行解释,为什么要用这个权限,然后可以帮助用户跳转到系统设置界面        //开启权限    } else {        //没拒绝过,也就是说权限还在询问状态        //那么我们询问用户授权        ActivityCompat.requestPermissions(thisActivity,                new String[]{Manifest.permission.READ_CONTACTS},                MY_PERMISSIONS_REQUEST_READ_CONTACTS);    }}.........    /**    * Activity父类的方法,询问是否授权的回调    */    @Override    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)    {        if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE)        {            if (grantResults[0] == PackageManager.PERMISSION_GRANTED)            {                //授权了            } else {               //拒绝了            }            return;        }        super.onRequestPermissionsResult(requestCode, permissions, grantResults);    }

参考:
http://blog.csdn.net/lmj623565791/article/details/50709663