一、概述
在对动态权限申请进行详细说明时,还是先大致介绍下6.0后,google对权限的一个归类和划分。在Android M之前,再开发应用的时候,程序员只需要在AndroidManifest.xml文件中进行权限配置即可,这种操作确实比较方便,但是也容让有些程序员为了图方便,一股脑儿的申请很多权限,也不管APP是否能用上。另一方面,对用户而言,一般在安装应用的时候,也不会注意申请了哪些权限,很容易造成用户的数据泄露。所以谷歌从Android M之后,将权限进行了分类,分为普通权限,危险权限和特殊权限。普通权限和以前一样,在AndroidManifest.xml文件配置即可,危险权限就需要程序员更加需要进行动态申请(两个特殊权限再次暂不做讨论)。
危险权限共分为9组,每一组只要其中一个权限授权了,那同一组的其他权限也自动取得授权,具体如下:
group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
group:android.permission-group.PHONE
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
group:android.permission-group.CAMERA
permission:android.permission.CAMERA
group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS
group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO
group:android.permission-group.SMS
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS
二、动态申请权限的方法步骤
总的来说,动态申请权限分为三大步
第一、检测权限是否已经获取
第二、申请获取权限
第三、根据申请反馈的结果(用户是否同意)进行不同的处理
检测是否已经获取到权限,调用checkSelfPermission(String permission)方法即可
final String[] permissions = {Manifest.permission.CAMERA};
// 第一步 检测权限:返回结果如下
//PackageManager.PERMISSION_GRANTED(有权限)
//PackageManager.PERMISSION_DENIED(无权限)
int result = checkSelfPermission(permissions[0]);
根据返回检测结果,做不同处理,如果没有获取到权限,调用requestPermissions(@NonNull String[] permissions, int requestCode)方法获取权限。
这里多啰嗦几句,一般在调用该方法之前,需要先调用shouldShowRequestPermissionRationale(@NonNull String permission)这个方法,判断用户是否已经拒绝过该权限。如果用户在第一次申请的时候,拒绝了该权限,再次申请该权限的时候,该方法就会返回true(默认返回false),这个时候为了增加用户友好体验,可以在此处给用户做一些说明,为什么需要这个权限,希望用户同意等等……,不过此处有坑,后面会详细介绍。
if (result == PackageManager.PERMISSION_GRANTED) {
// 已经具有权限,直接打开相机
startCamera();
} else {
// 第二步 申请权限
// 判断是否需要向用户弹出权限需求说明
if (shouldShowRequestPermissionRationale(permissions[0])) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("提示")
.setMessage("应用需要相机权限才能正常使用, 是否授权")
.setNegativeButton("取消", null)
.setPositiveButton("授权", new DialogInterface.OnClickListener() {
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermissions(permissions, REQUEST_CODE);
}
})
.show();
return;// 结束执行,防止重复请求权限
}
requestPermissions(permissions, REQUEST_CODE);
}
如果是第一次申请权限,则直接弹出申请对话框:
如果
是第二次申请权限,则会弹出提示对话框
对申请结果(用户同意与否)进行监听并处理,重写onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults)这个方法
if (requestCode == REQUEST_CODE && grantResults.length > 0) { // 判断是否有返回结果
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "获取到相机权限, 打开相机", Toast.LENGTH_SHORT).show();
startCamera();
} else {
Toast.makeText(this, "获取相机权限失败", Toast.LENGTH_SHORT).show();
}
}
三、使用过程中遇到的一些坑
在此先将个人已经遇到的一些坑分享给大家
1、动态权限同样需要在 AndroidManifest.xml文件中进行配置。不知道是我某些地方出错还是确实是这样,至少我在使用过程中发现,如果没有在AndroidManifest.xml文件中进行权限配置,同样不能够正常申请权限。所以无论是普通权限还是危险权限,全部都需要在清单文件里面进行配置。
2、shouldShowRequestPermissionRationale(@NonNull String permission)的返回值问题。由于国内android手机厂家的系统几乎都是经过自己定制处理过的,有些手机厂家直接将该方法的返回值确定为false。及无论用户第几次拒绝,都不会返回true。解决办法和问题3解决方法相同如下
3、用户选择不再提示后拒绝权限。如果用户在拒绝权限的时候,选择了不再提示,那以后应用都不会在弹出对框去申请权限,最终造成APP无法正常使用。如果用户不知道是因为自己拒绝了权限造成的,就会以为你的APP很烂,造成用户体验差。一般解决问题2和3的方式就是,在用户选择了拒绝权限的时候,就对用户进行提示,如果需要,同时引导用户去重新授权,我的处理方式,如果用户确定拒绝,则退出应用,如果用户选择重新授权,直接跳转到应该管理的界面,让用户重新授权,代码如下(该Demo里面不含此部分处理)
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("权限提醒")
.setMessage("是否要拒绝权限,如果拒绝,应用将无法正常运行")
.setPositiveButton("拒绝", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
MyApplication.getInstance().exit();
}
})
.setNegativeButton("重设", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(LoginActivity.this)) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}
})
.show();
4、兼容问题:checkSelfPermission和requestPermissions从API 23才加入,低于23版本,需要在运行时判断 或者使用Support Library v4中提供的方法
ContextCompat.checkSelfPermission
ActivityCompat.requestPermissions
ActivityCompat.shouldShowRequestPermissionRationale
四、比较好用的动态权限处理第三方库推荐
个人目前感觉比较好用的有两个库
PermissionsDispatcher gitHub地址
PermissionGen gitHub地址
本文Demo的下载地址 https://github.com/victorcatfish/PermissionsM.git
我也是一个初学和摸索者,如果有不对的地方还望大家多多指正。