针对 Android O 的运行时权限策略的特点,为了适配各个版本的系统,我们的代码会变成如下方式(伪代码):
- // 需要申请的权限。
- String[] permissions = {
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.READ_SMS,
- ...
- };
- String[] deniedPermissions = getDeinedPermission(permissions);
- if (deniedPermissions.length <= 0) {
- // TODO do something...
- } else {
- requestPermission(deniedPermissions, callback);
- }
但是这样会存在两个问题,一是有的权限组权限比较多,开发者难易全部记住;二是
这个权限常量是在 API 16 时才被添加到 SDK 中,类似这样的权限常量还有好几个,有的甚至在 Android M 时才被添加到 SDK 中。如果我们强制写了,当 APP 运行在低版本的系统中时,还是会崩溃。有人就说了,我们在申请之前判断系统版本不就好啦?当然,如果你不嫌麻烦,这是完全可以的。
- READ_EXTERNAL_STORAGE
因此我们总结出一个更优的方案,归根结底就是申请权限时要申请权限组,而不是单一的某个权限。所以我们按照系统权限组分类,把一个组的常量放到一个数组中,并根据系统版本为这个数组赋值,于是乎产生了这样一个类:
- public final class Permission {
- public static final String[] CALENDAR; // 读写日历。
- public static final String[] CAMERA; // 相机。
- public static final String[] CONTACTS; // 读写联系人。
- public static final String[] LOCATION; // 读位置信息。
- public static final String[] MICROPHONE; // 使用麦克风。
- public static final String[] PHONE; // 读电话状态、打电话、读写电话记录。
- public static final String[] SENSORS; // 传感器。
- public static final String[] SMS; // 读写短信、收发短信。
- public static final String[] STORAGE; // 读写存储卡。
- static {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- CALENDAR = new String[]{};
- CAMERA = new String[]{};
- CONTACTS = new String[]{};
- LOCATION = new String[]{};
- MICROPHONE = new String[]{};
- PHONE = new String[]{};
- SENSORS = new String[]{};
- SMS = new String[]{};
- STORAGE = new String[]{};
- } else {
- CALENDAR = new String[]{
- Manifest.permission.READ_CALENDAR,
- Manifest.permission.WRITE_CALENDAR};
- CAMERA = new String[]{
- Manifest.permission.CAMERA};
- CONTACTS = new String[]{
- Manifest.permission.READ_CONTACTS,
- Manifest.permission.WRITE_CONTACTS,
- Manifest.permission.GET_ACCOUNTS};
- LOCATION = new String[]{
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION};
- MICROPHONE = new String[]{
- Manifest.permission.RECORD_AUDIO};
- PHONE = new String[]{
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.CALL_PHONE,
- Manifest.permission.READ_CALL_LOG,
- Manifest.permission.WRITE_CALL_LOG,
- Manifest.permission.USE_SIP,
- Manifest.permission.PROCESS_OUTGOING_CALLS};
- SENSORS = new String[]{
- Manifest.permission.BODY_SENSORS};
- SMS = new String[]{
- Manifest.permission.SEND_SMS,
- Manifest.permission.RECEIVE_SMS,
- Manifest.permission.READ_SMS,
- Manifest.permission.RECEIVE_WAP_PUSH,
- Manifest.permission.RECEIVE_MMS};
- STORAGE = new String[]{
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE};
- }
- }
- }
在 Android M 以前使用某权限是不需要用户授权的,只要在 Manifest 中注册即可,在 Android M 之后需要注册并申请用户授权,所以我们根据系统版本在 Android M 以前用一个空数组作为权限组,在 Android M 以后用真实数组权限。
因为要传入多个权限组,所以我们约定的两个方法就不够用了,所以我们加两个方法:
- /**
- * 拿到没有被授权的权限。
- */
- String[] getDeinedPermission(String...permissions);
- /**
- * 请求几个权限。
- */
- void requestPermission(String...deinedPermissions);
- /**
- * 拿到没有被授权的权限。
- */
- String[] getDeinedPermission(String[]...permissions);
- /**
- * 请求几个权限。
- */
- void requestPermission(String[]...deinedPermissions);
于是我们申请权限的代码就简化成这样了:
- // 这方法里面判断版本,返回空数组或者没有权限的数组。
- String[] deniedPermissions = getDeinedPermission(Permission.STORAGE,Permission.SMS);
- if (deniedPermissions.length <= 0) {
- // TODO do something...
- } else {
- requestPermission(deniedPermissions, callback);
- }
当然这不是最简化的,但是已经足以兼容到 Android O 的权限策略的变化了。
这里只是介绍下
也兼容了 Android O 的权限变化,如果你觉得这个项目不适合你,你可以自行封装一个,我比较鼓励开发者自己动手,下面是开源地址: https://github.com/yanzhenjie/AndPermission
- AndPermisison
它的一些简单的特点:
1. 链式调用,一句话申请权限,省去复杂的逻辑判断。
2. 支持注解回调结果、支持 Listener 回调结果。
3. 拒绝一次某权限后,再次申请该权限时可使用 Rationale 向用户说明申请该权限的目的,在用户同意后再继续申请,避免用户勾选不再提示而导致不能再次申请该权限。
4. 就算用户拒绝权限并勾选不再提示,可使用 SettingDialog 提示用户去设置中授权。
5. RationaleDialog 和 SettingDialog 允许开发者自定义。
6. AndPermission 自带默认对话框除可自定义外,也支持国际化。
7. 支持在任何地方申请权限,不仅限于 Activity 和 Fragment 等。
8. 支持申请权限组、兼容 Android8.0。
申请多个权限组示例:
- AndPermission.with(this)
- .permission(Permission.CAMERA, Permission.SMS) // 多个权限组。
- .callback(new PermissionListener() {
- @Override
- public void onSucceed(int i, @NonNull List<String> list) {
- // TODO do something...
- }
- @Override
- public void onFailed(int i, @NonNull List<String> list) {
- // TODO 用户没有同意授权,一般弹出Dialog让用户去Setting中授权。
- }
- })
- .start();
申请单个或者某几个权限示例,因为 Android O 的出现,现在不鼓励这样使用了,但是在 Android O 正式发布前没有问题:
- AndPermission.with(this)
- .permission(
- // 多个不同权限组权限,现在不鼓励这样使用了,但是在Android O正式发布前没有问题。
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_SMS
- )
- .callback(new PermissionListener() {
- @Override
- public void onSucceed(int i, @NonNull List<String> list) {
- // TODO do something...
- }
- @Override
- public void onFailed(int i, @NonNull List<String> list) {
- // TODO 用户没有同意授权,一般弹出Dialog让用户去Setting中授权。
- }
- })
- .start();
关于 Android O 的运行时权限策略变化和应对方案的介绍到这里就结束了,如果还不理解的可以在博客下方留言。
来源: http://blog.csdn.net/yanzhenjie1003/article/details/76719487