Android 6.0动态权限申请

概述

Google在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限和危险权限。应用的相关功能每次在使用危险权限时需要动态的申请并得到用户的授权才能使用。

权限分类

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

  • 正常权限不会直接给用户隐私权带来风险。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。
  • 危险权限会授予应用访问用户机密数据的权限。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。如果您列出了危险权限,则用户必须明确批准您的应用使用这些权限。
危险权限和权限组

重要方法

  • ContextCompat.checkSelfPermission
    检查应用是否具有某个危险权限。如果应用具有此权限,方法将返回 PackageManager.PERMISSION_GRANTED,并且应用可以继续操作。如果应用不具有此权限,方法将返回 PackageManager.PERMISSION_DENIED,且应用必须明确向用户要求权限。

  • ActivityCompat.requestPermissions
    应用可以通过这个方法动态申请权限,调用后会弹出一个对话框提示用户授权所申请的权限。

  • ActivityCompat.shouldShowRequestPermissionRationale
    如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。如果用户在过去拒绝了权限请求,并在权限请求系统对话框中选择了 Don't ask again 选项,此方法将返回 false。如果设备规范禁止应用具有该权限,此方法也会返回 false。

  • onRequestPermissionsResult
    当应用请求权限时,系统将向用户显示一个对话框。当用户响应时,系统将调用应用的 onRequestPermissionsResult() 方法,向其传递用户响应,处理对应的场景。

示例

本示例在Google示例的基础上做了少许修改,步骤如下:

1、在AndroidManifest.xml中添加所需权限。

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

2、封装了一个requestPermission方法来动态检查和申请权限

    private void requestPermission() {

        Log.i(TAG,"requestPermission");
        // Here, thisActivity is the current activity
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {
            Log.i(TAG,"checkSelfPermission");
            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.READ_CONTACTS)) {
                Log.i(TAG,"shouldShowRequestPermissionRationale");
                // 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.

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

            } else {
                Log.i(TAG,"requestPermissions");
                // No explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(this,
                        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.
            }
        }
    }

3、重写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) {
                    Log.i(TAG,"onRequestPermissionsResult granted");
                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.

                } else {
                    Log.i(TAG,"onRequestPermissionsResult denied");
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                    showWaringDialog();
                }
                return;
            }

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

    private void showWaringDialog() {
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setTitle("警告!")
                .setMessage("请前往设置->应用->PermissionDemo->权限中打开相关权限,否则功能无法正常运行!")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // 一般情况下如果用户不授权的话,功能是无法运行的,做退出处理
                finish();
            }
        }).show();
    }

RxPermissions

官方提供的方法在一次申请多个权限的时候代码逻辑写起来比较繁琐,于是有了RxPermissions。RxPermissions是使用Rxjava封装的第三方的权限申请库,他的特点是借助Rxjava的特性简化了权限申请的代码逻辑,使代码看起来简洁易读。具体的使用方法可以参看《RxPermissions获取运行时权限》,里面写的比较详细。

参考文献

Google Doc:在运行时请求权限
Google Doc:正常权限和危险权限
权限分类:正常权限和危险权限
Android6.0动态权限申请步骤以及需要注意的一些坑
Android6.0------权限申请管理(单个权限和多个权限申请)
android6.0运行时权限详解

推荐阅读更多精彩内容