Android6.0(SDK23)以上对权限进行了划分:normal permission 和 dangerous permission,即普通权限和危险权限。像存储、相机、位置等都属于危险权限,如果你的应用涉及到了这些权限,且APP运行在Android6.0及以上的手机上,就需要处理运行时权限的问题了。
先看下面一组对应关系:
targetSDKVersion < 23 & API(手机系统) < 6.0:安装时默认获得权限,且用户无法在安装App之后取消权限。
targetSDKVersion >= 23 & API(手机系统) < 6.0:安装时默认获得权限,且用户无法在安装App之后取消权限。
targetSDKVersion < 23 & API(手机系统) >= 6.0:安装时默认获得权限,但是用户可以在安装App完成后动态取消授权。
targetSDKVersion >= 23 & API(手机系统) >= 6.0:安装时不会获得权限,可以在运行时向用户申请权限。用户授权以后仍然可以在设置界面中取消授权。
可见当手机系统版本<6.0时,会默认获取AndroidManifest.xml中声明的所有权限,这时没有任何问题。
但当手机系统版本>=6.0时,特别是开发环境targetSDKVersion >= 23时,需要向用户动态申请【危险权限】(普通权限不受影响)。
遇到这种情况处理方法如下:
第一步,仍然需要把所需权限写人到AndroidManifest.xml,包括普通权限和危险权限。
第二步,在需要危险权限的地方动态申请。
// 权限请求码
private final int PERMISSION_REQUEST_CODE= 1;
// 权限集合
private String[] PERMISSIONS = new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_COARSE_LOCATION
};
public void mapStartLocation(View view) {
if(lacksPermissions(PERMISSIONS)) {// 缺少权限,则向用户申请权限
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_REQUEST_CODE);
}else {// 拥有权限,直接进行业务操作
mLocationClient.startLocation();
}
}
// 判断权限集合
public boolean lacksPermissions(String... permissions) {
for(String permission : permissions) {
if(ContextCompat.checkSelfPermission(PermissionsActivity.this, permission)
== PackageManager.PERMISSION_DENIED) {
return true;
}
}
return false;
}
第三步,在请求权限回调函数处进行判断处理。
// 请求运行时权限回调函数
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if(requestCode == PERMISSION_REQUEST_CODE&&hasAllPermissionsGranted(grantResults)) {
// 许可所有权限,进行业务操作
mLocationClient.startLocation();
}
super.onRequestPermissionsResult(requestCode,permissions, grantResults);
}
// 含有全部的权限
protected boolean hasAllPermissionsGranted(@NonNull int[] grantResults) {
for (int grantResult : grantResults) {
if (grantResult == PackageManager.PERMISSION_DENIED) {
return false;
}
}
return true;
}
事情到此并没有结束,如果用户选择彻底禁止弹出权限请求,那么下次打开应用时,用上面的方法还是无法获取所需权限。不用担心,Google已经考虑到了这个问题并给开发人员提供了接口ActivityCompat.shouldShowRequestPermissionRationale,接口用法如下:
boolean isTip = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE); if (isTip) {// 表明用户没有彻底禁止弹出权限请求 ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_REQUEST_CODE); } else {// 表明用户已经彻底禁止弹出权限请求 // 这里一般会提示用户进入权限设置界面 }