版权声明:转载必须注明本文转自严振杰的博客:http://blog.yanzhenjie.com
Android8.0也就是Android O即将要发布了,有很多新特性,目前我们可以通过AndroidStudio3.0 Canary版本下载android O最新的系统映像的Developer Preview 4版本,Developer Preview 4是Android O正式版推出前的最后一个预览版本,所以它是Android O的候选版本,我们可以使用它来完成开发和测试,让我们的应用平稳过度到Android O。

后期会计划出一篇Android O行为变化和兼容方案的文章,本篇文章主要讲Android O行为变化的其中一点——系统运行时权限的策略变化和适配方案。

Android系统的运行时权限是从Android 6.0(Android M)开始加入的,如果你还不知道Android运行时权限,你可以看Android 6.0 运行时权限管理最佳实践:
http://blog.csdn.net/yanzhenjie1003/article/details/52503533

针对运行时权限管理,有很多开源的管理库,16年9月份时本人也开源了一个运行权限管理方案,它最大程度上兼容了国产机,当然也兼容了Android 8.0:
https://github.com/yanzhenjie/AndPermission

本文中申请权限的示例代码是原生代码,没有使用AndPermission。
Android O的运行时权限策略变化

如果你喜欢看Google官网的文章,你可以看这里:
https://developer.android.com/preview/behavior-changes.html#rmp

在 Android O 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用。

对于针对Android O的应用,此行为已被纠正。系统只会授予应用明确请求的权限。然而一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准。

例如,假设某个应用在其清单中列出READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE。应用请求READ_EXTERNAL_STORAGE,并且用户授予了该权限,如果该应用针对的是API级别24或更低级别,系统还会同时授予WRITE_EXTERNAL_STORAGE,因为该权限也属于STORAGE权限组并且也在清单中注册过。如果该应用针对的是Android O,则系统此时仅会授予READ_EXTERNAL_STORAGE,不过在该应用以后申请WRITE_EXTERNAL_STORAGE权限时,系统会立即授予该权限,而不会提示用户。

下面我们还是以READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE为例来具体分析一下,这对我们现有的代码有什么影响。

正式开始之前,我们先约定两个方法:

/**
* 拿到没有被授权的权限。
*/
getDeinedPermission(String... permissions);
/**
* 请求几个权限。
*/
requestPermission(String... deinedPermissions);
权限的常量在Manifest.permission类中,而READ_EXTERNAL_STORAGE权限是在API 16之后才添加的,所以在在Android M出来后为了适配更低版本的系统,我们一般是这样申请权限的(伪代码):

// 需要申请的权限。
String[] permissions = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_SMS,
...
};

String[] deniedPermissions = getDeinedPermission (www.wmyl15.com/ permissions);

if(deniedPermissions.length <= 0) {
// TODO do something...
} else {
requestPermission(deniedPermissions, callback);
逻辑非常简单清晰,其中的callback是申请权限的回调,这里我们申请了WRITE_EXTERNAL_STORAGE权限,在Android O之前,我们同时会得到READ_EXTERNAL_STORAGE权限,我们在其它地方涉及到读取存储卡的操作时只需要判断有WRITE_EXTERNAL_STORAGE权限就去读取了。

霸特,此时应用如果安装在Android O的系统中我们会发现,判断了有WRITE_EXTERNAL_STORAGE权限后去读取存储卡内容时应用崩溃了,原因就是我们没有申请READ_EXTERNAL_STORAGE权限。

对Android O运行时权限策略变化的应对方案

针对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);

但是这样会存在两个问题,一是有的权限组权限比较多,开发者难易全部记住;二是READ_EXTERNAL_STORAGE这个权限常量是在API 16时才被添加到SDK中,类似这样的权限常量还有好几个,有的甚至在Android M时才被添加到SDK中。如果我们强制写了,当APP运行在低版本的系统中时,还是会崩溃。有人就说了,我们在申请之前判断系统版本不就好啦?当然,如果你不嫌麻烦,这是完全可以的。

升级方案

因此我们总结出一个更优的方案,归根结底就是申请权限时要申请权限组,而不是单一的某个权限。所以我们按照系统权限组分类,把一个组的常量放到一个数组中,并根据系统版本为这个数组赋值,于是乎产生了这样一个类:

public final class Permission {

public static final String[] CALENDAR; // 读写日历。
public static final String[] CAMERA; // 相机。
public static final String[] CONTACTS; // 读写联系人。
public static final String[www.wmyl11.com/] LOCATION; // 读位置信息。
public static final String[www.xucaizxyl.com/] MICROPHONE; // 使用麦克风。
public static final String[www.lieqibiji.com/] PHONE; // 读电话状态、打电话、读写电话记录。
public static final String[www.dejiaylsmile.cn] SENSORS; // 传感器。
public static final String[www.yongshiyule178.com] SMS; // 读写短信、收发短信。
public static final String[www.xingchexiu.com] 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,
在Android M以前使用某权限是不需要用户授权的,只要在Manifest中注册即可,在Android M之后需要注册并申请用户授权,所以我们根据系统版本在Android M以前用一个空数组作为权限组,在Android M以后用真实数组权限。

因为要传入多个权限组,所以我们约定的两个方法就不够用了,所以我们加两个方法:

/**
* 拿到没有被授权的权限。
*/
String[] getDeinedPermission(String... permissions);
/**
* 请求几个权限。
*/
void requestPermission(String... deinedPermissions);
/**
* 拿到没有被授权的权限。
*/
String[] getDeinedPermission(String[]... permissions);
/**
* 请求几个权限。
*/
void requestPermission(String[]... www.senta77.com/ deinedPermissions);
于是我们申请权限的代码就简化成这样了:

// 这方法里面判断版本,返回空数组或者没有权限的数组。
String[] deniedPermissions = getDeinedPermission(Permission.STORAGE, Permission.SMS);

if(deniedPermissions.length <= 0) {
// TODO do something...
} else {
requestPermission(deniedPermissions, callback);
当然这不是最简化的,但是已经足以兼容到Android O的权限策略的变化了。

如果是AndPermission如何做到最简

这里只是介绍下AndPermisison也兼容了Android O的权限变化,如果你觉得这个项目不适合你,你可以自行封装一个,我比较鼓励开发者自己动手,下面是开源地址:
https://github.com/yanzhenjie/AndPermission

它的一些简单的特点:
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();
14
申请单个或者某几个权限示例,因为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://www.6788878.cn/

Android8.0运行时权限策略变化和适配方案相关推荐

  1. Android 8.0学习(18)--- Android8.0运行时权限策略变化和适配方案

    Android8.0运行时权限策略变化和适配方案    在 Android O 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用.对 ...

  2. Android 8.0 运行时权限策略变化和适配方案

    Android8.0也就是Android O即将要发布了,有很多新特性,目前我们可以通过AndroidStudio3.0 Canary版本下载Android O最新的系统映像的Developer Pr ...

  3. Android 6.0 运行时权限处理完全解析

    一.概述 随着Android 6.0发布以及普及,我们开发者所要应对的主要就是新版本SDK带来的一些变化,首先关注的就是权限机制的变化.对于6.0的几个主要的变化,查看查看官网的这篇文章http:// ...

  4. 获取权限android sync,GitHub - AndSync/XPermissionUtils: 可能是最精简的Android6.0运行时权限处理方式,支持Rationale提示...

    # XPermissionUtils 可能是最精简的Android6.0运行时权限处理方式,支持Rationale提示,只有一个类,100行代码,所有弹窗等操作由用户自行处理,在Demo中也有提供代码 ...

  5. 这可能是最精简的Android6.0运行时权限处理,百行代码的工具类,支持Rationale,附:各种权限详细处理

    0x00:前言 对于Android6.0运行时权限的处理方式网上有很多,包括注解,RxJava等等.一直没有正面提到我关心的问题–如果我不在Activity或者Fragment里面,需要运行时权限该怎 ...

  6. Android6.0运行时权限解决方案

    今天在测试APP的时候发现部分手机APP定位权限使用不了.看了一下机型都是Android6.0以上版本的Android手机. 之前就听说Android6.0以上版本权限管理更严格了,没想到今天踩坑了. ...

  7. Android 6.0 运行时权限处理

    2019独角兽企业重金招聘Python工程师标准>>> 运行时权限介绍 Android 6.0在我们原有的AndroidManifest.xml声明权限的基础上, 又新增了运行时权限 ...

  8. Android6.0运行时权限处理

    前言 在Android6.0版本以前,往往是应用程序需要什么权限直接在manifest.xml中直接声明,当你安装程序的时候,如果不想让该程序使用某种权限,唯一的办法只能是不装这个应用,但是我们生活中 ...

  9. Android 6.0运行时权限管理

    运行时权限管理 定义: 之前我们的App需要权限,只需在manifest中申明,用户安装后,一切申明的权限都可使用. 但是Android 6.0以后Android M把权限管理做了加强处理,除了需要在 ...

最新文章

  1. 深度学习多变量时间序列预测:Bi-LSTM算法构建时间序列多变量模型预测交通流量+代码实战
  2. 成功解决The subservice has not been subscribed.
  3. vim编写python没有代码提示_vim编写python自动补全
  4. TREX搜索的执行最后也是通过HTTP call来完成的
  5. 《零基础看得懂的C语言入门教程 》——(七)C语言的循环分分钟上手
  6. c语言1 2 10000,C语言1~10000之间所有水仙花数
  7. 情人节海报设计没有灵感?看过来
  8. android adb 模拟来电,在Android模拟器中模拟GPS、打电话、发短信……
  9. 【白皮书分享】2020全球数字治理白皮书.pdf(附下载链接)
  10. 【转】关于Class.forName(“com.mysql.jdbc.Driver”)
  11. SHA256 算法 加密文件、防文件篡改、文件校验
  12. TIPTOP实施基础资料收集计划表
  13. 最好的远程桌面破解软件frdpb_v2
  14. Oracle数据库违反唯一约束条件
  15. 自制MyEclipse豆沙绿主题
  16. Android之如何分析手机系统相册图片和视频删除后保存的位置
  17. 内含扩容源码的面试题,目标是手写HashMap!
  18. 梯度下降---偏导数及其几何意义
  19. linux下删除软连接
  20. 【问题收集】slam中常见make问题错误 相关总结

热门文章

  1. 转:Tkinter教程之Text(2)篇
  2. limit_choices_to a value on a field in the same model - Google Groups
  3. WP8调用NativeCode
  4. sklearn网格搜索
  5. linux路由介绍,Linux的路由表详细介绍
  6. Java开发四年的程序员想再学习一门语言,该选着C还是Python呢?
  7. python大牛分享一些对python的看法
  8. 看看专科程序员与本科程序员之间,到底有什么区别?
  9. c java utf 8_如何对javac设置encoding utf 8
  10. 人工智能改善客户服务体验