Android6.0运行时权限申请

1.简介

在Android6.0之前版本,权限请求较为简单,仅在用户安装app时将自己需要使用的所有权限列出来告知用户,若用户授权,则app安装后可随时使用该权限。自6.0开始,一些涉及用户隐私的敏感权限需在使用时动态申请,且用户可选择授权或拒绝。当然,权限的改进对用户而言是好事,毕竟更能保护用户隐私。但对于开发者而言,也多了一项动态权限申请的工作

2.权限分类

对开发者而言,权限则主要分为以下两类:
1)普通权限(normal permissions): 只需在manifest中注册
2)危险权限(dangerous permissions):仍需在manifest中注册,但具体授权分以下几种情况

targetSdk<23 targetSdk>=23
手机系统<23 安装时默认获得权限且用户无法在安装后取消权限 安装时默认获得权限且用户无法在安装后取消权限
手机系统>=23 安装时默认获得权限,但用户可在安装后取消授权( 取消时手机会提示用户该APP是为旧版手机打造,让用户谨慎操作 ) 安装时不会获得权限而需在运行时向用户动态申请。用户授权后仍可在设置界面中取消,取消授权后在app运行过程中可能会出现crash

由上表可知当APP的targetSdk>=23且运行在Android>=6.0(API23)的手机上时必须使用动态申请权限


具体危险权限如下:

危险权限.png

3.运行时权限申请(使用系统提供的API)

1)权限检查

对于权限检查,Android提供了以下3种方式
1.ContextCompat#checkSelfPermission
2.Context#checkSelfPermission
3.PermissionChecker#checkSelfPermission

需注意的是若应用targetSdk<23,则第1、2种方式返回的永远是PERMISSION_GRANTED,即永远返回已授权。根据本文上面内容知当targetSdk<23时,应用虽在安装时就获得授权,但若运行在>=Android6.0的手机上时,用户可在安装后取消授权,此时就不能使用第1、2种方式来检查权限,而需使用第3种

public static boolean checkSelfPermission(String permission, Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        //getTargetVersion是判断app的targetSdk的方法
        if (getTargetVersion(context) >= Build.VERSION_CODES.M) { 
            //应用的targetSdk>=23则使用Context#checkSelfPermission(permission)        
            return context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
        } else {
            //若targetSdk<23则使用PermissionChecker#checkSelfPermission
            return PermissionChecker.checkSelfPermission(context, permission) == PermissionChecker.PERMISSION_GRANTED;
        }
    } else {//手机版本低于6.0的,安装后即授权且用户无法取消
        return true;
    }
}

2)请求权限

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 
requestCode);

注意:1.Fragment中请求需使用自己的requestPermissions方法

3)处理请求结果

请求权限后系统会回调申请权限的Activity的onRequestPermissionsResult(),若使用的是Fragment的requestPermissions方法,则回调对应Fragment的onRequestPermissionsResult()

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode != this.requestCode || grantResults.length = 0) {
            return;
        }
        for (int i = 0; i < grantResults.length; i++) {
            String permission = permissions[i];
            if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, permission + "已被授权", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, permission + "已被拒绝", Toast.LENGTH_SHORT).show();
                if (shouldShowRequestPermissionRationale(permission)) {
                    //请求被用户拒绝但用户未勾选不再询问框,可继续请求权限
                } else {
                    //请求被用户拒绝且用户勾选了不再询问框,需要用户前往设置中授权
                }
            }
        }
    }

4)总结

用系统提供的api进行申请步骤较为繁琐,且请求和处理代码不在相同位置,代码量多了的话可读性变差。那有没有什么好的方法既能简化流程提高可读性又能避免以上第二种情况呢?答案是肯定的,著名基佬交流网站github上就有丰富的权限请求库供各位客官享用!

4.使用EasyPermissions进行权限申请

1)特点

  • 链式操作
  • 请求前会自动检查是否已被授予 (这样在请求前就不必再进行权限检查了)
  • 若请求的权限未在manifest中注册,将抛出明确的异常 (请求未在manifest注册的权限将导致不弹出dialog而直接返回false,有时我们可能对此十分懵逼,因为这既不报错也不弹出dialog代码也OK就是请求失败,可能要很久才反应过来忘了在manifest中注册)
  • 自动重试(可配置项),配置该选项后若请求被拒但用户未勾选不再提示框时会自动重试直到用户授权或勾选不再提示框

2)依赖

A.在项目根build.gradle中

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

B.添加依赖

dependencies {
    implementation 'com.github.Ficat:EasyPermissions:v2.1.0'
}

3)使用

//requestEach方式
EasyPermissions
   .with(activity)
   .requestEach(Manifest.permission.CAMERA)
   .result(new RequestEachExecutor.ResultReceiver() {
       @Override
       public void onPermissionsRequestResult(Permission permission) {
           String name = permission.name;
           if (permission.granted) {
               //name权限被授予
           } else {
               if (permission.shouldShowRequestPermissionRationale) {
                   //name权限被拒绝但用户未勾选不再提示框,可继续请求
               } else {
                   //name权限被拒绝且用户勾选了不再提示框
                   //此时不能再次请求了,而需要user前往设置界面手动授权
                   EasyPermissions.goToSettingsActivity(activity);
               }
           }
       }
   });


//request方式,请求的所有权限被用户授权后返回true,否则返回false  
EasyPermissions
    .with(activity)
    .request(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE)
    .autoRetryWhenUserRefuse(true, new BaseRequestExecutor.RequestAgainListener() {//是否自动重试
        @Override
        public void requestAgain(String[] needAndCanRequestAgainPermissions) {
            //该监听回调中传入的是再次请求的权限,用以在重新请求时弹出说明框等信息(如
            //向用户说明为何要使用该权限)
            for (String s : needAndCanRequestAgainPermissions) {
                Log.e("TAG", "request again permission = "+s);
            }
        }
    })
    .result(new RequestExecutor.ResultReceiver() {
        @Override
        public void onPermissionsRequestResult(boolean grantAll, List<Permission> results) {
            if (grantAll) {
                Toast.makeText(MainActivity.this, "request permissions success!", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "request permissions fail!", Toast.LENGTH_SHORT).show();
            }
        }
    });
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容