Android8.0运行时权限策略变化和适配方案
版权声明:转载必须注明本文转自严振杰的博客: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运行时权限策略变化和适配方案的更多相关文章
- Android 6.0 运行时权限处理完全解析
一.概述 随着Android 6.0发布以及普及,我们开发者所要应对的主要就是新版本SDK带来的一些变化,首先关注的就是权限机制的变化.对于6.0的几个主要的变化,查看查看官网的这篇文章http:// ...
- Android 6.0+ 运行时权限
1.权限被分为了普通和危险两种 2.打电话的Demo import android.Manifest; import android.app.Activity; import android.cont ...
- Android 6.0 运行时权限处理完全解析 (摘抄)
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/50709663: 本文出自:[张鸿洋的博客] 一.概述 随着Android 6. ...
- Android权限管理之Android 6.0运行时权限及解决办法
前言: 今天还是围绕着最近面试的一个热门话题Android 6.0权限适配来总结学习,其实Android 6.0权限适配我们公司是在今年5月份才开始做,算是比较晚的吧,不过现在Android 6.0以 ...
- Android6.0运行时权限(基于RxPermission开源库)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 在6.0以前的系统,都是权限一刀切的处理方式,只要用户安装,Manifest申请的权限都会被赋予,并且安装后权限也撤销不了. And ...
- Android数据存储之Android 6.0运行时权限下文件存储的思考
前言: 在我们做App开发的过程中基本上都会用到文件存储,所以文件存储对于我们来说是相当熟悉了,不过自从Android 6.0发布之后,基于运行时权限机制访问外置sdcard是需要动态申请权限,所以以 ...
- 谈谈Android 6.0运行时权限理解
前言 谷歌在2015年8月份时候,发布了Android 6.0版本,代号叫做“棉花糖”(Marshmallow ),其中的很大的一部分变化,是在用户权限授权上,或许是感觉之前默认授权的不合理,现在6. ...
- android-详解Android 6.0运行时权限
感谢郭神,从Android 6.0开始,不再是安装应用时用户确定获得全部的权限.而是在使用软件过程中需要该权限时,弹出对话框让用户选择权限.不仅如此,用户选择权限后还可以关闭. 检查是否获得权限 通过 ...
- Android 6.0运行时权限
一.Runtime Permissions Android 6.0在手机安全方面做的一个处理就是增加了运行时权限(Runtime Permissions). 新的权限机制更好的保护了用户的隐私,Goo ...
随机推荐
- Spring Boot 之 Profile 使用
Spring Boot 之 Profile 使用 一个应用为了在不同的环境下工作,常常会有不同的配置,代码逻辑处理.Spring Boot 对此提供了简便的支持. 关键词: @Profile.spri ...
- .NET的弹性及瞬间错误处理库Polly
原文:.NET的弹性及瞬间错误处理库Polly 本文基本是官方说明的翻译和总结(https://github.com/App-vNext/Polly) 什么是Polly? Polly是一款基于.NET ...
- echarts 响应式布局
<body> <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main" style="width: ...
- C# LINQ 详解 From Where Select Group Into OrderBy Let Join
目录 1. 概述 2. from子句 3. where子句 4. select子句 5. group子句 6. into子句 7. 排序子句 8. let子句 9. join子句 10. 小结 1. ...
- [Oracle]快速构造大量数据的方法
[Oracle]快速构造大量数据的方法: create table tab001(id integer primary key, val varchar2(100)); insert into tab ...
- default construction
4种情况下编译器会构造出nontrivial(有用)的构造函数 带有default construction的member class object 我们有两个class: class Foo { p ...
- Node.js系列-express(下)
前言 距上次更新博客又两个月多了,这两个月内除了上班时间忙公司的项目外,下班后也没有闲着,做了点外包,有小程序的,管理端的项目.也可能那段时间做的外包项目也都比较急,所以晚上都搞到一点左右睡,严重的压 ...
- vsftpd虚拟账户配置
1. 概述 FTP是文件传输协议,在内外网的文件传输中使用广泛. 本篇博客主要介绍FTP服务器的部署和测试. 2. 软件环境部署 查看系统是否安装FTP软件(vsftpd),执行命令:rpm -qa ...
- BugkuCTF web基础$_POST
前言 写了这么久的web题,算是把它基础部分都刷完了一遍,以下的几天将持续更新BugkuCTF WEB部分的题解,为了不影响阅读,所以每道题的题解都以单独一篇文章的形式发表,感谢大家一直以来的支持和理 ...
- 算法模板学习专栏之总览(会慢慢陆续更新ing)
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/7495310.html特别不喜欢那些随便转载别人的原创文章又不给 ...