Android6.0运行时权限处理

概述

从Android6.0(API23)开始,用户可以在应用运行时向其授予权限,而不是在应用安装时授予。

在Android6.0以前,应用安装会给出应用声明的权限列表,用户如果要继续安装,就得接受全部的权限,让用户很无奈;

从Android6.0开始的运行时权限,让用户可以对应用的功能进行更多的控制,例如,用户可以选择为相机应用提供相机的访问权限,而不提供设备位置的访问权限。用户可以随时进入应用的“Settings”开关权限。

兼容性

  • 如果设备的系统版本是Android5.1或者更低的版本,或者应用的targetSdkVersion为22或更低:如果您在清单中列出了危险权限,则用户必须在安装应用时授予此权限;如果用户不授予此权限,系统根本不会安装应用。
  • 如果设备的系统版本是Android6.0或者更高的版本,或者应用的targetSdkVersion为23或更高:应用必须在清单中列出权限,并且它必须在运行时请求其需要的每项危险权限。用户可以授权或拒绝每项权限,且即使用户拒绝权限请求,应用仍可以继续运行有限的功能。

权限分类

系统权限分为两类:正常权限和危险权限

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
  • FOREGROUND_SERVICE
  • GET_PACKAGE_SIZE
  • INSTALL_SHORTCUT
  • INTERNET
  • KILL_BACKGROUND_PROCESSES
  • MANAGE_OWN_CALLS
  • MODIFY_AUDIO_SETTINGS
  • NFC
  • READ_SYNC_SETTINGS
  • READ_SYNC_STATS
  • RECEIVE_BOOT_COMPLETED
  • REORDER_TASKS
  • REQUEST_COMPANION_RUN_IN_BACKGROUND
  • REQUEST_COMPANION_USE_DATA_IN_BACKGROUND
  • REQUEST_DELETE_PACKAGES
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
  • SET_ALARM
  • SET_WALLPAPER
  • SET_WALLPAPER_HINTS
  • TRANSMIT_IR
  • USE_FINGERPRINT
  • VIBRATE
  • WAKE_LOCK
  • WRITE_SYNC_SETTINGS

Dangerous Permissions

危险权限,会授予应用访问用户机密数据的权限。如果您的应用在清单中列出了危险权限,则用户必须明确批准您的应用使用这些权限。

危险权限是按权限组来划分,如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。

例如,你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。

NOTE:对应申请时弹出的Dialog上面的文本说明也是对整个权限组的说明,而不是单个权限。

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

运行时权限处理

检查权限

如果你的应用需要危险权限,则每次执行需要这一权限的操作时都必须检查自己是否具有该权限。因为用户可以自由的开关此权限,所以,即使应用昨天使用了相机,它不能假设自己今天仍具有该权限。

ContextCompat.checkSelfPermission:用于检测某个权限是否已经被授予

1
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);

说明:如果应用具有此权限,方法将返回PackageManager.PERMISSION_GRANTED,并且允许应用可以继续操作。如果应用不具有此权限,方法将返回PackageManager.PERMISSION_DENIED,且应用必须明确向用户要求权限。

请求权限

如果应用尚无所需的权限,则应用必须调用requestPermissions()方法,来请求适当的权限。

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

说明:从第二个参数可以看出,支持一次性请求多个权限,系统会通过对话框逐一询问用户是否授权。

处理权限请求响应

当应用请求权限时,系统将向用户显示一个对话框。当用户响应时,系统将调用应用的onRequestPermissionsResult()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
public 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
}
}

解释权限的用途

如果用户继续尝试使用需要某项权限的功能,但拒绝权限请求,则可能表明用户不理解应用为什么需要此权限才能提供相关的功能,这时就可以显示解释给用户。

shouldShowRequestPermissionRationale()

如果应用之前请求过此权限但用户拒绝了请求,此方法返回true

如果用户过去拒绝了权限请求,并在权限请求系统对话框选择了Don't ask again选项,此方法返回false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (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.
}
}

AndPermission的使用

AndPermission是严格按照Android系统的运行时权限设计的,并最大限度上兼容了国产手机。

库地址:https://github.com/yanzhenjie/AndPermission

导入

1
implementation 'com.yanzhenjie:permission:2.0.0-rc12'

使用

申请权限
1
2
3
4
5
6
7
8
9
10
AndPermission.with(this)
.runtime()
.permission(Permission.Group.STORAGE)
.onGranted(permissions -> {
// Storage permission are allowed.
})
.onDenied(permissions -> {
// Storage permission are not allowed.
})
.start();
权限被拒绝,说明权限用途
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private Rationale mRationale = new Rationale() {
@Override
public void showRationale(Context context, List<String> permissions,
RequestExecutor executor) {
// 这里使用一个Dialog询问用户是否继续授权。

// 如果用户继续:
executor.execute();

// 如果用户中断:
executor.cancel();
}
};

AndPermission.with(this)
.runtime()
.permission(Permission.WRITE_EXTERNAL_STORAGE)
.rationale(mRationale)
.onGranted(...)
.onDenied(...)
.start();
权限总是被拒绝,前往设置页授权
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
AndPermission.with(this)
.runtime()
.permission(...)
.rationale(...)
.onGranted(...)
.onDenied(new Action() {
@Override
public void onAction(List<String> permissions) {
if (AndPermission.hasAlwaysDeniedPermission(context, permissions)) {
// 这些权限被用户总是拒绝。
// 这里使用一个Dialog展示没有这些权限应用程序无法继续运行,询问用户是否去设置中授权。
AndPermission.with(this)
.runtime()
.setting()
.onComeback(new Setting.Action() {
@Override
public void onAction() {
// 用户从设置回来了。
}
})
.start();
}
}
})
.start();

参考链接

  1. Android 6.0 运行时权限处理完全解析
  2. Android 6.0 运行时权限管理最佳实践
  3. Android 6.0运行时权限讲解
  4. 在运行时请求权限
  5. Android 6.0 变更
  6. 权限最佳做法
  7. AndPermission
文章目录
  1. 1. 概述
  2. 2. 兼容性
  3. 3. 权限分类
    1. 3.1. Normal Permissions
    2. 3.2. Dangerous Permissions
  4. 4. 运行时权限处理
    1. 4.1. 检查权限
    2. 4.2. 请求权限
    3. 4.3. 处理权限请求响应
    4. 4.4. 解释权限的用途
  5. 5. AndPermission的使用
    1. 5.1. 导入
    2. 5.2. 使用
      1. 5.2.1. 申请权限
      2. 5.2.2. 权限被拒绝,说明权限用途
      3. 5.2.3. 权限总是被拒绝,前往设置页授权
  6. 6. 参考链接
,