Android Developer指南中,对Android安全体系结构的核心有这么一个说法:默认情况下,任何应用程序都无权执行任何会对其他应用程序、操作系统或者用户产生负面影响的操作。这句话其实就很好的诠释了权限管理的意义,即用户才是手中设备的主人,没有用户的允许,设备不可以私自记录用户的通讯录,不可以上传用户的姓名和身份证号,更不可以偷偷地窃取属于用户的高级隐私。但在如今的手机程序中,特别是一些流氓应用,私自获取用户高级权限的现象也不少见。随着Android版本的更新,对于权限这一块也比以往做得更好了。这一次重新梳理权限管理环节,并通过实例展示在Android 6.0版本后的权限处理过程。

什么是Android权限?

权限(Permission),顾名思义是一种对信息访问的申请。Android的权限有上百种,例如应用程序尝试调用拨号权限、调用摄像头权限、调用读取短信权限、调用读取通讯录权限等等。对于这些权限,Android将其按照危险等级进行了划分分组,分成如下的三种类别:

  • 正常权限(PROTECTION_NORMAL):指的是应用程序需要访问的一些数据资源,但并不涉及到用户的隐私或者对其他应用程序无害。例如设置闹钟就是属于正常权限。Android在处理正常权限时并不会提示用户,而用户也没有办法取消这些正常权限
  • 签名权限(PROTECTION_SIGNATURE):指的是Android在安装时授予应用程序的权限,利用签名权限,两个签名相同的应用程序就可以进行安全的数据共享。
  • 危险权限(PROTECTION_DANGEROUS ):指的是直接触碰到用户隐私或者影响其他程序操作的权限,对于这一类的权限,Android会以弹窗的方式向用户进行问询,应用程序必须要经过用户的授权后才可以进行相应的行为

以危险权限为例,Android规定了如下的权限必须请求用户的许可。

Android权限获取的方式

对于程序中申请的权限,都应该在AndroidManifest.XML文件中进行注册,否则申请的权限将无法发挥作用。下图中的AndroidManifest文件中添加了打电话摄像头的权限。

Android权限获取可以分成两个阶段,在Android 6.0之前,所申请的权限只要在AndroidManifest文件中列举就可以了,并会在程序安装时全部显示在安装页面上,这个过程并不区分权限是否为常规权限还是正常权限。这种方式是造成早期Android系统在隐私性做的不好的直接原因,因为用户在安装应用程序时,很多时候并不会去仔细查看程序弹出的方框到底包含了哪些危险的权限,为了尽快的进入程序首页,一般都会同意全部弹出的权限,这就给了很多流氓程序肆意发挥的入口。下图展示了Android 5.0安装界面的部分危险权限截图。

Google显然也注意到了这一点,于是在Android 6.0中推出了一种运行时权限管理机制,这种机制对原有的权限处理方式进行了很大程度的改善:应用程序安装后,点开程序时,不再是列出程序申请的所有权限,而是将部分危险权限与应用本身的功能相关联。例如相机应用,只有当用户点击拍照按钮时,系统就会弹出申请摄像头的权限,这种方式将用户的注意力集中到了当下的操作上,使得用户有足够的时间和意愿去判定是否同意程序的权限申请,并且用户随时可以在设置中关掉授予程序的危险权限,从而极大程度上避免了对危险权限的放行,保护了用户的隐私。

Android 6.0之后的运行时权限处理机制很好的解决了危险权限的获取问题,它具有如下的两个行为:

  • 如果应用程序在当前的权限组(一组权限的集合)中没有任何权限,那么在请求权限时,系统会显示该权限组的请求对话框,例如程序请求CALL_PHONE权限,那么Android将弹出CALL权限对话框显示应用希望拨打电话功能。
  • 如果一个权限组中的任意一个权限被授权,那么该权限组中的其他权限都会被Android默认授权。例如上面的CALL_PHONE权限被允许,那么PHONE权限组中的其它权限,例如READ_PHONE_NUMBERS读取电话号码的权限就会默认被授权,并且不会向用户弹框显示权限申请过程。

运行时权限处理机制中的第二点的特性并不被Google推崇,Google认为后续的Android版本中这个特征可能会发生变化,并建议开发者应明确指出所需要的每一个权限。

Android实现权限管理

关于Android权限更详细的介绍可以在官方的Android Developer指南中查阅。重点是如何在实践中学会使用Android权限,后半部分将会以代码和流程图的方式展示Android权限管理。

Android权限处理可以分解为三个部分:

  1. 检查权限:权限是否为危险权限,正常权限会被系统默认允许,危险权限需要用户手动允许,所以我们的权限讨论范围是危险权限的获取,在Android中检查权限是否获取的方法是ContextCompat.checkSelfPermission(),这个方法返回一个int类型的PERMISSION_GRANTED或者PERMISSION_DENIED,一般来说,程序刚申请权限的时候都是处于PERMISSION_DENIED状态,因此需要后续的申请过程。
  2. 请求权限:当权限并没有被允许的情况下,就需要向用户请求处理权限申请,在应用层上则表现为Android系统会弹出一个对话框,提示用户进行操作。

从代码层面考虑,Android提供了一个requestPermissions()的调用方法来请求相应权限,这个方法接受目标Activity、 需要请求授权的权限组和识别权限请求的请求代码作为参数传递,并且它是一个异步的方法,并返回产生的结果。

  1. 处理权限响应:当用户对弹出的权限申请框进行响应后,Android会调用onRequestPermissionsResult()方法,将用户的响应作为参数传递。开发者必须使用@Override声明覆盖这个方法,来确认这个权限是否真的被用户所允许,并进行后续的业务逻辑编写。

权限获取的一般过程就是遵循上面的三个步骤进行的,但是千万不要忘记了所申请的权限一定要在AndroidManifest.xml中注册,不然就准备尝尝异常抛出铁拳的力量吧。

当然,更清晰明了的是用流程图来展示权限申请和授权的过程。

单个权限的获取过程

下面以获取打电话的权限为例,通过代码实现的方式来解释这个流程的具体做法。以下面一个Demo的页面为测试对象,只要点击获取电话权限按钮,就会弹出权限提示窗,然后允许该请求,就可以实现跳转到拨号页面进行通话的功能。

第一部分是检测权限部分。点击获取电话权限按钮,就会调用程序中的callPermission()这个方法,在callPermission中调用checkSelfPermission的方法进行权限检测,实参是当前的Activity对象和对应的权限,这个方法返回一个int类型的值,其中若权限允许则返回值为0的PERMISSION_GRANTED,否则返回值为-1的PERMISSION_DENIED,当权限已经被允许的情况下,直接调用else语句中的callPhone()方法,意味着直接可以拨打电话了。

当权限检测为未允许的情况下,进入请求权限状态,即if语句中的requestPermissions这个方法,这个方法会创建一个字符串数组,将请求的权限同一放入这个数组中,最后一个参数是一个int类型的requestCode,该值在后续的处理权限中发挥作用,并且这个值不一定取1,只要这个值大于等于0即可。为了方便起见,这里取1作为请求码。

 @Overridepublic void onClick(View view) {switch (view.getId()){case R.id.getCallPermission:Toast.makeText(MainActivity.this, "获取打电话权限", Toast.LENGTH_SHORT).show();callPermission();break;case R.id.getCameraPermission:Toast.makeText(MainActivity.this, "转至第二个页面", Toast.LENGTH_SHORT).show();Intent intent = new Intent(this, SecondActivity.class);startActivity(intent);default:break;}}/*** 查询app是否有相关权限* 如果有就直接调用写的方法* 没有的话就需要申请权限*/private void callPermission(){if(ActivityCompat.checkSelfPermission(MainActivity.this,Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){// 说明没有该权限,就需要申请权限ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CALL_PHONE}, 1);}else {callPhone();}}

当用户点击了权限的弹窗后,Android会调用下面的onRequestPermissionsResult的方法,这个方法接受从requestPermissions()方法传递的requestCode、权限字符串数组和用户响应数组这三种作为参数,用户响应数组中的元素个数应与申请的权限字符串数组中元素个数保持一致。requestCode的作用是作为请求权限时权限处理成功的一种标识,只有这个标识匹配正确了,才能进一步的核对用户响应数组中的元素是否与PERMISSION_GRANTED相等,从而验证权限是否真正的被用户所允许。所以上一步的requestCode在这里发挥了作用。应当注意的是,由于这个实例只用了一个权限,所以应该通过索引的方式来获取用户响应数组中的第一个元素grantResult[0]。

/*** 权限申请的回调结果* @param requestCode 请求码* @param permissions 请求权限* @param grantResults 授权结果,是一个int型数组,若有多个授权,则依次读取*/@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if(requestCode == 1){if(grantResults[0] == PackageManager.PERMISSION_GRANTED){callPhone();}else {Toast.makeText(this, "权限未授权!", Toast.LENGTH_SHORT).show();}}}/*** 打电话,注意异常处理,不然会报错*/private void callPhone(){try{Intent intent = new Intent(Intent.ACTION_CALL);Uri uri = Uri.parse("tel:" + 10086);intent.setData(uri);startActivity(intent);}catch (SecurityException e){e.printStackTrace();}}

对于单个的权限而言,上述的流程就可以完成权限获取的全部操作,在手机端运行程序,点击获取电话权限后就会弹出权限窗口,点击允许后转到电话拨打的界面。

那么如果想一次性申请多个权限,该如何处理这种需求?

多个权限的获取过程

假设需要一个按钮来获取两个权限:打电话权限和摄像头权限。处理的方式和上面的大同小异,如果你注意到上述请求权限和处理权限响应的方法中,它们都是接收一个权限字符串数组和用户响应字符串数组,那么问题就很好解决了。思路如下:

  • 构建一个申请权限的ArrayList
  • 检测权限,并将没有被授予允许的权限通通addArrayList
  • 转换ArrayList变为requestPermissions的参数
  • 依次读取用户响应数组中的grantCode,判断是否授权
  • 授权过程结束

下面的代码展示了如何一键处理两个权限的过程。

private void callAllPermissions(){List<String> permissionsList = new ArrayList<>();if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)!= PackageManager.PERMISSION_GRANTED){permissionsList.add(Manifest.permission.CALL_PHONE);}if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED){permissionsList.add(Manifest.permission.CAMERA);}//不为空,说明有需要授权的部分if(!permissionsList.isEmpty()){ActivityCompat.requestPermissions(this,permissionsList.toArray(new String[permissionsList.size()]), 1);}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);switch (requestCode){case 1:int resultLength = grantResults.length;//说明回调成功了,权限授权被允许if(resultLength > 0){for(int grantCode : grantResults){if(grantCode == PackageManager.PERMISSION_GRANTED){Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();}else{Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();}}}break;default:break;}}

上述的过程完成后,程序所需要的权限得到了满足,便可以继续的进行后续的业务逻辑。但是仍然要提醒一点,Android 6.0以后,权限是可以由用户手动关闭的,并不是永久授权,这意味着今天的授权成功并不代表着明天就不需要授权了,因此权限的检查是必须要有的一个步骤。

总结

在以前学习Android的时候接触过权限处理,所以这次结合业务上遇到权限处理的问题,借助Android Developer的指南,对Android 6.0后的权限问题进行了一次重新的梳理。通过实例和流程图来展示Android对于危险权限的获取过程和一些应该注意的地方。同时也应该时刻的关注官网的指南,因为权限问题可能随着版本的更迭而发生一些调整或改变,不然很容易出现代码一样但出现异常的情况。

更多文章可以在公众号追风栈Binary中查看,如果能帮助到你一点点,那就太好了~

android 一个字符串分两行显示_重新梳理Android权限管理相关推荐

  1. android 一个字符串分两行显示_【Android】DataBindinglt;中gt;

    DataBindingUtil类 DataBinding不仅可以绑定Activity还可以绑定视图内容(View) // 视图static extends ViewDataBinding> T ...

  2. Android TextView 实现一个单词分两行显示

    今天遇到一个需求,TextView实现自动换行时一个英文单词能够换行显示,使布局整齐.通过网上查询,确定实现逻辑如下: 自定义TextView,重写其onMeasure方法,在测量textView的宽 ...

  3. 猿创征文|Android 11.0 12.0Launcher3中app列表页的app名称分两行显示

    1.概述 在Launcher3桌面显示列表中,由于在app列表页中,由于有些app名称长度有些长,而系统默认显示一行,显示不下就省略号显示,由于页面高度有多余的,所以要求显示全app名称,这就需要看哪 ...

  4. R语言ggplot2可视化图例放置在图像底部(bottom)并分两行显示实战

    R语言ggplot2可视化图例放置在图像底部(bottom)并分两行显示实战 目录 R语言ggplot2可视化图例放置在图像底部(bottom)并分两行显示实战

  5. Java黑皮书课后题第7章:*7.22(计算一个字符串中大写字母的数目)编写程序,从命令行输入一个字符串,然后显示字符串中大写字母的数目

    7.22(计算一个字符串中大写字母的数目)编写程序,从命令行输入一个字符串,然后显示字符串中大写字母的数目 题目 题目描述 破题 代码 运行实例 题目 题目描述 7.22(计算一个字符串中大写字母的数 ...

  6. Java黑皮书课后题第5章:*5.50(对大写字母计数)编写一个程序,提示用户输入一个字符串,然后显示该字符串中大写字母的数目

    5.50(对大写字母计数)编写一个程序,提示用户输入一个字符串,然后显示该字符串中大写字母的数目 题目 题目概述 运行示例 破题 代码 题目 题目概述 5.50(对大写字母计数)编写一个程序,提示用户 ...

  7. 存货核算凭证无法删除的修复 U8 10.1存货核算中的凭证列表显示时,部分凭证会分两行显示,且不能删除...

    一般是摘要过长的原因  U8 10.1存货核算中的凭证列表显示时,部分凭证会分两行显示,且不能删除 您好:此问题应是明细帐中有不可见非法字符引起,多数是在摘要列,请备份数据后,用此脚本进行整理 upd ...

  8. 用汇编语言写一个程序,它先接收一个字符串,然后显示其中数字符的个数、英文字母的个数和字符串的长度

    ## 用汇编语言写一个程序,它先接收一个字符串,然后显示其中数字符的个数.英文字母的个数和字符串的长度 DATAS SEGMENT str1 db 0dh,0ah,'please enter a st ...

  9. c与指针 从一个字符串中提取子串_利用双指针解LeetCode第1297题:子串的最大出现次数

    题目描述(难度中等) 给你一个字符串 s ,请你返回满足以下条件且出现次数最大的任意子串的出现次数: 子串中不同字母的数目必须小于等于 maxLetters . 子串的长度必须大于等于 minSize ...

最新文章

  1. 虚幻4视频笔记002:精简StarterContent文件夹体积
  2. Centos7 Docker Jenkins ASP.NET Core 2.0 自动化发布和部署
  3. fatal: No configured push destination
  4. 做毕设时遇到的一些问题,以及一些小技巧
  5. 对话MPEG创始人Leonardo Chiariglione: MPEG精神将在MPAI中延续
  6. 866. 试除法判定质数
  7. linux 文件读取 监控,linux 文件系统的监控
  8. 整合Spring Cloud微服务分布式云架构技术点
  9. 一个循环递归遍历问题
  10. bs4 乱码_python使用beautifulsoup乱码问题
  11. Ttest(T检验)
  12. 【3D建模制作技巧分享】用3dsmax制作炫酷的机器人模型
  13. 服务窗口关闭了,服务就停止了,真特么烦 pm2了解一下
  14. 安装docker-ce报错
  15. 人类特有本能:保护族群老弱病残
  16. 2021年高考语文作文成绩查询,2021年国家高考语文作文题
  17. 泰课在线android,泰课在线rollaball
  18. 国开机考2020计算机应用基础,2020年武汉理工大学《计算机接口与通讯》作业与机考题库.docx...
  19. 物理机连接无线网络的配置
  20. EJB注解详细说明1

热门文章

  1. 数据分析学习笔记——数据可视化
  2. 使用 ABAP 代码解析一个 class 的所有方法
  3. SAP 电商云 Spartacus UI quick order 产品 live search 的实现
  4. SAP Spartacus B2B Org Unit树状结构的ghost数据
  5. Angular里interpolation text节点的创建逻辑,单步调试
  6. Angular 依赖注入的学习笔记
  7. 使用page-slot显示SAP Spartacus section里包含的Component和layout设计
  8. SAP Spartacus MyCompany菜单里Org unit的Add按钮Accessibility问题初始分析
  9. 如何使用配置的方式修改SAP C4C UI的字段标签,以及背后的工作原理
  10. 如何关闭Windows10任务栏里的应用图标