官网连接:
https://developer.android.google.cn/guide/topics/permissions/overview#normal-dangerous
从 Android 6.0(API 级别 23)开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予。 Android 6.0系统6.0以前,所有的权限,访问网络的权限,读取SD卡的权限,访问通讯录,拨打电话的权限都在安装的时候系统授予了要安装的应用。在系统运行的时候不需要对权限做任何的处理。用户在安装的时候一般都不知道这些权限用在了什么地方,这样做很不安全。一个应用很容易在一个Service中读取用户所有的通讯录信息发送到服务器上。Android 6.0后的动态权限让我们的系统更加安全,牺牲了用户的方便性,得到的是安全。下图是Android 6.0系统对相机权限的使用。
2. 正常权限 和 危险权限
Android系统权限分为几个保护级别。需要了解的两个最重要保护级别是 正常权限 和 危险权限:
(1)正常权限:
涵盖应用需要访问其沙盒外部数据或资源,但对用户隐私或其他应用操作风险很小的区域。这些权限在应用安装时授予,运行时不再询问用户。例如: 网络访问、WIFI状态、音量设置等。
所有的普通权限:
- 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_IGNORE_BATTERY_OPTIMIZATIONS
- 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
(2)危险权限:
涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如: 读取通讯录、读写存储器数据、获取用户位置等。如果应用声明需要这些危险权限,则必须在运行时明确告诉用户,让用户手动授予。
3. 权限组
Android系统对所有的危险权限进行了分组,称为 权限组 。属于同一组的危险权限将自动合并授予,用户授予应用某个权限组的权限,则应用将获得该权限组下的所有权限(前提是相关权限在 AndroidManifest.xml 中有声明)。
危险权限 和 权限组 列表如下:
二、Android 6.0+危险权限的动态处理
设备系统是 Android 6.0 (API 23) 或更高版本,并且应用的 targetSdkVersion 是 23 或更高版本,则针对在 AndroidManifest.xml 中声明的危险权限,在运行时还需要动态请求用户授权。
//申请权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(this.checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
// 申请一个(或多个)权限,并提供用于回调返回的获取码(用户定义)
requestPermissions( new String[]{Manifest.permission.CALL_PHONE },CALL_REQUEST_CODE);
}else{
callPhone();
}
}else{
callPhone();
}
/**
* 申请权限的回调
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions,grantResults);
switch(requestCode) {
// requestCode即所声明的权限获取码,在checkSelfPermission时传入
case CALL_REQUEST_CODE:
if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 获取到权限,作相应处理(调用定位SDK应当确保相关权限均被授权,否则可能引起定位失败)
callPhone();
} else{
ShowToast.showToast(R.string.please_get_call_phone_permission,context);
}
break;
}
}