动态权限
动态权限适配是 Android 6.0 最先开始的,也是 Android 系统对开发者影响最大的改动之一。系统权限主要分为两类,正常权限和危险权限。不管哪个版本的android,你应用中所用到的所有权限,不管是正常权限还是危险权限,都需要在应用Manifest中申明。你的目标SDK(targetSdkVersion)是23以及23以上版本:应用必须在Manifest中罗列出所有的权限,并且在程序运行时,它必须请求用户授予每一个危险权限,此时用户可以授予或者拒绝每一个权限,并且应用程序可以继续运行有限的功能,即使用户拒绝了权限请。在 Android 6.0 ~ Android 8.0中,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用,即对于同一组内的权限,只要有一个被同意,其他的都会被同意。在 Android 8.0 之后,此行为已被纠正。系统只会授予应用明确请求的权限。然而一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准,但是若没有请求相应的权限而进行操作的话就会出现应用 crash 的情况
危险权限分组说明
权限组 | 权限名称 |
---|---|
CALENDAR | android.permission.READ_CALENDAR |
android.permission.WRITE_CALENDAR | |
CAMERA | android.permission.CAMERA |
CALENDAR | android.permission.READ_CALENDAR |
android.permission.WRITE_CALENDAR | |
CONTACTS | android.permission.READ_CONTACTS |
android.permission.WRITE_CONTACTS | |
android.permission.GET_ACCOUNTS | |
LOCATION | android.permission.ACCESS_FINE_LOCATION |
android.permission.ACCESS_COARSE_LOCATION | |
MICROPHONE | android.permission.RECORD_AUDIO |
PHONE | android.permission.READ_PHONE_STATE |
android.permission.CALL_PHONE | |
android.permission.READ_CALL_LOG | |
android.permission.ADD_VOICEMAIL | |
android.permission.WRITE_CALL_LOG | |
android.permission.USE_SIP | |
android.permission.PROCESS_OUTGOING_CALLS | |
android.permission.ANSWER_PHONE_CALLS(8.0新增) | |
android.permission.READ_PHONE_NUMBERS(8.0新增) | |
SENSORS | android.permission.BODY_SENSORS |
SMS | android.permission.SEND_SMS |
android.permission.RECEIVE_SMS | |
android.permission.READ_SMS | |
android.permission.RECEIVE_WAP_PUSH | |
android.permission.RECEIVE_MMS | |
STORAGE | android.permission.READ_EXTERNAL_STORAGE |
android.permission.WRITE_EXTERNAL_STORAGE |
AndroidManifest.xml清单配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
...
</manifest>
动态申请
首先设置app下面build.gradle中的targetSdkVersion为23.
apply plugin: 'com.android.application'
android {
...
defaultConfig {
...
targetSdkVersion 23
}
}
然后在具体的需要获取权限的使用场景之前进行权限判断。我们的应用为了图省事,应用启动的时候一次性把应用需要的所有危险权限都申请了,但其实这种是不可取的,对用户来说体验非常不好。最好的方式就是需要的时候再去判断有没有权限,再去申请相应的权限。比如需要拍照,就在点击拍照之前进行申请,而不是一启动就申请。
下面是在代码中动态申请的示例
private boolean isHasPermissions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//申请的权限列表
private String[] permissions = {Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 权限是否已经授权 GRANTED---授权 DINIED---拒绝
String[] diniedPermissions = lacksPermissions(permissions);
if (diniedPermissions != null && diniedPermissions.length > 0) {
// 如果没有授予该权限
ActivityCompat.requestPermissions(this, diniedPermissions, 21);
isHasPermissions = false;
} else {
isHasPermissions = true;
}
} else {
isHasPermissions = true;
}
}
/**
* 检查列表中的权限是否通过
*
* @param permissions 待验证的权限列表
* @return 返回没有通过的权限
*/
public String[] lacksPermissions(String... permissions) {
ArrayList<String> permissionList = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission)
== PackageManager.PERMISSION_DENIED) {
permissionList.add(permission);
}
}
return permissionList.toArray(new String[permissionList.size()]);
}
/**
* 请求获取权限后会执行此回调方法
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
String[] diniedPermissions = lacksPermissions(permissions);
if (diniedPermissions != null && diniedPermissions.length > 0) {
isHasPermissions = false;
//用户拒绝了授权,可以进一步提示用户授权,否则不能进行后续操作
} else {
isHasPermissions = true;
//已经授权,执行后续操作
}
}