1.引子

在换到Android手机之前,对Android系统的印象是这系统app的跑马场,app可以任意索取各种权限,随意窃取各种隐私,换手机后才知道Android系统对权限的管理已有很大的改观,索取的每个危险权限都需要提示用户,当然Android只是尽可能提示用户,还是存在着用户不同意就不给用的情况。

权限管理的改进给开发者增加了一定工作量,申请危险权限不再是简单的在AndroidManifest.xml添加一行代码的事,而是需要提示用户进行动态申请。了解动态申请之后,觉得没多复杂,但不了解时,只知道在网上拷贝现成代码片段,碰到需要申请新的权限就不知道从何下手。我曾经粘贴了几段动态申请权限代码,就是因为不了解原理,只会复制粘贴,代码虽然能够运行,但无比臃肿。

为此通过此文梳理Android权限,以便掌握Android权限管理,拒绝做Copy工程师。

2.权限的作用

权限的目的是保护Android用户的隐私。作为一个可以任意定制的开源系统,权限真是用户隐私最后的屏障,Android系统要求,在默认情况下,任何应用程序无权执行会对其他应用程序、操作系统或用户产生不利影响的任何操作。包括读写用户的私人数据(例如联系人或电子邮件),读写其他应用程序的文件,访问网络等等。要执行这些操作,Android应用必须获得对应的权限。

Android有上百种权限,可分为三大类,一类是普通权限,一类是签名权限,还有一类是危险权限。

其中普通权限是指那些不会威胁到用户安全和隐私的权限,例如设置闹钟权限。授予app普通权限只需要在AndroidManifest.xml文件里声明,系统会自动授权,不需要用户确认,用户也无法做撤销操作。

第二种是签名权限,这类权限同样是在应用安装时由系统授予,不过并不是无条件授予,想使用权限的应用程序必须与定义该权限的应用程序使用相同的证书才行,例如应用A使用证书A签名,定义了一个签名权限,应用B想使用这个权限,必须由证书A签名。签名权限使用的场景如一个公司有多个app,为了能让这些app能够相互调用,但不希望被外部app调用,就可以通过自定义一个签名调用权限实现。

最后再来看第三类危险权限,危险权限之所以被危险,是因为这类权限涉及到用户个人敏感数据资源,或者影响用户存储的数据或者其他应用程序的数据,例如读取用户联系人,打开麦克风等,江湖上一直有传言,目前许多app会偷偷打开麦克风窃听用户对话,然后根据对话内容精准推送广告,这类传言像是都市传说,因为具有神秘性能广泛传播,要知道,原版Android系统中,应用索取危险权限必须需要向用户提示,在用户许可之前,应用是无法获取权限的。不过Android系统毕竟是开源的,将原生Android权限管理功能修改倒是有可能虽然用户没同意,但app仍可以获得权限,这话题就在本文之外了,个人认为有其他更好的方法来窃取隐私,窃听对话是成本较高的那种,用起来不值得。

如前所述,权限有上百种,一一记住不现实,其实我们只要知道哪些是危险权限,危险权限之外都是普通权限。

危险权限总共9个分组,24个权限,如果我们申请的权限不在这个表中,那就说明是普通权限,而权限分组意思是组内的这些权限同属于一个组,用户同意授权一个权限组,则组内的所有权限都会授予,比如,应用被授予READ_EXTERNAL_STORAGE权限之后,如果再申请WRITE_EXTERNAL_STORAGE权限,系统会立即授予该权限,不再向用户提示。

3.申请权限步骤和示例

  1. 普通权限申请很简单,只需要在AndroidManifest.xml文件申请即可,例如申请设置闹铃的权限
<uses-permission android:name="android.permission.SET_ALARM" />
  1. 签名权限申请类似,只需要修饰protectionLevel成signature即可,例如设置一个自定义权限成签名权限,代码如下,其他应用申请这个权限时必须具有相同的签名才能授予

    <permissionandroid:name="com.test.permission.act"android:protectionLevel="signature"/>
    
  2. 申请危险权限重点说一下,一方面和普通权限一样,仍需要在AndroidManifest.xml文件声明,另一方面,还需要额外动态申请。下面以申请存储读写权限来作为例子说明。
  • 在AndroidManifest文件中声明,这一步不可少

     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    • 在应用启动代码中检查权限,确认应用是否已经拥有读写存储的权限。这部分是在代码中实现了,所以叫动态申请。Android中使用ContextCompat.checkSelfPermission()检查权限的授权情况,这个方法第一个参数是上下文Context,第二个参数是所要申请权限的名称,名称当然不能随便写阿猫阿狗,而是有特定名称,建议直接调Android在Manifest.permission中已定义好的名称,比如现在要申请的读外部存储权限是Manifest.permission.WRITE_EXTERNAL_STORAGE。该方法返回一个int类型的PERMISSION_GRANTED(同意)或者PERMISSION_DENIED`(拒绝)。一般来说,程序初次安装后,所申请的权限的时候都是处于PERMISSION_DENIED状态,需要提出申请,用户同意之后不需要再次申请,除非卸载应用重新安装或者到系统设置里把权限给关了;

    • 接下来是申请权限,申请使用的方法requestPermissions(),该方法传入参数有三个,第一个是Activity、 第二个是需要请求授权的权限字符串数组,可以把想申请的权限名称都列入其中,第三个是识别权限请求的请求代码,在权限申请的回调函数onRequestPermissionsResult()用得着,该值必须大于或等于0,其作用在回调函数里再详细说明,这里只要理解成是一个自定义的标记。需要注意的是,申请权限是异步处理,也就是说,代码不会阻塞在等用户点击,而是用户点击后再回调onRequestPermissionsResult()。以上两个步骤的代码如下:

 //检查应用是否已经拥有权限if(ActivityCompat.checkSelfPermission(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){// 说明没有该权限,就需要申请权限ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);}else {//已经拥有权限,做进一步操作}
  • 接下来是覆写申请权限回调函数onRequestPermissionsResult(),对权限申请做后续处理,该回调函数有三个返回结果,第一个requestCode,这个参数就是在requestPermissions()提到的识别权限的请求代码,作用就是一个回执单号,根据这个单号我们能确定是我们申请权限的处理结果,也就是说,在申请权限时传入这个参数,在处理结束后,回调函数原封不动给回来,这样我们就知道是不是我们的处理结果;第二个参数是权限字符串数组,也就是我们在requestPermissions()填的权限字符串数组;第三个参数用户响应的数组,用户的对每个申请权限的批复情况就是在这个数组里,这个数组的个数是和申请权限数组是一一对应的。代码如下:
  @Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {//通过requestCode来识别是否同一个请求if (requestCode == 1){if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){//用户同意执行的操作}else{//用户不同意不同意执行的操作,例如提示用户不同意不给用。。。}}}

以上如果申请单个权限,如果申请多个权限又怎么操作呢?基本步骤和申请单个权限类似,但因为是多个权限,还需要做一下额外处理,例如怎么判断是否每个权限都授权了。下面以多申请一个录音权限来说明

  • 同样,首先在AndroidManifest.xml做声明
      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.RECORD_AUDIO" />
  • 准备工作是创建一个权限字符串数组和声明一个权限列表list,其中列表用于判断每个权限的处理情况

    String[] permissions = new String[]{Manifest.permission.RECORD_AUDIO,Manifest.permission.READ_EXTERNAL_STORAGE};
    List<String> mPermissionList = new ArrayList<>();
    
    • 判断每个权限授权情况,未同意的列入申请名单,然后申请权限
    private void myRequestPermission() {mPermissionList.clear();//逐个判断权限是否已经通过for (int i = 0; i < permissions.length; i++) {if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {            //如果未授权,则添加到列表中mPermissionList.add(permissions[i]);}}//申请权限,如果列表不为空,说明有权限需要申请if (mPermissionList.size() > 0) {//有权限没有通过,需要申请ActivityCompat.requestPermissions(this, permissionsList.toArray(new String[permissionsList.size()]), 1);}else{//已有权限,做进一步操作}}
  • 覆写请求权限回调的方法,做后续处理
 @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;}}

4.总结

经过了解Android权限后,可以看出申请权限过程不是很复杂,普通权限比较简单,只需要在AndroidManifest.xml中声明即可,危险权限不仅需要在AndroidManifest.xml声明,同时还需要在代码中动态申请,首先是使用checkSelfPermission()检查是否某个危险权限是否已授权,如果没有授权,则requestPermissions()申请授权,记得这是异步处理,代码不会阻塞在等待用户授权位置,接下来就是处理授权情况,系统回调onRequestPermissionsResult通知我们处理结果,我们根据这个结果做进一步处理。同时申请多个权限稍微复杂一点,需要处理每个权限的处理情况。

Android权限申请的学习实践相关推荐

  1. android权限申请Permission

    代码地址如下: http://www.demodashi.com/demo/12432.html android在6.0系统以后,权限申请变得麻烦起来,今天介绍一个超级好用的权限申请库,我在使用中经过 ...

  2. Android权限申请

    Android权限申请分为两种情况:一种是普通权限:一种是危险权限. 对于普通权限的申请和正常的权限申请一样,只需要在AndroidManifest.xml中使用<uses-permission ...

  3. Android权限申请完全解析(一):Android自带的权限申请

    1.为什么要权限申请 6.0以上就需要了,别问为什么.(不是重点,自行搜索) 2.如何进行权限申请 Android自带的权限申请 EasyPermission权限申请 Ps:EasyPermissio ...

  4. android权限申请方法,安卓开发Android6+权限申请管理用户拒绝权限一键解决方案...

    问题: android 开发中,权限是一个重要的环节,不可避免的环节.尤其是刚入行的小白们,认为在配 AndroidManifest 中加入权限表就万事大吉. 没想自己测试时还是正常,打包发布别人安装 ...

  5. android京东打不开,京东商城Android权限申请流程分析

    京东动态申请定位权限分析 京东权限申请流程.png 1.安装完成后,权限状态为询问状态,此时,进入应用提示 首次进入App提示信息.png 1.1点击取消,对话框消失,Toast提示信息如下 需在手机 ...

  6. Android权限申请和网络监听封装

    欢迎使用 红叶岭谷-(网络.权限) 封装包 在应用程序app开发过程中,我们经常用到网络的判断,网络 以及 Android6.0后的权限申请 每次开发都是一个不小的工程量,因此为了方便我专门将他们封装 ...

  7. Android权限申请库——EasyPermissions使用详解和打开相册方法

    1.添加依赖 dependencies {implementation 'pub.devrel:easypermissions:3.0.0' } 2.在AndroidManifest文件中添加需要的权 ...

  8. Android权限申请之动态申请权限

    先上图: 对于一些危险权限在AndroidManifest清单文件中申请之后,还需要得到用户的许可并打开,才算是真正的开启了这个权限.所以可以使用动态申请权限,对于某个功能,如果需要开启某个权限,在用 ...

  9. Android权限申请哪些需要动态申请

    动态权限:这类权限在需要的时候,需要我们动态申请 比如:当我们需要打开相机拍摄照片的时候需要我们通过代码的方式在需要的地方去申请权限. 具体的权限分组情况如下表: group:android.perm ...

最新文章

  1. swift禁用webView对H5中数字,链接,日期,地址,电话号码做解析
  2. 使用Mysql数据库完成增删改查综合案例(JSP页面)
  3. kafka的反序列化类KafkaDeserializationSchema的使用(还没整理完)
  4. 幼儿园 c语言,【资源学习】c语言程序代码,登录幼儿园200个小朋友的数据
  5. oracle连接工具类,c# .net oracle连接工具类
  6. 老板喜欢动脑子工作的人
  7. logback日志大量写磁盘导致微服务不能正常响应的解决方案
  8. 【JavaScript】JS的Array的用法总结
  9. 智能机器人建房子后房价走势_日本房价走势分析:房产投资是否“未来可期”?...
  10. GSM/CDMA/GPRS介绍
  11. NTP 服务的配置和使用
  12. 胆囊结石的危害你了解多少?
  13. 【开源】Easy系列开源与免费流媒体音视频方案汇总(持续更新)
  14. Spring Messaging 远程代码执行漏洞分析(CVE-2018-1270)
  15. 银行业法律法规与综合能力 第二章 银行业务 32%
  16. 赞!这款国产的SSH工具,好用到爆!
  17. 6个P2P流媒体开源项目介绍
  18. linux 安全狗 屏蔽ip,网站安全狗ip黑名单功能及使用方法教程
  19. explorer.exe系统调用失败
  20. 9行代码实现图片上传和预览(自定义按钮上传)

热门文章

  1. boost::hana::extract用法的测试程序
  2. boost::geometry::bg::model::multi_linestring用法的测试程序
  3. boost::endian::endian_load的测试程序
  4. C++实现教学信息管理系统
  5. VTK:PolyData之DownsamplePointCloud
  6. VTK:图片之ImageMapper
  7. OpenCV限制对比度自适应直方图均衡(CLAHE)的实例(附完整代码)
  8. OpenCV解码格雷码模式
  9. OpenGL多光源Multiple lights
  10. C++trie类的实现(附完整源码)