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 运行时权限管理最佳实践
juejin.im/post/57d5de…

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

在正式开始之前,先纠正一个问题,在网上看到有项目可以做到自定义申请授权的系统Dialog,首先要纠正就目前来看是绝对不行的,最多在调用申请的代码之前弹一个自己的Dialog提示用户要申请授权了。我快速拜读了下那个项目源码,果然如我想象的一样,在绕了一个圈子后最终还是调用了系统申请授权的代码。


Android O的运行时权限策略变化

如果你喜欢看Google官网的文章,你可以看这里:
developer.android.com/preview/beh…

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

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

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

下面我们还是以READ_EXTERNAL_STORAGEWRITE_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(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[] 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的权限策略的变化了。

如果是AndPermission如何做到最简

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

它的一些简单的特点:

  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() {@Overridepublic void onSucceed(int i, @NonNull List<String> list) {// TODO do something...}@Overridepublic 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() {@Overridepublic void onSucceed(int i, @NonNull List<String> list) {// TODO do something...}@Overridepublic void onFailed(int i, @NonNull List<String> list) {// TODO 用户没有同意授权,一般弹出Dialog让用户去Setting中授权。}}).start();复制代码

关于Android O的运行时权限策略变化和应对方案的介绍到这里就结束了,如果还不理解的可以在文章下方留言。

Android 8.0 运行时权限策略变化和适配方案相关推荐

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

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

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

    版权声明:转载必须注明本文转自严振杰的博客:http://blog.yanzhenjie.com Android8.0也就是Android O即将要发布了,有很多新特性,目前我们可以通过Android ...

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

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

  4. Android 6.0 运行时权限处理

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

  5. Android 6.0运行时权限管理

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

  6. 谈谈Android 6.0运行时权限理解

    前言 谷歌在2015年8月份时候,发布了Android 6.0版本,代号叫做"棉花糖"(Marshmallow ),其中的很大的一部分变化,是在用户权限授权上,或许是感觉之前默认授 ...

  7. android 6.0运行时权限应用之图库图片选取

    http://blog.csdn.net/oneblue123/article/details/53357098

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

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

  9. Android PermissionUtils:运行时权限工具类及申请权限的正确姿势

    Android PermissionUtils:运行时权限工具类及申请权限的正确姿势 ifadai 关注 2017.06.16 16:22* 字数 318 阅读 3637评论 1喜欢 6 Permis ...

最新文章

  1. ecshop 首页添加某个分类下面的商品
  2. Matlab-使用逻辑值进行索引
  3. Android应用apk的程序签名详解
  4. [SAP ABAP开发技术总结]CLEAR、REFRESH、FREE内表清理区别
  5. c++ c6386 缓冲区 溢出_Office 远程溢出漏洞测试与分析
  6. Android ConstraintLayout ConstraintSet动态布局
  7. 绩效工作流_流绩效–您的想法
  8. python安装环境傻瓜式安装_前后端分离——前端开发环境傻瓜式一步到位 nodejs ruby python nginx 安装搭建配置...
  9. CondLaneNet | 使用动态卷积核预测每个车道线实例
  10. ORACLE 索引的三种状态: VALID、 N/A 、UNUSABLE
  11. 在sql server中用正则表达式替换html标签,SQL Server中利用正则表达式替换字符串
  12. workbench谐响应
  13. php自动上传到onedrive,让iPhone里的照片自动上传备份到OneDrive
  14. 1414. 和为 K 的最少斐波那契数字数目 贪心+递归 大年初三力扣是想意思意思一下呗~
  15. nafxcw.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined问题解决
  16. 如何添加其他网段的打印机
  17. 牛客网SQL实战二刷 | Day10
  18. 图文:微博平台首席架构师杨卫华演讲
  19. 利用python将单个Excel文件转换为PDF
  20. Unity学习 — VideoPlayer控制视频播放、暂停、上下选择播放!

热门文章

  1. XCode提交app时提示SDK Version Issue,This app was built with the IOS 12.0 SDK...
  2. 什么是死锁?死锁如何解决
  3. 吐血整理《计算机网络五层协议之物理层(中)》
  4. nanopi 创建共享文件夹
  5. 提高网速软件_【干货】C盘空间不够用,这款软件或许会帮到你!一键清除C盘多余文件...
  6. 3说明书_电子产品说明书应该怎么翻译?知行君认为需要注意这3点
  7. SQL Server 2008 R2 系统配置检查器的检查参数和妨碍性问题的解决办法
  8. Sass--@-Rules
  9. 网络钓鱼者钓到威胁情报公司的身上 黑客惨遭溯源
  10. 《社会智能与综合集成系统》第1章1.节参考文献