Android 权限管理
1.权限分级
Android中权限分为四类,不同级别的权限对应不同的认证方式。
①normal:
只要申请了就可以使用(在AndroidManifest.xml中添加< uses-permission>标签),安装时不需要用户确认;
②dangerous:
安装时需要用户的确认才可使用;
③signature:
只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时(如果是申请系统权限,则需要与系统签名相同),才能将权限授给它;
④signatureOrSystem:
签名相同,或者申请权限的应用为系统应用(在system image中)
上述四类权限级别同样可用于自定义权限中。如果开发者需要对自己的应用程序(或部分应用)进行访问控制,则可通过在AndroidManifest.xml中添加< permission>标签,将其属性中的protectionLevel设置为上述四类级别中的某一种来实现。
2.Android所有权限:
需要用户手动赋予的权限( Dangerous Permissions):
日历 READ_CALENDAR
日历 WRITE_CALENDAR
相机 CAMERA
联系人 READ_CONTACTS
联系人 WRITE_CONTACTS
联系人 GET_ACCOUNTS
位置 ACCESS_FINE_LOCATION
位置 ACCESS_COARSE_LOCATION
麦克风 RECORD_AUDIO
电话 READ_PHONE_STATE
电话 CALL_PHONE
电话 READ_CALL_LOG
电话 WRITE_CALL_LOG
电话 ADD_VOICEMAIL
电话 USE_SIP
电话 PROCESS_OUTGOING_CALLS
传感器 BODY_SENSORS
短信 SEND_SMS
短信 RECEIVE_SMS
短信 READ_SMS
短信 RECEIVE_WAP_PUSH
短信 RECEIVE_MMS
存储 READ_EXTERNAL_STORAGE
存储 WRITE_EXTERNAL_STORAGE
注意:如果应用程序请求在AndroidManifest中列出的危险权限,并且应用程序已经在同一权限组中具有另一个危险权限,系统会立即授予权限,而不会与用户进行任何交互。例如,如果一个应用程序先前已经请求并被授予READ_CONTACTS权限,然后它请求WRITE_CONTACTS(同属于联系人一组),系统会立即授予该权限,不会再弹出权限授予询问的对话框。
3.Android安全架构规定:默认情况下,任何应用都没有权限执行对其他应用、操作系统或用户有不利影响的任何操作。这包括读写用户的私有数据(如联系人或电子邮件等)、读写其他应用的文件、执行网络访问、使设备保持唤醒状态等。
如果要使用这些受保护的设备功能,首先要在应用的清单文件(AndroidManifest.xml)中添加一个或多个 < uses-permission>标记:
< manifest xmlns:android=“http://schemas.android.com/apk/res/android”
package=“com.android.app.myapp” >
< uses-permission android:name=“android.permission.RECEIVE_SMS” />
…
< /manifest>
如果您的应用在其清单中列出正常权限(即不会对用户隐私或设备操作造成很大风险的权限),系统会自动授予这些权限。如果您的应用在其清单中列出危险权限(即可能影响用户隐私或设备正常操作的权限),系统会要求用户明确授予这些权限。
Android 发出权限请求的方式取决于系统版本:
①如果设备运行的是Android 6.0(API 23)或更高版本,并且应用的targetSdkVersion是23或更高版本,则应用将在运行时向用户请求权限(Runtime Permissions)。用户可随时撤销权限,因此应用每次运行时都应该检查自身是否具备所需的权限。
②如果设备运行的是Android 5.1(API 22)或更低版本,并且应用的targetSdkVersion是22或更低版本,则系统在用户安装应用时就要求用户授予权限。如果更新应用时又新增了权限,系统会在用户更新应用时要求授予该权限。用户一旦安装应用,他们撤销权限的唯一方式是卸载应用。
注意:从Android 6.0(API 23)开始,用户可以在任何时候撤销应用的某个权限,即使应用的targetSdkVersion小于23。因此一定要保证在请求授权失败时应用表现良好,无论你的应用的API等级是多少。
4.正常权限和危险权限
系统权限分为4个保护级别。需要了解的两个最重要保护级别是正常权限和危险权限:
①正常权限(Normal permissions):
正常权限涵盖了应用需要访问其沙盒外部的数据或资源,但对用户隐私或其他应用操作风险很小的区域。例如,设置时区的权限就是正常权限。如果应用声明其需要正常权限,系统会自动向应用授予该权限。
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
②危险权限(Dangerous permissions):
危险权限涵盖了应用需要那些涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如,读取用户的联系人的权限就属于危险权限。如果应用声明其需要危险权限,则用户必须明确向应用授予该权限。
为了更好地对权限进行管理和描述,将权限进行分组,所有危险的Android系统权限都属于权限组。
如果设备运行的是Android 6.0(API 23)或更高版本,并且应用的targetSdkVersion是23或更高版本,则当用户请求危险权限时系统会发生以下行为:
①如果应用请求一个已经在其清单文件中列出的危险权限,并且应用当前没有拥有该权限组的任何权限,那么系统就会向用户显示一个对话框询问用户是否授权,该对话框的描述应用想要访问的权限组而不是组内的特定权限。例如,如果一个应用请求READ_CONTACTS权限,系统会弹出对话框告知用户应用需要访问设备的联系人,如果用户允许授权,那么系统将授予应用所需的权限。
②如果应用请求一个已经在其清单文件中列出的危险权限,并且应用当前已经拥有了该权限组的其它危险权限,系统会立即授予该权限而不需要通知用户。例如,如果一个应用之前已经请求过并已经被授予了READ_CONTACTS权限,那么之后它请求WRITE_CONTACTS时系统将立即授予该权限。
CALENDAR权限组包括READ_CALENDAR、WRITE_CALENDAR。
CAMERA权限组包括CAMERA。
CONTACTS权限组包括READ_CONTACTS、WRITE_CONTACTS、GET_ACCOUNTS。
LOCATION权限组包括ACCESS_FINE_LOCATION、ACCESS_COARSE_LOCATION。
MICROPHONE权限组包括RECORD_AUDIO。
PHONE权限组包括READ_PHONE_STATE、CALL_PHONE、READ_CALL_LOG、WRITE_CALL_LOG、ADD_VOICEMAIL、USE_SIP、PROCESS_OUTGOING_CALLS。
SENSORS权限组包括BODY_SENSORS。
SMS权限组包括SEND_SMS、RECEIVE_SMS、READ_SMS、RECEIVE_WAP_PUSH、RECEIVE_MMS。
STORAGE权限组包括READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE。
5.运行时权限(RuntimePermissions )
从Android 6.0(API 23)开始,用户就可以在应用运行时而不是安装时授予应用权限了。由于用户不需要在安装和升级应用时给应用授权,应用的安装升级也更加流畅了。
也就是说,第一次请求权限时,系统会向用户弹出一个权限请求对话框,如:
如果用户点击了拒绝,那么之后shouldShowRequestPermissionRationale()方法将返回true,并且再次请求该权限时会出现"不再询问"复选框(Don’t ask again):
如果没有勾选"不再询问"并点击了拒绝,那么再次请求该权限时系统依然会向用户显示权限请求对话框。如果此时勾选了"不再询问"并点击了拒绝,那么之后shouldShowRequestPermissionRationale()方法将返回false,并且请求该权限时系统将不会向用户显示权限请求对话框(系统会立即拒绝该权限请求并调用你的onRequestPermissionsResult() 回调方法并传递PERMISSION_DENIED)。
为了简化版本判断等代码逻辑,我们可以直接使用Android支持库中的API来检查和请求权限。
6.动态申请权限的方法:
①首先,需要在AndroidManifest.xml静态申请权限,否则无法动态申请权限。
以下代码位置不能放错(在application之外):
< uses-permission android:name=“android.permission.上表的权限字符” />
②权限检查
为了检查当前是否拥有某一权限,可以调用ContextCompat.checkSelfPermission()方法。
如果应用当前拥有该权限,该方法返回PackageManager.PERMISSION_GRANTED,应用可以继续接下来的操作。如果应用当前没有该权限,该方法返回PackageManager.PERMISSION_DENIED,应用就必须明确地向用户请求授权。
为了给用户解释为什么需要该权限,Android提供了一个工具方法shouldShowRequestPermissionRationale(),如果应用之前请求过该权限但用户拒绝了该方法就会返回true。如果用户之前拒绝了权限请求并且勾选了权限请求对话框的”不再询问”,该方法会返回false,如果设备策略禁止该应用获得该权限也会返回false。
如果应用没有获得所需的权限,应用就必须调用requestPermissions()方法请求相应的权限。传过去权限列表和一个整型权限请求码,该方法是异步的:在用户操作完请求授权对话框后系统会调用应用的回调方法传给结果和之前requestPermissions()中的权限请求码:
if(ContextCompat.checkSelfPermission(this,Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
// 我们应该给用户个解释? if(ActivityCompatible.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_CONTACTS)) {
// 向用户显示一个解释,要以异步非阻塞的方式。该线程将等待用户响应!等用户看完解释后再继续尝试请求权限
} else {
// 不需要向用户解释了,我们可以直接请求该权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); //MY_PERMISSIONS_REQUEST_READ_CONTACTS 是应用自定义的一个int常量,用户唯一标识一个权限请求以便回调时进行判断
}
}
注意:当你的应用调用requestPermissions()方法时,系统会向用户展示一个标准对话框,你的应用不能修改也不能自定义这个对话框,如果你需要给用户一些额外的信息和解释你就需要在调用requestPermissions()之前像上面一样" 解释为什么应用需要这些权限"。
在java代码中写动态申请权限的逻辑(这是官网的写法):
public void requestPower() {
//判断是否已经赋予权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.上表权限字符) != PackageManager.PERMISSION_GRANTED) {
//如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。
if ( ActivityCompat.shouldShowRequestPermissionRationale this, Manifest.permission.上表权限字符)) {
//这里可以写个对话框之类的项向用户解释为什么要申请权限,并在对话框的确认键后续再次申请权限.它在用户选择"不再询问"的情况下返回false
} else {
//申请权限,字符串数组内是一个或多个要申请的权限,1是申请权限结果的返回参数,在onRequestPermissionsResult可以得知申请结果
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.上表权限字符,}, 1);
}
}
}
处理权限请求的响应结果:
当应用请求权限时,系统会向用户显示一个权限请求对话框。当用户响应时,系统会调用应用的onRequestPermissionsResult()方法并把用户响应传给它。这就要求应用重写该方法以判断权限是否被授予了。这个回调也会接受之前调用requestPermissions()方法时的请求码。
例如应用请求READ_CONTACTS权限,那么回调方法可能会是这样:
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// 如果请求被取消了,那么结果数组就是空的
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限被授予了,你可以随便访问联系人了
} else {
// 权限请求被拒绝了,不能继续依赖该权限的相关操作了
}
return;
}
// case其它权限请求…
}
}
当系统请求用户授予权限时,用户可以选择告诉系统不要再请求该权限了。这种情况下,无论应用在什么时候使用requestPermissions()再次请求该权限,系统都会立即拒绝该请求。系统会调用你的onRequestPermissionsResult() 回调方法并传递PERMISSION_DENIED,如果用户再次明确拒绝了你的请求,系统将采用相同方式操作。这意味着当你调用requestPermissions()时,你不能假设已经发生了与用户的任何直接交互。
7.注意
为了让应用有更好的用户体验,动态请求权限有两个场景要特别注意,一个就是用户多次拒绝权限申请,一个就是用户点击了拒绝并勾选了不再询问或者设备策略禁止该应用获得该权限。这两种情况下,如果用户还想使用该权限下的功能就需要你的应用自己定制用户引导了。
第一种情况,是因为用户不理解你为什么要申请这个权限才拒绝你的权限申请,所以这种情况下,你可以在请求权限(弹出权限请求对话框)之前向用户显示一个对话框向用户解释为什么你的应用需要这个权限:
当用户点击确定后再请求权限(弹出权限请求对话框)用户就很容易授予该权限了。要在shouldShowRequestPermissionRationale()返回true时显示这个对话框。
第二种情况,系统已经无法再申请权限时向用户弹出权限申请框,你可以显示一个对话框引导用户跳转到"设置>应用>[你的应用]"页面让用户手动授予该权限:
当用户点击确定后跳转到应用详情页让用户手动授予相应权限。
至于什么时候显示该对话框也很明显,即该权限申请被永久拒绝(可能是因为用户之前拒绝了该权限申请并勾选了不再询问,也可能是设备策略禁止了该应用的授权请求)时显示该对话框,也就是当系统调用你的onRequestPermissionsResult() 回调方法并传递PERMISSION_DENIED时shouldShowRequestPermissionRationale返回false时显示该对话框。
最后,是一些建议:
①尽可能少的申请权限。避免在清单文件中列出不需要的权限。
②考虑使用Intent。如果你的应用的某些功能完全可以由系统App或其他第三方App完成,而不需要你精确地控制,你可以考虑直接发一个Intent调起其他应用完成,而你只需在onActivityResult()方法中接收结果就可以了。
③在各种条件下测试你的App。虽然从Android 6.0(Marshmallow,API 23)开始才会支持运行时权限管理,但你还是要在各个版本和各个ROM中测试你的App以保证在未授权时应用依然能够正确运行。
Android 权限管理相关推荐
- android 一个字符串分两行显示_重新梳理Android权限管理
Android Developer指南中,对Android安全体系结构的核心有这么一个说法:默认情况下,任何应用程序都无权执行任何会对其他应用程序.操作系统或者用户产生负面影响的操作.这句话其实就很好 ...
- android 跳转权限管理的代码,Android权限管理
Android权限管理 说明 在targetSdkVersion的值为23或者更高,就要进行权限管理,否则如果运行在Android6.0或以上的设备会没有相应权限而导致崩溃 请求权限后,在onRequ ...
- Android权限管理
Android权限管理 说明 在targetSdkVersion的值为23或者更高,就要进行权限管理,否则如果运行在Android6.0或以上的设备会没有相应权限而导致崩溃 请求权限后,在onRequ ...
- Android权限管理之Permission权限机制及使用
前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...
- android 权限管理之判断禁止后不再提示
android 权限管理之判断禁止后不再提示 我看到了许多博客中写到了单独去判断shouldShowRequestPermissionRationale()方法的值去判断为是否为不再提示,结果遇到了小 ...
- 原生android 权限管理,Android 权限管理(原生、EasyPermissions、RxPermissions)
前言:动态权限管理是Android6.0(Build.VERSION_CODES.M = Api23)推出的,提醒用户当前APP所需要的权限,防止滥用.这些权限一般分为三种:(1)普通权限:直接man ...
- android10管理权限,Android 权限管理
关于运行时权限 在旧的权限管理系统中,权限仅仅在App安装时询问用户一次,用户同意了这些权限App才能被安装(某些深度定制系统另说),App一旦安装后就可以偷偷的做一些不为人知的事情了. 在Andro ...
- Android权限管理原理(含6.0)
前言 Android系统在MarshMallow之前,权限都是在安装的时候授予的,虽然在4.3时,Google就试图在源码里面引入AppOpsManager来达到动态控制权限的目的,但由于不太成熟,在 ...
- android 权限管理 主动防御,基于SEAndroid的敏感数据主被动防御机制分析与设计
摘要: 随着智能移动终端设备市场的不断扩张,Android系统已经成为智能移动终端市场中的领导者,占据着极其巨大的市场份额.与此同时,由于Android系统本身安全机制存在隐患,Android移动智能 ...
- Android权限管理详解
概述 Android安全架构规定:默认情况下,任何应用都没有权限执行对其他应用.操作系统或用户有不利影响的任何操作.这包括读写用户的私有数据(如联系人或电子邮件等).读写其他应用的文件.执行网络访问. ...
最新文章
- Eclipse连接MySQL数据库(傻瓜篇)
- AttributeError: 'StatusHandler' object has no attribute 'async_callback'
- html css页脚代码,HTML CSS - 页脚 - 下面的空格
- Redis未授权访问漏洞记录(端口:6379)
- linq distinct 不够用了!
- 潜藏中国30年,营收远超老干妈6倍,它才是真正的隐形辣酱冠军
- java # 折叠_如何在Java中实现列表折叠
- 三行代码实现冒泡排序算法
- linux引导过程和服务控制
- json日期格式化 java_java_Java Web程序中利用Spring框架返回JSON格式的日期,返回Json时格式化日期Date
第一 - phpStudy...
- 图扑智慧交通:数字化地铁大屏管控运维平台
- 实用Chrome插件
- 怎样使用 iOS 7 的 AVSpeechSynthesizer 制作有声书(1)
- 分布式应用之分布式缓存
- Android打字机动画,Android自定义View实现打字机效果
- 视频工作室必备利器——群晖NAS
- 荐读解惑 | FPGA是有门槛的,零基础并不是你想的那样,不要再被忽悠了!
- 2021国产数据库领域最具商业合作价值企业盘点
- 计算机cpu的功能和作用是什么意思,电脑的CPU和内存都起什么作用?
- 小米应用开发者文档(标注需要注意的地方)