Android 6.0运行时权限处理与封装

众所周知,在Android 6.0之后,Android对一些用户的敏感权限进行了进一步加强,需要用户去动态授予权限。


前言

在API23之前,只要在AndroidManifest.xml中注册过的权限,程序运行时都会自动获取到。但是到了23及更高,危险的权限就需要我们自己来动态的申请了,而此时用户也就有了拒绝我们需要的权限的权力,这当然会导致我们程序的运行不正常,甚至是造成程序的崩溃。所以我们就需要尽可能的提示用户同意我们的权限申请。

说明

系统权限分为几个保护级别。需要了解的两个最重要保护级别是正常权限和危险权限。 首先,你必须得知道哪些是需要动态申请的权限,也就是我前面所提到的危险权限,并且危险权限也分组,所以到底哪些是危险权限呢?

这里我们涉及到9大组危险权限,但是可喜可贺的是我们只需要申请每组中的一个权限,就能获取到全组权限的授权。

1、关于日历的权限: <uses-permission android:name="android.permission.READ_CALENDAR"/> <uses-permission android:name="android.permission.WRITE_CALENDAR"/> 2、关于相机的权限: <uses-permission android:name="android.permission.CAMERA"/> 3、关于联系人的权限: <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_CONTACTS"/> <uses-permission android:name="android.permission.GET_CONTACTS"/> 4、关于位置的权限: <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 5、关于电话的权限: <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.CALL_PHONE"/> <uses-permission android:name="android.permission.READ_CALL_LOG"/> <uses-permission android:name="android.permission.WRITE_CALL_LOG"/> <uses-permission android:name="android.permission.USE_SIP"/> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/> 6、关于传感器的权限: <uses-permission android:name="android.permission.BODY_SENSORS"/> 7、关于短信的权限: <uses-permission android:name="android.permission.SEND_SMS"/> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.READ_SMS"/> <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/> <uses-permission android:name="android.permission.RECEIVE_MMS"/> <uses-permission android:name="android.permission.READ_CELL_BROADCASTS"/> 8、关于SD卡的权限 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 9、关于录音的权限 <uses-permission android:name="android.permission.RECORD_AUDIO"/>

案例

这里我们通过一个打电话的案例进行说明

我们在6.0之前写打电话功能

第一步:在清单文件中申明打电话权限:

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

第二步:

Intent intent = new Intent(Intent.ACTION_CALL);        Uri data = Uri.parse("tel:" + mPhoneNumber);        intent.setData(data);        startActivity(intent);

之前这两步就可以实现一个打电话的功能,但是现在不行了,现在回程序运行会崩溃,因为你没有动态申请用户打电话权限。

我们在6.0之后写打电话功能

现在我们需要去检测该权限有没有背用户授予过,如果没有则需要申请打电话权限,如果有授予过可以直接拨打电话。

ContextCompat.checkSelfPermission:检测权限
ActivityCompat.requestPermissions:申请权限

第一步:检测用户用没有授权打电话,如果没有就需要申请权限

findViewById(R.id.btn_call).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission                        .CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {                    // 没有该权限 申请打电话权限                    //  Context ,                    // 第二个参数是用户需要申请的权限字符串数组,                    // 第三个参数是请求码 主要用来处理用户选择的返回结果                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, CALL_PHONE_REQUEST_CODE);                } else {                    callPhone();                }            }        });

是的,就是这么简单。不过,如果你就这样子用在了你的项目里,会有坑!!!

如果你本身就是Android用户,细心的你一定会发现,App在向你申请权限的时候,你会有几个选项:

1.允许
2.拒绝
3.还可以拒绝并不再提示!(坑就出现在这里了)
如果按上面的代码,你会永远得到一个答案:用户拒绝!!(如果用户是不小心点错,或者出于好奇心尝试,那很容易就懵逼了)

所以我们还需要对第一步做个调整

findViewById(R.id.btn_call).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission                        .CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {                    // 没有该权限 申请打电话权限                    //  Context ,                    // 第二个参数是用户需要申请的权限字符串数组,                    // 第三个参数是请求码 主要用来处理用户选择的返回结果                    // 1、此时还没有权限!                    if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,                            Manifest.permission.CALL_PHONE)) {                        // 2、用户还没选择或选择了但没选择拒绝并不再提示                        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, CALL_PHONE_REQUEST_CODE);                    } else {                        // 3、用户点选了不再提示                        //(正经的告诉用户这个功能必须给权限啊,求权限啊!最好告诉他怎么去设置!)                        showTipsDialog(MainActivity.this);                    }                } else {                    // 有权限了,去做该做的事情吧!                    callPhone();                }            }        });

优化部分:还可以拒绝并不再提示!,我们添加了一个可以让用户设置的跳转

/**     * 显示提示对话框(这个提示款适用于点击按钮请求权限的问题)     * 如果需要强制获取权限,需要自定义对话框     */    public static void showTipsDialog(final Context context) {        new AlertDialog.Builder(context)                .setTitle("提示信息")                .setMessage("当前应用缺少必要权限,该功能暂时无法使用。如若需要,请单击【确定】按钮前往设置中心进行权限授权。")                .setNegativeButton("取消", null)                .setPositiveButton("确定", new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        startAppSettings(context);                    }                }).show();    }    /**     * 启动当前应用设置页面     */    private static void startAppSettings(Context context) {        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);        intent.setData(Uri.parse("package:" + context.getPackageName()));        context.startActivity(intent);    }

第二步: 处理回调 如果用户同意或是拒绝那么会回调onRequestPermissionsResult()

@Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        if(requestCode == CALL_PHONE_REQUEST_CODE){            if (grantResults !=null&&grantResults[0] == PackageManager.PERMISSION_GRANTED) {                // Permission Granted  通过  打电话                callPhone();            } else {                // Permission Denied   被拒绝                Toast.makeText(this,"权限被拒绝了",Toast.LENGTH_SHORT).show();            }        }        super.onRequestPermissionsResult(requestCode, permissions, grantResults);    }

至此,这个功能算是可用了!!!但是,还不完美!!!必须稍微封装一下让自己用起来更方便嘛!那么接下来就带大家来一个更加完美的封装。

源码下载

更多相关文章

  1. Android的Activity一打开就出现讨嫌的软键盘,怎样将其关闭?
  2. Google Android(安卓)P之后,Android(安卓)工程师将何去何从?
  3. Android包管理机制
  4. Android应用程序设计策略
  5. Android(安卓)API Guides---System Permissions
  6. 为Android开发者整理的Google I/O开发者大会第一弹
  7. android:apk版本的的比对、下载、安装
  8. Android开发指南-用户界面-对话框
  9. Android(安卓)浏览器打开本地APK

随机推荐

  1. 使用Android(安卓)Studio开发NDK程序时出
  2. TextView关于xml属性用法(待完善)
  3. Android获取天气预报Demo
  4. android中的通知
  5. Android Process 优先级
  6. Android(安卓)View架构总结
  7. Android学习笔记―第十一章 Fragment
  8. Anroid 视频开发浅析
  9. 【Android】报错:Can't create handler in
  10. Android Trick 1: 使用View来制作专业的