Android 6.0 运行时权限处理解析

1.概述


不知道大家有没有遇到过这种情况,开发app的时候发现自己手机选择照片是正常的,测试那边的一台手机怎么搞都不行,然后查看版本之后才发现是6.0的手机。
  
  随着Android 6.0 7.0 我们开发者所要应对的主要就是新版本SDK带来的一些变化,既然是程序员那么我们肯定就特别关注开发部分的变化,其中之一就是权限处理。那么在6.0及以上版本我们的危险权限都需要在运行的时候去申请,之前都是在清单文件中配置即可,现在就不行了需要加代码申请。
  

这里写图片描述

2.运行时权限的检测


2.1. Android6.0之后的权限差别
  
  对于6.0以下的权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装。而在6.0以后,我们可以直接安装,当app需要权限是会给予用户提示用户可以选择同意和拒绝。

新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、打电话等等。

看几个Normal Permissions:

1INTERNET 2GET_PACKAGE_SIZE 3ACCESS_NETWORK_STATE 4ACCESS_NOTIFICATION_POLICY 5ACCESS_WIFI_STATE 6CHANGE_WIFI_STATE 7VIBRATE

看几组Dangerous Permissions:

1group:android.permission-group.CONTACTS 2 permission:android.permission.WRITE_CONTACTS 3 permission:android.permission.GET_ACCOUNTS 4 permission:android.permission.READ_CONTACTS 5 6group:android.permission-group.PHONE 7 permission:android.permission.READ_CALL_LOG 8 permission:android.permission.READ_PHONE_STATE 9 permission:android.permission.CALL_PHONE 10 permission:android.permission.WRITE_CALL_LOG 11 permission:android.permission.USE_SIP 12 permission:android.permission.PROCESS_OUTGOING_CALLS 13 14group:android.permission-group.CAMERA 15 permission:android.permission.CAMERA 16 17group:android.permission-group.STORAGE 18 permission:android.permission.READ_EXTERNAL_STORAGE 19 permission:android.permission.WRITE_EXTERNAL_STORAGE

你会发现dangerous permissions,危险权限都是一组一组的,这是个什么概念呢?又或是有什么用呢?如果app运行在Android 6.x的机器上,对于授权机制是这样的。如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。
  
  
2.2. 代码变化

**2.2.1.**之前写都是老套路直接上代码(已电话拨打为例):

1 Intent intent = new Intent(Intent.ACTION_CALL); 2 Uri data = Uri.parse("tel:" + mPhoneNumber); 3 intent.setData(data); 4 startActivity(intent);

**2.2.2.**但是现在不行啦,我们需要去检测该权限有没有背用户授予过,如果没有则需要申请打电话权限,如果有授予过可以直接拨打电话。
ContextCompat.checkSelfPermission:检测权限
ActivityCompat.requestPermissions:申请权限

1// ContextCompat.checkSelfPermission() 2// 方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。 3// 当返回GRANTED表示有该权限,DENIED表示没有该权限。 4 5if(ContextCompat.checkSelfPermission(this,Manifest.permission.CALL_PHONE) 6 != PackageManager.PERMISSION_GRANTED){ 7 8 // 没有该权限 申请打电话权限 9 // 三个参数 第一个参数是 Context , 第二个参数是用户需要申请的权限字符串数组,第三个参数是请求码 主要用来处理用户选择的返回结果 10 11 ActivityCompat.requestPermissions(this,new String[]{"Manifest.permission.CALL_PHONE"},CALL_PHONE_REQUEST_CODE); 12 }else { 13 // 有该权限,直接打电话 14 Intent intent = new Intent(Intent.ACTION_CALL); 15 Uri data = Uri.parse("tel:" + 137XXXXXXXX); 16 intent.setData(data); 17 startActivity(intent); 18 }

2.2.3. 处理回调
  如果用户同意或是拒绝那么会回调onRequestPermissionsResult(),别看错了不是onActivityResult()

1 @Override 2 public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 3 if(requestCode == CALL_PHONE_REQUEST_CODE){ 4 if (grantResults !=null&&grantResults[0] == PackageManager.PERMISSION_GRANTED) { 5 // Permission Granted 通过 打电话 6 7 Intent intent = new Intent(Intent.ACTION_CALL); 8 Uri data = Uri.parse("tel:" + 137XXXXXXXX); 9 intent.setData(data); 10 startActivity(intent); 11 } else { 12 // Permission Denied 被拒绝 13 Toast.makeText(this,"权限被拒绝了",Toast.LENGTH_SHORT).show(); 14 } 15 } 16 }

2.2.4. 简单的例子

1public class MainActivity extends AppCompatActivity { 2 // 打电话权限申请的请求码 3 private static final int CALL_PHONE_REQUEST_CODE = 0x0011; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 } 10 11 public void phoneClick(View view){ 12 if(ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) 13 != PackageManager.PERMISSION_GRANTED){ 14 Toast.makeText(this, "申请权限", Toast.LENGTH_SHORT).show(); 15 ActivityCompat.requestPermissions(this, 16 new String[]{"Manifest.permission.CALL_PHONE"}, CALL_PHONE_REQUEST_CODE); 17 }else { 18 callPhone(); 19 } 20 } 21 22 /** 23 * 拨打电话 24 **/ 25 private void callPhone() { 26 Intent intent = new Intent(Intent.ACTION_CALL); 27 Uri data = Uri.parse("tel:147****2514"); 28 intent.setData(data); 29 startActivity(intent); 30 } 31 32 @Override 33 public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 34 super.onRequestPermissionsResult(requestCode, permissions, grantResults); 35 if(requestCode == CALL_PHONE_REQUEST_CODE){ 36 if (grantResults !=null&&grantResults[0] == PackageManager.PERMISSION_GRANTED) { 37 // Permission Granted 38 callPhone(); 39 } else { 40 // Permission Denied 41 Toast.makeText(this,"权限被拒绝了",Toast.LENGTH_SHORT).show(); 42 } 43 } 44 } 45}

上面就是6.0以上的版本运行时权限处理,但是我们会发现一个问题,如果都得这么干那需要些多少代码量?下面我们就利用反射加注解的方式封装我们的权限处理框架,请看这里Android 6.0 运行时权限封装框架

这里写图片描述

  
  项目的代码不能够发给大家,里面涉及到后台接口以及数据加密,如果大家感兴趣可以看一下我录的视频:http://pan.baidu.com/s/1bpqqkGn

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Android开发 - 获取Android设备的唯一标识码(Android 6.0或更高)

在我们的APP开发中,通常需要获取到设备的唯一标识。在Android6.0之前,有很多方法我们可以方便获取到硬件的唯一标识,但是在Android6.0之后,Android系统大幅限制了我们获取设备的硬件信息。Android6.0之前的方法(已过时)1.DEVICE\_ID通getSystem