【从 0 开始开发一款直播 APP】13 Android 6.0 运行时权限

本文为菜鸟窝作者蒋志碧的连载。“从 0 开始开发一款直播 APP ”系列来聊聊时下最火的直播 APP,如何完整的实现一个类"腾讯直播"的商业化项目

一、前言

Android 6.0 版本(Api 23) 及其以上系统引入运行时权限 — 默认所有涉及用户隐私的权限都被关闭,我们在 AndroidManifest.xml 中申请权限之后,依然还需要动态申请权限,不然每次安装完APP后,就需要在「设置 -> 应用 -> APP」中打开所需权限。

Android 系统包含默认的授权提示框,但是仍需要我们设置自己的页面,原因的系统提供的授权框会有不再提示选项。如果用户选择,则无法触发授权提示,使用自定义的提示页面,可以给予用户手动修改授权的指导。

统一授权

如果设备运行的是 Android 5.1(API 级别 22)或更低版本,并且应用的 targetSdkVersion 是 22 或更低版本,则系统会在用户安装应用时要求用户授予权限。如果将新权限添加到更新的应用版本,系统会在用户更新应用时要求授予该权限。用户一旦安装应用,他们撤销权限的唯一方式是卸载应用。

运行时权限

如果设备运行的是 Android 6.0(API 级别 23)或更高版本,并且应用的 targetSdkVersion 是 23 或更高版本,则应用在运行时向用户请求权限。用户可随时调用权限,因此应用在每次运行时均需检查自身是否具备所需的权限。

二、权限分组

Android 6.0 引入运行时权限,所有权限仍然需要在 AndroidManifest 中声明,但是当访问需要的权限时,活动或片段必须验证权限已被授予或使用支持库的调用请求缺少的权限。

权限分为三类:

正常(Normal Protection)权限
危险(Dangerous)权限
特殊(Particular)权限
其它权限(一般很少用到)

正常权限

正常权限」涵盖应用需要访问其沙盒外部数据或资源,但对用户隐私或其他应用操作风险很小的区域。例如,设置时区的权限就是正常权限。如果应用声明其需要正常权限,系统会自动向应用授予该权限。

正常权限具有如下特点

1、对用户隐私没用较大影响或者不会带来安全问题

2、安装之后就被赋予这些权限,不需要显示提醒用户,用户也不能取消这些权限


危险权限

危险权限涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如,能够读取用户的联系人属于危险权限。如果应用声明其需要危险权限,则用户必须明确向应用授予该权限。

权限组

所有危险的 Android 系统权限都属于权限组。如果设备运行的是 Android 6.0(API 级别 23),并且应用的 targetSdkVersion是 23 或更高版本,则当用户请求危险权限时系统会发生以下行为:

如果应用请求其清单中列出的危险权限,而应用目前在权限组中没有任何权限,则系统会向用户显示一个对话框,描述应用要访问的权限组。对话框不描述该组内的具体权限。例如,如果应用请求 READ_CONTACTS 权限,系统对话框只说明该应用需要访问设备的联系信息。如果用户批准,系统将向应用授予其请求的权限。

如果应用请求其清单中列出的危险权限,而应用在同一权限组中已有另一项危险权限,则系统会立即授予该权限,而无需与用户进行任何交互。例如,如果某应用已经请求并且被授予了 READ_CONTACTS 权限,然后它又请求 WRITE_CONTACTS,系统将立即授予该权限。

任何权限都可属于一个权限组,包括正常权限和应用定义的权限。但权限组仅当权限危险时才影响用户体验。可以忽略正常权限的权限组。

如果设备运行的是 Android 5.1(API 级别 22)或更低版本,并且应用的 targetSdkVersion 是 22 或更低版本,则系统会在安装时要求用户授予权限。再次强调,系统只告诉用户应用需要的权限组,而不告知具体权限。


特殊权限

有许多权限其行为方式与正常权限及危险权限都不同。SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS 特别敏感,因此大多数应用不应该使用它们。如果某应用需要其中一种权限,必须在清单中声明该权限,并且发送请求用户授权的 intent。系统将向用户显示详细管理屏幕,以响应该 intent。

SYSTEM_ALERT_WINDOW 设置悬浮窗

WRITE_SETTINGS 修改系统设置

SYSTEM_ALERT_WINDOW

允许应用使用类型 TYPE_APPLICATION_OVERLAY 创建窗口,该窗口显示在所有其他应用程序的顶端。极少的应用程序应该使用这个权限,这些窗口用于与用户的系统级交互。

Note:如果是 API 23 及其以上版本,用户必须通过权限管理向应用程显示权限。 应用程序通过发送 ACTION_MANAGE_OVERLAY_PERMISSION action 的隐式 intent 请求用户的批准。 该应用程序可以通过调用 Settings.canDrawOverlays() 来检查是否具有此授权。

请求 SYSTEM_ALERT_WINDOW 权限

private static final int REQUEST_CODE_SYSTEM_ALERT_WINDOW = 1;
private  void requestAlertWindowPermission() {
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
    intent.setData(Uri.parse("package:" + getPackageName()));
    startActivityForResult(intent, REQUEST_CODE_SYSTEM_ALERT_WINDOW);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_SYSTEM_ALERT_WINDOW) {
        if (Settings.canDrawOverlays(this)) {
          Log.i(TAG, "ACTION_MANAGE_OVERLAY_PERMISSION granted");
        }
    }
}

注意:

使用 Action 的 Settings.ACTION_MANAGE_OVERLAY_PERMISSION 启动隐式 Intent。
使用 "package:" + getPackageName() 携带 APP 包名信息
使用 Settings.canDrawOverlays(this) 判断授权结果

WRITE_SETTINGS

允许应用程序读取或写入系统设置。

Note:如果是 API 23 及其以上版本,则用户必须通过权限管理向应用程序显式授予该权限。 应用程序通过发送 ACTION_MANAGE_WRITE_SETTINGS 的 action 的隐式 Intent 来请求用户的批准。 该应用程序可以通过调用 Settings.System.canWrite() 来检查是否具有此授权。

请求 WRITE_SETTINGS 权限

private static final int REQUEST_CODE_WRITE_SETTINGS = 2;
private void requestWriteSettings() {
    Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
    intent.setData(Uri.parse("package:" + getPackageName()));
    startActivityForResult(intent, REQUEST_CODE_WRITE_SETTINGS );
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_WRITE_SETTINGS) {
        if (Settings.System.canWrite(this)) {
            Log.i(LOGTAG, "WRITE_SETTINGS granted" );
        }
    }
}

注意:

使用 Action 的 Settings.ACTION_MANAGE_WRITE_SETTINGS 启动隐式 Intent。
使用 "package:" + getPackageName() 携带 APP 包名信息
使用 Settings.canDrawOverlays(this) 判断授权结果

关于这两个特殊权限,一般不建议应用申请。

三、申请权限的主要方法

Android 6.0 运行时权限申请位于 package android.support.v4.app 包中。主要方法有三个:

**1、权限通过 ActivityCompat 类的 checkSelfPermission() 方法判断是否有所需权限。
**
**2、权限请求是通过 ActivityCompat 类中的 requestPermissions() 方法,在OnRequestPermissionsResultCallback # onRequestPermissionsResult() 方法中回调。
**
3、应用程序可以提供一个额外的合理的使用权限调用 Activitycompat # shouldShowRequestPermissionRationale() 方法。Android 原生系统中,如果第二次弹出权限申请的对话框,会出现「以后不再弹出」的提示框,如果用户勾选了,你再申请权限,则 shouldShowRequestPermissionRationale() 返回 true,意思是说要给用户一个解释,告诉用户为什么要这个权限。

四、运行时权限示例

以照相机权限为例。

1、在 AndroidManifest.xml 文件中申请所需要的权限。

<uses-permission android:name="android.permission.CAMERA"/>

2、在 gradle 中修改 targetSdkVersion 大于或等于 23。

3、开始申请权限。

权限检查

PublishPresenter.java # checkPublishPermission()

@Override
public boolean checkPublishPermission(Activity activity) {
    //1、ActivityCompat.checkSelfPermission() 判断权限
    if (Build.VERSION.SDK_INT >= 23) {
        List<String> permissions = new ArrayList<>();
        if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)) {
            permissions.add(Manifest.permission.CAMERA);
        }
        //2、ActivityCompat.requestPermissions() 申请权限
        if (permissions.size() != 0) {
           ActivityCompat.requestPermissions(activity
                            , permissions.toArray(new String[0]),
                            Constants.WRITE_PERMISSION_REQ_CODE);
          return false;
        }
     }
  return true;
}

方法回调

PublishActivity.java # onRequestPermissionsResult()

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode){
        case Constants.WRITE_PERMISSION_REQ_CODE:
            for (int ret:grantResults){
                if (ret != PackageManager.PERMISSION_GRANTED){
                    return;
                }
            }
            mPermission = true;
            break;
        default:
            break;
    }
}

五、运行效果

当进入该界面,系统就会判断是否具有照相机权限,没有则会弹出对话框提示用户添加权限。


详情请转至 GitHub

参考:

http://www.what21.com/article/a_3_1483187432030.html

http://droidyue.com/blog/2016/01/17/understanding-marshmallow-runtime-permission/

https://developer.android.com/guide/topics/security/permissions.html?hl=zh-cn#normal-dangerous

撸这个项目的一半,你就是大神 , 戳http://mp.weixin.qq.com/s/ZagocTlDfxZpC2IjUSFhHg

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

推荐阅读更多精彩内容