Android M(6.0)运行时权限申请及遇到的坑

一、概述

        在对动态权限申请进行详细说明时,还是先大致介绍下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
我也是一个初学和摸索者,如果有不对的地方还望大家多多指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值