Android6.0运行时权限处理

概述

从Android6.0(API23)开始,用户可以在应用运行时向其授予权限,而不是在应用安装时授予。

在Android6.0以前,应用安装会给出应用声明的权限列表,用户如果要继续安装,就得接受全部的权限,让用户很无奈;

从Android6.0开始的运行时权限,让用户可以对应用的功能进行更多的控制,例如,用户可以选择为相机应用提供相机的访问权限,而不提供设备位置的访问权限。用户可以随时进入应用的“Settings”开关权限。

兼容性

  • 如果设备的系统版本是Android5.1或者更低的版本,或者应用的targetSdkVersion为22或更低:如果您在清单中列出了危险权限,则用户必须在安装应用时授予此权限;如果用户不授予此权限,系统根本不会安装应用。
  • 如果设备的系统版本是Android6.0或者更高的版本,或者应用的targetSdkVersion为23或更高:应用必须在清单中列出权限,并且它必须在运行时请求其需要的每项危险权限。用户可以授权或拒绝每项权限,且即使用户拒绝权限请求,应用仍可以继续运行有限的功能。

权限分类

系统权限分为两类:正常权限和危险权限

Normal Permissions

正常权限,不会直接给用户隐私权带来风险。如果您的应用在其清单列出了正常权限,系统将自动授予该权限。

  • ACCESS_LOCATION_EXTRA_COMMANDS
  • ACCESS_NETWORK_STATE
  • ACCESS_NOTIFICATION_POLICY
  • ACCESS_WIFI_STATE
  • BLUETOOTH
  • BLUETOOTH_ADMIN
  • BROADCAST_STICKY
  • CHANGE_NETWORK_STATE
  • CHANGE_WIFI_MULTICAST_STATE
  • CHANGE_WIFI_STATE
  • DISABLE_KEYGUARD
  • EXPAND_STATUS_BAR
  • FOREGROUND_SERVICE
  • GET_PACKAGE_SIZE
  • INSTALL_SHORTCUT
  • INTERNET
  • KILL_BACKGROUND_PROCESSES
  • MANAGE_OWN_CALLS
  • MODIFY_AUDIO_SETTINGS
  • NFC
  • READ_SYNC_SETTINGS
  • READ_SYNC_STATS
  • RECEIVE_BOOT_COMPLETED
  • REORDER_TASKS
  • REQUEST_COMPANION_RUN_IN_BACKGROUND
  • REQUEST_COMPANION_USE_DATA_IN_BACKGROUND
  • REQUEST_DELETE_PACKAGES
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
  • SET_ALARM
  • SET_WALLPAPER
  • SET_WALLPAPER_HINTS
  • TRANSMIT_IR
  • USE_FINGERPRINT
  • VIBRATE
  • WAKE_LOCK
  • WRITE_SYNC_SETTINGS

Dangerous Permissions

危险权限,会授予应用访问用户机密数据的权限。如果您的应用在清单中列出了危险权限,则用户必须明确批准您的应用使用这些权限。

危险权限是按权限组来划分,如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。

例如,你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。

NOTE:对应申请时弹出的Dialog上面的文本说明也是对整个权限组的说明,而不是单个权限。

权限组 权限
CALENDAR READ_CALENDAR
WRITE_CALENDAR
CALL_LOG READ_CALL_LOG<BR/>WRITE_CALL_LOG<BR/>PROCESS_OUTGOING_CALLS
CAMERA CAMERA
CONTACTS READ_CONTACTS<BR/>WRITE_CONTACTS<BR/>GET_ACCOUNTS
LOCATION ACCESS_FINE_LOCATION<BR/>ACESS_COARSE_LOCATION
MICROPHONE RECORD_AUDIO
PHONE READ_PHONE_STATE<BR/>READ_PHONE_NUMBERS<BR/>CALL_PHONE<BR/>ADD_VOICEMAIL<BR/>USE_SIP
SENSORS BODY_SENSORS
SMS SEND_SMS<BR/>RECEIVE_SMS<BR/>READ_SMS<BR/>RECEIVE_WAP_PUSH<BR/>RECEIVE_MMS
STORAGE READ_EXTERNAL_STORAGE<BR/>WRITE_EXTERNAL_STORAGE

运行时权限处理

检查权限

如果你的应用需要危险权限,则每次执行需要这一权限的操作时都必须检查自己是否具有该权限。因为用户可以自由的开关此权限,所以,即使应用昨天使用了相机,它不能假设自己今天仍具有该权限。

ContextCompat.checkSelfPermission:用于检测某个权限是否已经被授予

int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);

说明:如果应用具有此权限,方法将返回PackageManager.PERMISSION_GRANTED,并且允许应用可以继续操作。如果应用不具有此权限,方法将返回PackageManager.PERMISSION_DENIED,且应用必须明确向用户要求权限。

请求权限

如果应用尚无所需的权限,则应用必须调用requestPermissions()方法,来请求适当的权限。

ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);

说明:从第二个参数可以看出,支持一次性请求多个权限,系统会通过对话框逐一询问用户是否授权。

处理权限请求响应

当应用请求权限时,系统将向用户显示一个对话框。当用户响应时,系统将调用应用的onRequestPermissionsResult()方法。

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

解释权限的用途

如果用户继续尝试使用需要某项权限的功能,但拒绝权限请求,则可能表明用户不理解应用为什么需要此权限才能提供相关的功能,这时就可以显示解释给用户。

shouldShowRequestPermissionRationale()

如果应用之前请求过此权限但用户拒绝了请求,此方法返回true

如果用户过去拒绝了权限请求,并在权限请求系统对话框选择了Don't ask again选项,此方法返回false

if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

AndPermission的使用

AndPermission是严格按照Android系统的运行时权限设计的,并最大限度上兼容了国产手机。

库地址:https://github.com/yanzhenjie/AndPermission

导入

implementation 'com.yanzhenjie:permission:2.0.0-rc12'

使用

申请权限
AndPermission.with(this)
  .runtime()
  .permission(Permission.Group.STORAGE)
  .onGranted(permissions -> {
    // Storage permission are allowed.
  })
  .onDenied(permissions -> {
    // Storage permission are not allowed.
  })
  .start();
权限被拒绝,说明权限用途
private Rationale mRationale = new Rationale() {
    @Override
    public void showRationale(Context context, List<String> permissions, 
            RequestExecutor executor) {
        // 这里使用一个Dialog询问用户是否继续授权。

        // 如果用户继续:
        executor.execute();

        // 如果用户中断:
        executor.cancel();
    }
};

AndPermission.with(this)
    .runtime()
    .permission(Permission.WRITE_EXTERNAL_STORAGE)
    .rationale(mRationale)
    .onGranted(...)
    .onDenied(...)
    .start();
权限总是被拒绝,前往设置页授权
AndPermission.with(this)
    .runtime()
    .permission(...)
    .rationale(...)
    .onGranted(...)
    .onDenied(new Action() {
        @Override
        public void onAction(List<String> permissions) {
            if (AndPermission.hasAlwaysDeniedPermission(context, permissions)) {
                // 这些权限被用户总是拒绝。
                // 这里使用一个Dialog展示没有这些权限应用程序无法继续运行,询问用户是否去设置中授权。
                AndPermission.with(this)
                    .runtime()
                    .setting()
                    .onComeback(new Setting.Action() {
                        @Override
                        public void onAction() {
                            // 用户从设置回来了。
                        }
                    })
                    .start();
            }
        }
    })
    .start();

参考链接

  1. Android 6.0 运行时权限处理完全解析
  2. Android 6.0 运行时权限管理最佳实践
  3. Android 6.0运行时权限讲解
  4. 在运行时请求权限
  5. Android 6.0 变更
  6. 权限最佳做法
  7. AndPermission
    编码前线.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容