Android6.0 发布以后,Android 的权限系统被从新设计。在 23 以前 App 的权限只会在用户安装的时候询问一次,App一旦安装后就可使用全部的权限了,而从 23 以后,App 能够直接安装,App 只有在运行时须要使用某些权限时才会向用户询问是否受权,此时系统会弹出一个对话框让用户选择确认或者取消受权,同时用户也能够在设置页面对每一个 App 的权限进行管理。重要:这个对话框须要开发者手动调用,且不可自行定制样式html
Android Developer 文章:
System Permissions
Requesting Permissions at Run Time
Permissions Best Practicesjava
通用权限是指不涉及用户隐私,只须要在Manifest
中声明便可的权限,好比网络、蓝牙等,只要 app 安装,这些权限默认都是被app容许使用的。android
通用权限列表:git
全部危险的Android系统权限属于权限组,若是APP运行在Android 6.0 (API level 23)或者更高级别的设备中,并且targetSdkVersion>=23时,系统将会自动采用动态权限管理策略。
此类权限也必须在Manifest中申明,不然申请时不提使用用户,直接回调开发者权限被拒绝。
同一个权限组的任何一个权限被受权了,这个权限组的其余权限也自动被受权。例如,一旦WRITE_CONTACTS
被受权了,App也有READ_CONTACTS
和GET_ACCOUNTS
了。
申请某一个权限的时候系统弹出的Dialog是对整个权限组的说明,而不是单个权限。例如我申请READ_EXTERNAL_STORAGE
,系统会提示"容许xxx访问设备上的照片、媒体内容和文件吗?"。
若是App运行在Android 5.1 (API level 22)或者更低级别的设备中,或者targetSdkVersion<=22时(此时设备能够是Android 6.0 (API level 23)或者更高),在全部系统中仍将采用旧的权限管理策略,系统会要求用户在安装的时候授予权限。其次,系统就告诉用户App须要什么权限组,而不是个别的某个权限。github
(targetSdkVersion>=23)
Dangous Permissions数组
Permission Group | Permissions |
---|---|
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 |
SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS 这两个权限比较特殊,不能经过代码申请方式获取,必须得用户打开软件设置页手动打开,才能受权。官方建议须要申请该权限时引导用户跳转到Setting中本身去开启权限开关。网络
public static int OVERLAY_PERMISSION_REQ_CODE = 1234; @TargetApi(Build.VERSION_CODES.M) public void requestDrawOverLays() { if (!Settings.canDrawOverlays(MainActivity.this)) { Toast.makeText(this, "can not DrawOverlays", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + MainActivity.this.getPackageName())); startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE); } else { // Already hold the SYSTEM_ALERT_WINDOW permission, do addview or something. } } @TargetApi(Build.VERSION_CODES.M) @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == OVERLAY_PERMISSION_REQ_CODE) { if (!Settings.canDrawOverlays(this)) { // SYSTEM_ALERT_WINDOW permission not granted... Toast.makeText(this, "Permission Denieddd by user.Please Check it in Settings", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Permission Allowed", Toast.LENGTH_SHORT).show(); // Already hold the SYSTEM_ALERT_WINDOW permission, do addview or something. } } }
一、检查某一个权限的当前状态,在请求某个权限时应该检查这个权限是否已经被用户受权,已经受权的权限应该跳过申请。
二、该方法有一个参数是权限名称,有一个int的返回值,可判断检查的权限当前的状态。app
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { // 没有权限 }else{ // 有权限了 }
申请权限,调用后系统会显示一个请求用户受权的提示对话框,App不能配置和修改这个对话框。
一、 若是须要提示用户这个权限相关的信息或说明,须要在调用 requestPermissions() 以前处理,该方法有两个参数:ide
int requestCode //会在回调onRequestPermissionsResult()时返回,用来判断是哪一个受权申请的回调。 String[] permissions//权限数组,你须要申请的的权限的数组
二、当用户处理完受权操做时,会回调Activity或者Fragment的onRequestPermissionsResult()
方法。ui
处理权限结果回调,当用户处理完受权操做时,系统会自动回调该方法,此时返回三个参数,能够判断用户是否容许了申请的权限
int requestCode // 在调用requestPermissions()时的第一个参数。 String[] permissions //权限数组,在调用requestPermissions()时的第二个参数。 int[] grantResults //受权结果数组,对应permissions,具体值和上方提到的PackageManager中的两个常量作比较。
是否应该显示请求权限的说明。
一、当第一次请求权限时,用户拒绝了,此时再调用shouldShowRequestPermissionRationale()
后会返回true,显示为何须要这个权限的说明。
二、用户在第一次拒绝某个权限后,下次再次申请时,受权的dialog中将会出现“再也不提醒”选项,一旦选中勾选了,那么下次申请将不会提示用户。此时调用shouldShowRequestPermissionRationale()
会返回false
三、设备的策略禁止当前应用获取这个权限的受权:shouldShowRequestPermissionRationale()
返回false
一个本身实现的Permission辅助库,帮助咱们可以快速而简洁的在Android上申请权限。
Github地址:PermissiongBuilder
博客地址:cpacm