Android动态权限申请

一,前言

最近App的targetSdkVersion提升到23以上,因此需要处理动态权限的问题,因此网上学习了动态权限的一些知识,在实践中也遇到了不少的问题,因此在此做记录。

二,关于动态权限

安卓系统的权限管理机制从Android 6.0( Android M,对应的API 23)之后发生了很大的改变,为了对app安全运行有更好的控制,谷歌对权限进行了分类,权限分为普通权限(Normal Permissions)和危险权限(Dangerous Permissions),普通权限是一些不会涉及用户隐私,拥有权限也不会造成什么危险,比如访问网络等,如果需要在Mainfest.xml里添加即可,app会在安装的时候被给予权限,而且一旦给予权限也没有地方可以取消。而危险权限则是一些会涉及到用户隐私,需要让用户来决定是否接受赋予app的权限,比如摄像头,通讯录等等。被列为危险的权限要求必须申请动态权限,并且也需要在Mainfest.xml里添加。如果没有权限去运行则会崩溃。

普通权限不多做介绍了,可以去谷歌官网自行查找,下面对危险权限进行讲解,谷歌对危险权限提出了权限组的概念,即相似权限的在一个权限组里,赋予权限时是以权限组的方式赋予的,比如sd卡的读写权限组:

group:android.permission-group.STORAGE
    permission:android.permission.READ_EXTERNAL_STORAGE
    permission:android.permission.WRITE_EXTERNAL_STORAGE

申请权限时会把权限组的权限一起赋予,比如申请sd卡写权限,同时会把读权限一起给予(8.0之后对此做了更为严格的限制,同一权限组也必须单独的申请,不过如果之前已经申请过该组里的权限,则不会再通知用户)。危险权限共分为九组,具体权限组如下:

Android动态权限申请_第1张图片
危险权限组

申请动态权限发生的场景:

1,targetSdkVersion>=23

2,手机是6.0及以上的。

如果手机系统是6.0以下,或者targetSdkVersion<23,无论手机系统版本是不是6.0以上,都不会进 行动态权限的申请。(M以下的系统进行权限查询checkSelfPermission会直接返回true)。

三,动态权限申请步骤

1,在AndroidManifest文件中添加需要的权限。(如果没有声明,直接去申请权限会导致程序崩溃)。

2,检查权限:

int checkSelfPermission(@NonNull Context context, @NonNull String permission)

private boolean checkPermission(String permission) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {         
            return true;
        } else {
            return false;
        }
    } else {
        return true;
    }
}    

3,申请授权

void ActivityCompat.requestPermissions(final @NonNull Activity activity,final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode)

private void startRequestPermision(String[] permissions) {
    ActivityCompat.requestPermissions(MainActivity.this, permissions, REQUEST_CODE);
}

该方法是异步的,第一个参数是Context;第二个参数是需要申请的权限的字符串数组;第三个参数为requestCode,主要用于回调的时候检测。可以从方法名requestPermissions以及第二个参数看出,是支持一次性申请多个权限的,系统会通过对话框逐一询问用户是否授权。

4,处理权限申请回调

void onRequestPermissionsResult(intrequestCode, String permissions[],int[] grantResults)

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == REQUEST_CODE) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                //TODO
            } else {
                //如果拒绝授予权限,且勾选了再也不提醒
                if (!shouldShowRequestPermissionRationale(permissions[0])) {
                    //说明申请权限原因 showDescDialog();
                } else {
                    //去设置页面 goSetting();
                }
            }
        }
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

申请的权限系统会通过弹窗逐一让用户选择是否给予,如果不给予而又必须申请权限,则有两种情况,如果用户没有勾选“不再提醒”选项,则还可以通过弹窗来说明申请权限的原因。如果用户勾选了“不再提醒”选项,则只能通过去设置页面让用户手动添加权限。

四,遇到的问题

1,不同手机厂商对权限申请机制做了修改
在申请权限时表现形式会有所不同,不过大部分的流程还是和原生系统大同小异。比如小米手机,小米手机在6.0以下已经增加了动态权限,是通过类似安全管家的软件进行权限检测。有一些厂商修改的动态权限申请有问题,比如魅族的flyme,在一个6.0的版本上,检查权限会告知有权限,因此检查步骤通过,但是实际上并没有给予,在实际使用权限的时候触发告知app正在请求使用权限,即使此时同意,也不能避免此次调用失败,再次使用时才成功。确实挺坑的,也没想到好的解决方案。
2,用户在应用设置页面手动操作权限对应用的影响
app如果在后台正在运行,当在系统设置里增加权限没问题,如果有减少权限的动作(1,减少某一个权限; 2,对某个权限增加又减少),则都会触发系统把app进程kill掉,然后重新启动进程。具体现象如下:
从后台中重新打开app时,activity的栈为空,系统自动把退到后台时显示的activity放到栈顶,并且记录了原来的栈顺序,可以像原来栈顺序一样后退,但是每个activity显示时都是重新创建(onCreate),另外重启后内存数据全部丢失了。针对该问题有如下的处理方法,在ActivityLifeCycle里增加记录Activity栈里activity数量的变量,可以检测到栈为空到有的时刻,如果该时刻第一个入栈的activity不是闪屏页(第一个启动的页面)则重启应用。

你可能感兴趣的:(Android动态权限申请)