Android动态权限

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权限分成与设备功能相关的权限组,便于用户在授予权限时做出更有意义和更明智的选择。

权限组 权限
CALENDAR READ_CALENDAR
- WRITE_CALENDAR
CAMERA CAMERA
CONTACTS CONTACTS
- READ_CONTACTS
- WRITE_CONTACTS
- GET_ACCOUNTS
LOCATION ACCESS_FINE_LOCATION
- ACCESS_COARSE_LOCATION
MICROPHONE RECORD_AUDIO
PHONE READ_PHONE_STATE
- READ_PHONE_NUMBERS
- CALL_PHONE
- ANSWER_PHONE_CALLS
- READ_CALL_LOG
- WRITE_CALL_LOG
- ADD_VOICEMAIL
- USE_SIP
- PROCESS_OUTGOING_CALLS
SENSORS BODY_SENSORS
SMS SEND_SMS
- RECEIVE_SMS
- READ_SMS
- RECEIVE_WAP_PUSH
- RECEIVE_MMS
STORAGE READ_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);
                    }
                }
            });
}

参考

猜你喜欢

转载自blog.csdn.net/zhanhong39/article/details/82316561
今日推荐