Android Jetpack - Permissions权限初探

一、Android的权限声明

当APP需要访问APP沙箱外部数据或资源的区域,则需要声明权限。APP必须在AndroidManiffest文件中,通过<uses-permission>声明所需的权限。例如APP需要网络连接,则在manifest中添加一行

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.xxx">

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

    <application ...>
        ...
    </application>
</manifest>

如果应用在manifest中列出了正常权限,系统会自动授予APP这些权限。

如果应用在manifest中列出了危险权限,则需要用户明确同意授予这些权限。

二、Android的权限分类

Android权限分成几个保护级别,保护级别会影响是否需要APP运行时申请权限。

目前分为三个保护级别:NormalSigatureDangerous权限。

Normal权限在APP安装时系统自动授予。

Sigature权限也是在APP安装时系统授予。

Dangerous权限则需要在APP运行时,APP提示用户授予权限,即动态申请。

1、Normal权限

Normal权限不会直接给用户隐私权带来风险。如果APP在其manifest中声明Normal权限,则系统会在安装时自动授予APP该权限。系统不会提示用户授予Normal权限,用户也无法撤消这些权限。

从Android 8.1(API 27)开始,以下权限为Normal:

  • 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
  • GET_PACKAGE_SIZE
  • INSTALL_SHORTCUT
  • INTERNET
  • KILL_BACKGROUND_PROCESSES
  • MANAGE_OWN_CALLS
  • MODIFY_AUDIO_SETTINGS
  • NFC ……

2、Sigature权限

顾名思义,Sigature权限仅限于用该APK(定义了这个权限的APK)相同的私钥签名的应用才可以申请该权限。

从Android 8.1(API 27)开始,以下权限为Signature:

  • BIND_ACCESSIBILITY_SERVICE
  • BIND_AUTOFILL_SERVICE
  • BIND_CARRIER_SERVICES
  • BIND_CHOOSER_TARGET_SERVICE
  • BIND_CONDITION_PROVIDER_SERVICE
  • BIND_DEVICE_ADMIN
  • BIND_DREAM_SERVICE
  • BIND_INCALL_SERVICE
  • BIND_INPUT_METHOD ……

3、Dangerous权限

Dangerous权限分成与设备功能相关的权限组,便于用户在授予权限时做出更有意义和更明智的选择。

权限组权限
CALENDARREAD_CALENDAR
WRITE_CALENDAR
CAMERACAMERA
CONTACTSCONTACTS
READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
LOCATIONACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
MICROPHONERECORD_AUDIO
PHONEREAD_PHONE_STATE
READ_PHONE_NUMBERS
CALL_PHONE
ANSWER_PHONE_CALLS
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
SENSORSBODY_SENSORS
SMSSEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
STORAGEREAD_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

运行时请求Dangerous权限

  • 如果设备运行的是Android 6.0(API 23)或更高版本,并且APP的targetSdkVersion为23或更高,则在安装时,不会通知用户任何APP权限。APP必须在运行时提示用户授予Dangerous权限。

  • 如果设备运行Android 5.1.1(API 22)或更低版本,或者targetSdkVersion为22或更低,则在安装时,系统会自动要求用户授予所有Dangerous权限。

三、动态申请权限的关键代码

1、请求需要的权限

例如:检查APP是否具备摄像头权限Manifest.permission.CAMERA为例,并根据需要请求该权限

// 检查权限,没有返回true,需要申请
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.CAMERA)
        != PackageManager.PERMISSION_GRANTED) {

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

        // 如果应用之前请求过此权限但用户拒绝了请求,此方法将返回true,这步判断非必须      
        // 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.CAMERA},
                MY_PERMISSIONS_REQUEST_CAMERA);

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

注:当APP调用requestPermissions()时,系统将向用户显示一个标准对话框。APP无法配置或更改此对话框。如果需要为用户提供任何信息或解释,应在调用requestPermissions()之前进行,如解释应用为什么需要权限中所述。

2、处理权限请求响应

当应用请求权限时,系统将向用户显示一个对话框。当用户响应时,系统将调用应用的onRequestPermissionsResult()方法,向其传递用户响应。因此,需要在Activity或者Fragment实现onRequestPermissionsResult方法。

@TargetApi(Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_CAMERA: {
            // If request is cancelled, the result arrays are empty.
            // 异常情况,grantResultsw也是空数组
            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
    }
}

四、其他

为了方便申请动态权限,可以使用一些开源库,比如RxPermissions,将权限申请的代码requestPermissions()和请求结果的代码onRequestPermissionsResult()放在一起管理,避免了代码的分散,同时具备Rx(RxJava)的特性。

使用如下

private void requestPremission() {
    RxPermissions rxPermissions = new RxPermissions(this);
    rxPermissions.request(Manifest.permission.CAMERA)
            .subscribe(new Consumer<Boolean>() {
                @Override
                public void accept(Boolean granted) throws Exception {
                    if (granted) {
                        Log.d("zzhtest", "permission = " + granted);
                    } else {
                        Log.d("zzhtest", "permission = " + granted);
                    }
                }
            });
}

五、 结论

系统自定义的权限以及一直feature, 可以直接定义在xml(/etc/permissions下面)配置文件里.
一个apk在安装的时候已经将非运行时权限直接grant给设备上所有的用户,而运行时权限是跟权限直接相关的.
一个apk可以申请permission, 即用<uses-permission />表示,也可以自定义权限,如systemserver相关的权限大多是在 framework-res.apk里定义的。
具体相同的sharedUserId的package拥有相同的permission, 代码中使用的是Shared UID的permissions, 且该permissions是所有sharedUserId的合集。
【附录】

《Android Jetpack - Permissions权限初探》 资料图

需要资料的朋友可以加入Android架构交流QQ群聊:513088520

点击链接加入群聊【Android移动架构总群】:加入群聊

获取免费学习视频,学习大纲另外还有像高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)等Android高阶开发资料免费分享。

    原文作者:Android架构
    原文地址: https://www.jianshu.com/p/124fe6a6da4b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞