1. 目标
此文章的最终目标:让童鞋们了解6.0动态权限的逻辑,以及学会封装动态权限申请,实现'一句话申请权限'。
2. 前言
在android6.0之前,开发者无需在java代码里进行危险权限的申请,只需在AndroidManifest.xml文件里进行权限声明即可,但从android6.0开始,google为了用户的安全考虑,加入了动态权限机制,危险权限必须在代码里申请,当然,AndroidManifest.xml文件里一样还是要进行声明,别忘了这一点哦。(ps:加入了动态权限,虽然对开发者而言是麻烦了一些,但是对整体的android环境有一定的改善,流氓软件不能像以前那样流氓了。)
3. 正常权限 和 危险权限
Android系统权限分为几个保护级别。需要了解的两个最重要保护级别是 正常权限 和 危险权限:
(1)正常权限:
涵盖应用需要访问其沙盒外部数据或资源,但对用户隐私或其他应用操作风险很小的区域。这些权限在应用安装时授予,运行时不再询问用户。例如: 网络访问、WIFI状态、音量设置等。完整的正常权限列表参考官网 正常权限。
(2)危险权限:
涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如: 读取通讯录、读写存储器数据、获取用户位置等。如果应用声明需要这些危险权限,则必须在运行时明确告诉用户,让用户手动授予。
权限组
Android系统对所有的危险权限进行了分组,称为 权限组 。属于同一组的危险权限将自动合并授予,用户授予应用某个权限组的权限,则应用将获得该权限组下的所有权限(前提是相关权限在 AndroidManifest.xml 中有声明)。
危险权限 和 权限组 列表如下:
(英文版)
(中文版)
注意:在 AndroidManifest.xml 声明过的危险权限对应的权限组可以在系统 “设置” -> “应用” -> “应用信息” -> “权限” 中查看,可以手动授权和取消授权。
4.申请步骤
(1) targetSdkVersion>=23的,需要动态申请;<23不需要动态申请(2018年8月Google要求所有应用面向Android8.0及以上开发,即targetSdkVersion 26+);
(2) 在AndroidManifest.xml中申请你需要的权限,包括普通权限和需要申请的特殊权限。
(3) 开始申请权限,此处分为3部。
a.检查权限,有的话就doSomething,没有就走第2步。
/**
* 检查所有权限是否授权
* @return true,全部已授权,false,全部或者部分未授权
*/
private boolean isAllPermissionGranted() {
boolean isAllGranted = true;
for (int i = 0; i < mPermissions.length; i++) {
if (ContextCompat.checkSelfPermission(this,mPermissions[i]) != PackageManager.PERMISSION_GRANTED) {
isAllGranted = false;
break;
}
}
return isAllGranted;
}
b.申请权限
if(ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.CALL_PHONE)){
//已经拒绝过一次,会有一个不再提示的选项框
new AlertDialog.Builder(this)
.setTitle("权限申请")
.setMessage("提供了解释需要该权限的机会")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermission();
}
})
.setNegativeButton("Cancel", null)
.create()
.show();
}else {
//从未拒绝过
requestPermission();
}
c.处理申请结果,在Activity/Fragment中有回调方法onRequestPermissionsResult()
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE){
//是否全部授权
boolean isAllGranted = true;
for (int grant:grantResults) {
Log.d("grant:",grant+"");
if (grant != PackageManager.PERMISSION_GRANTED){
//一个未通过授权即变为false
isAllGranted = false;
break;
}
}
if (isAllGranted){
//授权成功
call();
}else {
//引导用户去设置里面手动设置权限
openAppDetails();
}
}
}
private void openAppDetails() {
new AlertDialog.Builder(this)
.setMessage("需要拨打电话权限")
.setPositiveButton("手动设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:"+getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
}
})
.setNegativeButton("取消",null)
.create()
.show();
}
https://blog.csdn.net/android2me/article/details/69525975
Android 6.0动态权限介绍与处理详细介绍