详解Android权限管理之Android 6.0运行时权限及解决办法

 更新时间:2016年11月23日 15:05:08   作者:总李写代码  
本篇文章主要介绍Android权限管理之Android 6.0运行时权限及解决办法,具有一定的参考价值,有兴趣的可以了解一下。

GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!
如果你想靠AI翻身,你先需要一个靠谱的工具!

前言:

今天还是围绕着最近面试的一个热门话题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
2
3
4
5
6
7
8
9
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所推荐使用的。

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

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

检查是否拥有使用权

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

判断是否是Android 6.0以上

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

是否申请了该使用权限

1
2
3
4
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.)申请使用权限

1
2
3
4
5
6
7
8
9
10
11
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.)处理授权回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@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示例
 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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 权限适配问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

蓄力AI

微信公众号搜索 “ 脚本之家 ” ,选择关注

程序猿的那些事、送书等活动等着你

原文链接:http://www.cnblogs.com/whoislcj/p/6064710.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!

相关文章

  • Android开发使用Drawable绘制圆角与圆形图案功能示例

    Android开发使用Drawable绘制圆角与圆形图案功能示例

    这篇文章主要介绍了Android开发使用Drawable绘制圆角与圆形图案功能,结合具体实例形式分析了Drawable绘制圆角矩形的实现步骤与使用方法,需要的朋友可以参考下
    2017-10-10
  • Android计时器的三种实现方式(Chronometer、Timer、handler)

    Android计时器的三种实现方式(Chronometer、Timer、handler)

    这篇文章主要介绍了Android计时器的三种实现方式,Chronometer、Timer、handler计时器的实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • Flutter折叠控件使用方法详解

    Flutter折叠控件使用方法详解

    这篇文章主要为大家详细介绍了Flutter折叠控件的使用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • android模拟实现航拍遥控

    android模拟实现航拍遥控

    这篇文章主要为大家详细介绍了android模拟实现航拍遥控,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • kotlin浅析when与循环的使用

    kotlin浅析when与循环的使用

    这篇文章主要介绍了kotlin语言中when与循环的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Android自定义加载框效果

    Android自定义加载框效果

    这篇文章主要为大家详细介绍了Android自定义加载框效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • Android 内存泄漏的几种可能总结

    Android 内存泄漏的几种可能总结

    本文主要介绍 Android 内存泄漏的几种可能进行总结,这里整理了八种可以性,并一一介绍,有需要的小伙伴可以参考下
    2016-09-09
  • Android实现返回键功能

    Android实现返回键功能

    本文给大家介绍android实现返回键功能,返回键的操作方法,非常不错,具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-06-06
  • Android使用PullToRefresh实现上拉加载和下拉刷新效果的代码

    Android使用PullToRefresh实现上拉加载和下拉刷新效果的代码

    这篇文章主要介绍了Android使用PullToRefresh实现上拉加载和下拉刷新效果 的相关资料,需要的朋友可以参考下
    2016-07-07
  • Android实现水波纹扩散效果的实例代码

    Android实现水波纹扩散效果的实例代码

    这篇文章主要介绍了Android实现水波纹扩散效果的实例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05

最新评论