前言:

今天还是围绕着最近面试的一个热门话题Android 6.0权限适配来总结学习,其实Android 6.0权限适配我们公司是在今年5月份才开始做,算是比较晚的吧,不过现在Android 6.0以上设备越来越多了,所以Android 6.0 权限适配是必不可少的工作,这里主要介绍一下我们公司是如何做Android 6.0权限适配的。

权限管理相关博客:

Android 6.0以下非运行时权限:

根据上面博客我们很清楚的知道,Android的权限其实就是为了程序之间更加的安全的访问,所以权限有等级之分,比如:Normal 低风险权限 、Dangerous  高风险权限等,虽然有这种安全意识,但是这些权限只会在安装的时候被询问一次,一旦安装之后,如果app申请了高风险权限的话,而且大部分用户在安装的时候很少去关注这些权限列表,再加上很多Android市场都有静默安装的功能用户更加感知不到任何权限提示,就这样app就有可能会在后台做一些对用户带来伤害的事情。如下图所示:

Android6.0运行时权限:

鉴于6.0之前的版本权限管理相对不那么安全,所以Android 6.0 采用新的权限模型,只有在需要权限的时候,才告知用户是否授权,是在runtime时候授权,而不是在原来安装的时候 ,同时默认情况下每次在运行时打开页面时候,需要先检查是否有所需要的权限申请。这样的用户的自主性提高很多,比如用户可以给APP赋予摄像的权限,也可以使用权限。

Android 6.0权限适配:

1.)不进行适配造成的现象

先看下app module的build.gradle配置

 compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.whoislcj.rxpermissions"
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
}

由于Android 6.0 以上的权限变成了运行时权限,也就是说在需要使用某个权限的时候必须动态去申请使用,直接访问直接导致app崩溃。

2.)早期的解决办法

其实判断是否是需要运行时权限的标记就是targetSDKVersion,当targetSDKVersion<23的时候,仅在安装时赋予权限,使用时将不被提醒,当targetSDKVersion≥23的时候才会使用新的运行时权限规则。所有在最早遇见因权限未适配的导致的崩溃的时候,我们团队采用的解决办法是将targetSDKVersion人为的降到小于23,这样就变成了还是默认使用权限,但是这种并不是Google所推荐使用的。

 compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.whoislcj.rxpermissions"
minSdkVersion 15
targetSdkVersion 22
versionCode 1
versionName "1.0"
}

3.)判断是否拥有该权限的使用权限

检查是否拥有使用权

    public boolean isGranted(String permission) {
return !isMarshmallow() || isGranted_(permission);
}

判断是否是Android 6.0以上

  private boolean isMarshmallow() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}

是否申请了该使用权限

 private boolean isGranted_(String permission) {
int checkSelfPermission = ActivityCompat.checkSelfPermission(this, permission);
return checkSelfPermission == PackageManager.PERMISSION_GRANTED;
}

ContextCompat.checkSelfPermission,主要用于检测某个权限是否已经被授予,方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。当返回DENIED就需要进行申请授权了。

4.)申请使用权限

    private void requestPermission(String permission, int requestCode) {
if (!isGranted(permission)) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { } else {
ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
}
} else {
//直接执行相应操作了
}
}

shouldShowRequestPermissionRationale主要用于给用户一个申请权限的解释,该方法只有在用户在上一次已经拒绝过你的这个权限申请。也就是说,用户已经拒绝一次了,你又弹个授权框,你需要给用户一个解释,为什么要授权,则使用该方法。requestCode这个需要在处理的回调的时候 一一对应的。

5.)处理授权回调

   @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == CAMERA) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
String jpgPath = getCacheDir() + "test.jpg";
takePhotoByPath(jpgPath, 2);
} else {
// Permission Denied
Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

6.)完整的Activity示例

public class MainActivity extends AppCompatActivity {
private static final int CAMERA = 2; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.request_permission).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
requestPermission(Manifest.permission.CAMERA, CAMERA);
}
});
} /**
* 拍照,返回拍照文件的绝对路径
*/
private String takePhotoByPath(String filePath, int requestCode) {
File file = new File(filePath);
startActivityForResult(getTakePhotoIntent(file), requestCode);
return file.getPath();
} private Intent getTakePhotoIntent(File file) {
if (file.exists()) {
file.delete();
} try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
} Uri uri = Uri.fromFile(file);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
return intent;
} public boolean isGranted(String permission) {
return !isMarshmallow() || isGranted_(permission);
} private boolean isGranted_(String permission) {
int checkSelfPermission = ActivityCompat.checkSelfPermission(this, permission);
return checkSelfPermission == PackageManager.PERMISSION_GRANTED;
} private boolean isMarshmallow() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
} //shouldShowRequestPermissionRationale主要用于给用户一个申请权限的解释,该方法只有在用户在上一次已经拒绝过你的这个权限申请。也就是说,用户已经拒绝一次了,你又弹个授权框,你需要给用户一个解释,为什么要授权,则使用该方法。
private void requestPermission(String permission, int requestCode) {
if (!isGranted(permission)) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { } else {
ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
}
} else {
//直接执行相应操作了
}
} @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == CAMERA) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
String jpgPath = getCacheDir() + "test.jpg";
takePhotoByPath(jpgPath, 2);
} else {
// Permission Denied
Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
} }

总结:

本篇总结学习了Android 6.0的运行时权限及如何适配的问题,但是这个并不是我们公司目前最终的解决办法,从上面可以看出实现起来还是蛮麻烦的,申请权限和处理回调在不同的地方代码可读性相对较差,我们最终的解决方案是采用RxJava+RxPermission的方式解决,下一篇将介绍一下如何使用RxPermission解决Android 6.0 权限适配问题。

Android权限管理之Android 6.0运行时权限及解决办法的更多相关文章

  1. Android开发学习之路-Android6.0运行时权限

    在Android6.0以后开始,对于部分敏感的“危险”权限,需要在应用运行时向用户申请,只有用户允许的情况下这个权限才会被授予给应用.这对于用户来说,无疑是一个提升安全性的做法.那么对于开发者,应该怎 ...

  2. Android 6.0+ 运行时权限

    1.权限被分为了普通和危险两种 2.打电话的Demo import android.Manifest; import android.app.Activity; import android.cont ...

  3. Android6.0运行时权限(基于RxPermission开源库)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 在6.0以前的系统,都是权限一刀切的处理方式,只要用户安装,Manifest申请的权限都会被赋予,并且安装后权限也撤销不了. And ...

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

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

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

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

  6. Android 6.0 运行时权限处理完全解析 (摘抄)

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/50709663: 本文出自:[张鸿洋的博客] 一.概述 随着Android 6. ...

  7. Android数据存储之Android 6.0运行时权限下文件存储的思考

    前言: 在我们做App开发的过程中基本上都会用到文件存储,所以文件存储对于我们来说是相当熟悉了,不过自从Android 6.0发布之后,基于运行时权限机制访问外置sdcard是需要动态申请权限,所以以 ...

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

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

  9. android-详解Android 6.0运行时权限

    感谢郭神,从Android 6.0开始,不再是安装应用时用户确定获得全部的权限.而是在使用软件过程中需要该权限时,弹出对话框让用户选择权限.不仅如此,用户选择权限后还可以关闭. 检查是否获得权限 通过 ...

随机推荐

  1. 基于spring注解AOP的异常处理

    一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...fin ...

  2. ASP.NET Aries 入门开发教程7:DataGrid的行操作(主键操作区)

    前言: 抓紧勤奋,再接再励,预计共10篇来结束这个系列. 上一篇介绍:ASP.NET Aries 入门开发教程6:列表数据表格的格式化处理及行内编辑 本篇介绍主键操作区相关内容. 1:什么时候有默认的 ...

  3. ASP.NET Aries 入门开发教程5:自定义列表页工具栏区

    前言: 抓紧时间,继续写教程,因为发现用户期待的内容,都在业务处理那一块. 不得不继续勤劳了. 这节主要介绍工具栏区的玩法. 工具栏的默认介绍: 工具栏默认包括5个按钮,根据不同的权限决定显示: 添加 ...

  4. ABP文档 - Hangfire 集成

    文档目录 本节内容: 简介 集成 Hangfire 面板授权 简介 Hangfire是一个综合的后台作业管理器,可以在ABP里集成它替代默认的后台作业管理器,你可以为Hangfire使用相同的后台作业 ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)

    系列目录 前言: 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访 ...

  6. 带你实现开发者头条APP(四)---首页优化(加入design包)

    title: 带你实现开发者头条APP(四)---首页优化(加入design包) tags: design,Toolbar,TabLayout,RecyclerView grammar_cjkRuby ...

  7. javascript中的继承与深度拷贝

    前言 本篇适合前端新人,下面开始...... 对于前端新手来说(比如博主),每当对js的对象做操作时,都是一种痛苦,原因就是在于对象的赋值是引用的传递,并非值的传递,虽然看上去后者赋值给了前者,他们就 ...

  8. mybatis_开发篇

    一.使用mybatis的动态代理方式开发 需求:这里以crm系统中分页条件查询所有的客户信息的功能为例? 1.创建工程 2.引入所需的jar包 3.引入日志文件.数据库连接参数的配置文件等 4.创建m ...

  9. 高频交易算法研发心得--MACD指标算法及应用

    凤鸾宝帐景非常,尽是泥金巧样妆. 曲曲远山飞翠色:翩翩舞袖映霞裳. 梨花带雨争娇艳:芍药笼烟骋媚妆. 但得妖娆能举动,取回长乐侍君王. [摘自<封神演义>纣王在女娲宫上香时题的诗] 一首定 ...

  10. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...