前言:

今天还是围绕着最近面试的一个热门话题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配置

  1. compileSdkVersion 24
  2. buildToolsVersion "24.0.2"
  3. defaultConfig {
  4. applicationId "com.whoislcj.rxpermissions"
  5. minSdkVersion 15
  6. targetSdkVersion 24
  7. versionCode 1
  8. versionName "1.0"
  9. }

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

2.)早期的解决办法

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

  1. compileSdkVersion 24
  2. buildToolsVersion "24.0.2"
  3. defaultConfig {
  4. applicationId "com.whoislcj.rxpermissions"
  5. minSdkVersion 15
  6. targetSdkVersion 22
  7. versionCode 1
  8. versionName "1.0"
  9. }

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

检查是否拥有使用权

  1. public boolean isGranted(String permission) {
  2. return !isMarshmallow() || isGranted_(permission);
  3. }

判断是否是Android 6.0以上

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

是否申请了该使用权限

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

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

4.)申请使用权限

  1. private void requestPermission(String permission, int requestCode) {
  2. if (!isGranted(permission)) {
  3. if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
  4.  
  5. } else {
  6. ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
  7. }
  8. } else {
  9. //直接执行相应操作了
  10. }
  11. }

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

5.)处理授权回调

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

6.)完整的Activity示例

  1. public class MainActivity extends AppCompatActivity {
  2. private static final int CAMERA = 2;
  3.  
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. findViewById(R.id.request_permission).setOnClickListener(new View.OnClickListener() {
  9. @Override
  10. public void onClick(View v) {
  11. requestPermission(Manifest.permission.CAMERA, CAMERA);
  12. }
  13. });
  14. }
  15.  
  16. /**
  17. * 拍照,返回拍照文件的绝对路径
  18. */
  19. private String takePhotoByPath(String filePath, int requestCode) {
  20. File file = new File(filePath);
  21. startActivityForResult(getTakePhotoIntent(file), requestCode);
  22. return file.getPath();
  23. }
  24.  
  25. private Intent getTakePhotoIntent(File file) {
  26. if (file.exists()) {
  27. file.delete();
  28. }
  29.  
  30. try {
  31. file.createNewFile();
  32. } catch (IOException e) {
  33. e.printStackTrace();
  34. }
  35.  
  36. Uri uri = Uri.fromFile(file);
  37. Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  38. intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
  39. return intent;
  40. }
  41.  
  42. public boolean isGranted(String permission) {
  43. return !isMarshmallow() || isGranted_(permission);
  44. }
  45.  
  46. private boolean isGranted_(String permission) {
  47. int checkSelfPermission = ActivityCompat.checkSelfPermission(this, permission);
  48. return checkSelfPermission == PackageManager.PERMISSION_GRANTED;
  49. }
  50.  
  51. private boolean isMarshmallow() {
  52. return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
  53. }
  54.  
  55. //shouldShowRequestPermissionRationale主要用于给用户一个申请权限的解释,该方法只有在用户在上一次已经拒绝过你的这个权限申请。也就是说,用户已经拒绝一次了,你又弹个授权框,你需要给用户一个解释,为什么要授权,则使用该方法。
  56. private void requestPermission(String permission, int requestCode) {
  57. if (!isGranted(permission)) {
  58. if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
  59.  
  60. } else {
  61. ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
  62. }
  63. } else {
  64. //直接执行相应操作了
  65. }
  66. }
  67.  
  68. @Override
  69. public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
  70. if (requestCode == CAMERA) {
  71. if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  72. String jpgPath = getCacheDir() + "test.jpg";
  73. takePhotoByPath(jpgPath, 2);
  74. } else {
  75. // Permission Denied
  76. Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
  77. }
  78. return;
  79. }
  80. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  81. }
  82.  
  83. }

总结:

本篇总结学习了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. 使用HTML5开发Kinect体感游戏

    一.简介 我们要做的是怎样一款游戏? 在前不久成都TGC2016展会上,我们开发了一款<火影忍者手游>的体感游戏,主要模拟手游章节<九尾袭来 >,用户化身四代,与九尾进行对决, ...

  2. Restful资源文章

    理解RESTful架构 RESTful API设计指南 RESTful架构详解 NodeJs的RESTful API

  3. 前端css兼容性与易混淆的点

    一.常用的骨灰级清除浮动 .clearfix:after { content: "."; display: block; height:; clear: both; visibil ...

  4. SQLSERVER聚集索引与非聚集索引的再次研究(上)

    SQLSERVER聚集索引与非聚集索引的再次研究(上) 上篇主要说聚集索引 下篇的地址:SQLSERVER聚集索引与非聚集索引的再次研究(下) 由于本人还是SQLSERVER菜鸟一枚,加上一些实验的逻 ...

  5. iOS开发之App间账号共享与SDK封装

    上篇博客<iOS逆向工程之KeyChain与Snoop-it>中已经提到了,App间的数据共享可以使用KeyChian来实现.本篇博客就实战一下呢.开门见山,本篇博客会封装一个登录用的SD ...

  6. 初学者看过来之JSON入门

    1. 什么是JSON JSON---Javascript Object Notation,前两个单词大家应该都认识,最后一个notation,是"记号.标记法"的意思,连在一起,便 ...

  7. C#发送邮箱

    之前自己从来没有做过发送邮箱的功能,前段时间项目需要,在找了很多帖子之后,终于实现了. 之后有整理了一下,写了一个类.直接给类传递信息,就可以发送了. 这里还需要说明的是,发送邮箱需要开通POP3/S ...

  8. JDBC Tutorials: Commit or Rollback transaction in finally block

    http://skeletoncoder.blogspot.com/2006/10/jdbc-tutorials-commit-or-rollback.html JDBC Tutorials: Com ...

  9. TCP/IP基础

    TCP/IP 是用于因特网 (Internet) 的通信协议. 计算机通信协议是对那些计算机必须遵守以便彼此通信的规则的描述. 什么是 TCP/IP? TCP/IP 是供已连接因特网的计算机进行通信的 ...

  10. 【SAP业务模式】之ICS(四):组织单元的配置

    SAP的ICS业务后台配置主要有以下几个配置点: 1.组织单元的配置(公司代码.销售组织.工厂.采购组织等): 2.主数据的部分: 3.订单和开票的定价过程: 4.开票输出类型: 5.公司间发票的配置 ...