6.0权限的那些事

/ 2评 / 0

前言

随着Android版本的升级,Android系统也越来越完善,在Android 6.0版本(SdkVersion 23),Android为我们带来了全新的权限申请机制,对于部分高危权限应用必须动态申请才能继续操作

下面,我就来详细介绍下Android 6.0动态权限的那些事。

简单的说明

在Android 6.0之前:对于应用权限管理是在应用安装的时候以列表的形式展示给用户,用户选择安装则表示同意了这些权限,如果不同意就只能选择取消安装(部分国产ROM可以在这个阶段选择给与或者拒绝)。

这样就带来一个安全问题,如果用户没有详细看权限列表直接安装了,这样恶意应用就可能获取到很多危险权限。比如读取通讯录等。

Android 6.0及以后:如果你的应用targetSdkVersion < 23,那么权限管理机制与Android 6.0之前的操作一样,这样的目的是为了防止旧app在Android 6.0上面因为权限机制的变化崩溃。如果你的应用targetSdkVersion >= 23,那么你就必须动态申请高危权限,否则app会直接崩溃。

那么是不是只要在开发的时候将targetSdkVersion设置的比23小那么就一切ok呢?

如果暂时还不想适配6.0运行时权限,但是又想要app可以在6.0及以上机型运行,那我们可以将目标版本改为23以下,如:targetSdkVersion 22。但是由于6.0机型在设置中可以进行权限管理,用户可以取消该应用的某个权限,但是app并不知道该权限被取消,此时app会崩溃(合理的try可以避免)。

权限的分类

Android 6.0将权限分为一般权限和危险权限两种,一般权限跟以前一样在AndroidManifest直接声明即可,危险权限需要开发者不仅需要声明而且在代码中还要动态申请权限。

Normal Permissions

ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS

Dangerous Permissions

group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS

group: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_VOICEMAIL

group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
  permission:android.permission.CAMERA

group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO

group: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

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

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

相关API

检查是否拥有某权限:ActivityCompat.checkSelfPermission(@NonNull Context context, @NonNull String permission)

申请权限:ActivityCompat.requestPermissions(final @NonNull Activity activity,final @NonNull String[] permissions, final int requestCode)

申请权限结果回调:覆写Activity中的onRequestPermissionsResult方法。

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
}

检查用户拒绝权限的时候是否点击了不在提醒:ActivityCompat.shouldShowRequestPermissionRationale(@NonNull Activity activity,@NonNull String permission)

最佳实战

doBackUp()是一个备份联系人的方法,由于读取联系人是高危权限,所以必须先验证是否拥有权限,如果没有权限则申请权限以后继续操作,当用户拒绝权限以后通过ActivityCompat.shouldShowRequestPermissionRationale方法验证是否选择了不再提示然互进行相应操作。

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == 10) {
        //用户授予了权限
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            mContactOperate.doBackup(ContactsUtil.queryAllContacts(getContentResolver()));
        } else {
            //权限被用户拒绝了,但是并没有选择不再提示,也就是说还可以继续申请
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) {
                //提示用户必须给与权限才能继续操作
                Snackbar snackbar = Snackbar.make(mDrawerLayout, "需要授予权限才能继续操作", Snackbar.LENGTH_LONG);
                snackbar.setAction("重试", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //继续申请权限
                        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 10);
                    }
                });
                snackbar.show();
            } else {
                //用户拒绝并选择了不在提示,这里可以提示用户然后打开权限设置界面
                ToastUtil.show(this, R.string.no_permission_read_contacts);
            }
        }
    }
}
  1. Leridy_Lei说道:

    安卓都已经出到 8 了。。。你还在讨论 6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注