Android 6.0适配

94 阅读2分钟

动态权限

动态权限适配是 Android 6.0 最先开始的,也是 Android 系统对开发者影响最大的改动之一。系统权限主要分为两类,正常权限和危险权限。不管哪个版本的android,你应用中所用到的所有权限,不管是正常权限还是危险权限,都需要在应用Manifest中申明。你的目标SDK(targetSdkVersion)是23以及23以上版本:应用必须在Manifest中罗列出所有的权限,并且在程序运行时,它必须请求用户授予每一个危险权限,此时用户可以授予或者拒绝每一个权限,并且应用程序可以继续运行有限的功能,即使用户拒绝了权限请。在 Android 6.0 ~ Android 8.0中,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用,即对于同一组内的权限,只要有一个被同意,其他的都会被同意。在 Android 8.0 之后,此行为已被纠正。系统只会授予应用明确请求的权限。然而一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准,但是若没有请求相应的权限而进行操作的话就会出现应用 crash 的情况

危险权限分组说明

权限组权限名称
CALENDARandroid.permission.READ_CALENDAR
android.permission.WRITE_CALENDAR
CAMERAandroid.permission.CAMERA
CALENDARandroid.permission.READ_CALENDAR
android.permission.WRITE_CALENDAR
CONTACTSandroid.permission.READ_CONTACTS
android.permission.WRITE_CONTACTS
android.permission.GET_ACCOUNTS
LOCATIONandroid.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION
MICROPHONEandroid.permission.RECORD_AUDIO
PHONEandroid.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新增)
SENSORSandroid.permission.BODY_SENSORS
SMSandroid.permission.SEND_SMS
android.permission.RECEIVE_SMS
android.permission.READ_SMS
android.permission.RECEIVE_WAP_PUSH
android.permission.RECEIVE_MMS
STORAGEandroid.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;
    	//已经授权,执行后续操作
    }
}