Android6.0权限适配实践

Android6.0权限适配实践

概要

  • 判断是否需要请求权限
  • 如何请求权限
  • 如何部分请求权限
  • 处理权限请求回调
  • 关于“自定义提示”的说明
  • 问题一:获取权限后进入设置取消权限再回到应用的问题
  • 问题二:勾选“不再询问”的说明

判断是否需要请求权限

关于权限申请,第一手的资料可以查看官方文档:http://developer.android.com/intl/zh-cn/training/permissions/requesting.html

Android M (API 23)起,权限管理有了很大的改变,引入了运行时权限检测,并将权限大致分为普通和危险两类,当应用首次使用某一危险的权限时,需要弹出授权对话框,让用户进行二次确认。

遗憾的是授权对话框并不会自己弹出来,需要开发者手动调用授权API才行,判断是否需要请求权限只需要将应用的target SDK版本设置为23,并在6.0的模拟器或设备上运行,程序运行到使用危险权限的地方时会Crash,并抛出Permission Denial异常。

下图是需要运行时授权的危险权限表:

这里写图片描述

如何请求权限

请求权限需要调用ActivityCompat的requestPermissions方法,通过第二个参数permission[i]传入需要请求的权限字符串数组。

        if (Build.VERSION.SDK_INT >= 23) {
            String[] permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.CAMERA};
            ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST);   
        }

调用该方法后系统会弹出授权对话框,用户可以在对话框上选择授权或不授权,操作结果会通过ActivityCompat.OnRequestPermissionsResultCallback接口的onRequestPermissionsResult方法返回。

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
    }        

如何部分请求权限

以上的例子中我们请求了读取存储设备和使用相机两个权限,此时系统弹出的授权对话框会分别让用户确认两个权限。即使其中的一个权限用户已经授权过了也依然会让用户再授权一次。因此再弹出调用授权API之前需要先判断是否需要授权,方法如下:

        if (Build.VERSION.SDK_INT >= 23 && !mInRequestPermission) {
            String[] permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.CAMERA};
            boolean needGrantedPermissions = false;
            for (int i = 0, size = permissions.length; i < size; i++) {
                if (ActivityCompat.checkSelfPermission(this, permissions[i])
                        != PackageManager.PERMISSION_GRANTED) {
                    needGrantedPermissions = true;
                } else {
                    permissions[i] = "";
                }
            }

            if (needGrantedPermissions) {
                mInRequestPermission = true;
                ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST);
                return false;
            } else {
                permissionGranted();
                return true;
            }
        }

对于已获得的权限,将permission置为空字符串,避免重复请求已获得的权限

处理权限请求回调

用户操作完权限对话框后,系统会调用ActivityCompat.OnRequestPermissionsResultCallback接口的onRequestPermissionsResult()方法将结果返回,在该方法中我们可以获取到每个权限的授权情况:

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_REQUEST) {
            mInRequestPermission = false;
            if (grantResults.length > 0) {
                boolean cameraSuccess = true;
                boolean storageSuccess = true;
                for (int i = 0, size = permissions.length; i < size; i++) {
                    String permission = permissions[i];
                    if (permission.equals(Manifest.permission.CAMERA)) {
                        if (grantResults.length > i) {
                            int grantResult = grantResults[i];
                            if (grantResult != PackageManager.PERMISSION_GRANTED) {
                                cameraSuccess = false;
                            }
                        } else {
                            cameraSuccess = false;
                        }
                    } else if (permission.equals(Manifest.permission.READ_EXTERNAL_STORAGE)) {
                        if (grantResults.length > i) {
                            int grantResult = grantResults[i];
                            if (grantResult != PackageManager.PERMISSION_GRANTED) {
                                storageSuccess = false;
                            }
                        } else {
                            storageSuccess = false;
                        }
                    }
                }

                if (cameraSuccess && storageSuccess) {
                    permissionGranted();
                } else if (!cameraSuccess){
                    Toast.makeText(this, "摄像头权限未开启,请到设置-应用-XXAPP中开启摄像头权限", Toast.LENGTH_LONG).show();
                    setResult(Activity.RESULT_CANCELED);
                    finish();
                } else {
                    Toast.makeText(this, "存储空间权限未开启,请到设置-应用-XXAPP中开启存储空间权限", Toast.LENGTH_LONG).show();
                    setResult(Activity.RESULT_CANCELED);
                    finish();
                }
            } else {
                Toast.makeText(this, "摄像头权限未开启,请到设置-应用-XXAPP中开启摄像头权限", Toast.LENGTH_LONG).show();
                setResult(Activity.RESULT_CANCELED);
                finish();
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

关于“自定义提示”的说明

系统的授权对话框总内存不够友好,不能够很好的向用户传达需要权限的原因,有时,用户会因为不明白为什么需要权限而将权限申请拒绝掉,此时就有必要在弹出系统对话框之前向用户解释下需要授权的原因了,官方文档中有如下说明:

To help find situations where the user might need an explanation, Android provides a utiltity method, shouldShowRequestPermissionRationale(). This method returns true if the app has requested this permission previously and the user denied the request.
Note: If the user turned down the permission request in the past and chose the Don't ask again option in the permission request system dialog, this method returns false. The method also returns false if a device policy prohibits the app from having that permission.

大意就是在请求权限前先调用shouldShowRequestPermissionRationale()方法判断是否需要先弹出自定义的解释说明,需要注意的是这个方法在首次请求的时候是返回false的,只有当用户拒绝过一次授权后才会返回true,毕竟多一步交互会造成体验下降,只有在用户对权限产生困扰的时候才需要向用户进行解释说明。

问题一:获取权限后进入设置取消权限再回到应用的问题

如果将权限请求放在了onCreate()方法中,那么建议在onResume()中再进行一次校验,避免用户在当前页面授权后通过按Home键进入设置中取消了刚授权的权限,返回应用后由于无权限而Crash。onResume()的校验逻辑和onCreate()的请求逻辑几乎一致,但是需要判断如果在请求权限的过程中,就不要进行校验了。请求权限的过程中可以通过一个状态位在调用requestPermissions()和收到onRequestPermissionsResult()回调的地方进行标记。

问题二:勾选“不再询问”的说明

勾选了“不在询问”选项后,每次调用requestPermissions()方法,onRequestPermissionsResult()回调都会直接返回未授权,不会弹出授权对话框,此时可以通过Toast或对话框告知用户如何去设置中进行授权。

参考资料:
https://medium.com/ribot-labs/exploring-the-new-android-permissions-model-ba1d5d6c0610#.dfrov6k6p

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值