欢迎访问个人我的博客 传送门html
从 Android 6.0(API 级别 23)开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予。此方法能够简化应用安装过程,由于用户在安装或更新应用时不须要授予权限。它还让用户能够对应用的功能进行更多控制;例如,用户能够选择为相机应用提供相机访问权限,而不提供设备位置的访问权限。用户能够随时进入应用的“Settings”屏幕调用权限。java
系统权限分为几个保护级别。须要了解的两个最重要保护级别是正常权限和危险权限,若是应用声明其须要正常权限,系统会自动向应用授予该权限,如:访问网络。若是应用声明其须要危险权限,则用户必须明确向应用授予该权限,如:访问联系人、读写权限。react
官网可查 点击查询android
ACCESS_LOCATION_EXTRA_COMMANDS ACCESS_NETWORK_STATE ACCESS_NOTIFICATION_POLICY ACCESS_WIFI_STATE BLUETOOTH BLUETOOTH_ADMINbaidu_push 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
可经过adb 命令获取 adb shell pm list permissions -d -ggit
group:android.permission-group.RCS_PERMISSION group:com.google.android.gms.permission.CAR_INFORMATION permission:com.google.android.gms.permission.CAR_VENDOR_EXTENSION permission:com.google.android.gms.permission.CAR_MILEAGE permission:com.google.android.gms.permission.CAR_FUEL group:android.permission-group.CONTACTS permission:android.permission.WRITE_CONTACTS permission:android.permission.GET_ACCOUNTS permission:android.permission.READ_CONTACTS group:android.permission-group.PHONE permission:android.permission.READ_CALL_LOG permission:android.permission.ANSWER_PHONE_CALLS permission:android.permission.READ_PHONE_NUMBERS permission:android.permission.READ_PHONE_STATE permission:android.permission.CALL_PHONE permission:android.permission.WRITE_CALL_LOG permission:android.permission.USE_SIP permission:android.permission.PROCESS_OUTGOING_CALLS permission:com.android.voicemail.permission.ADD_VOICEMAIL group:android.permission-group.CALENDAR permission:android.permission.READ_CALENDAR permission:android.permission.WRITE_CALENDAR group:android.permission-group.CAMERA permission:android.permission.CAMERA group:android.permission-group.SENSORS permission:android.permission.BODY_SENSORS group:android.permission-group.LOCATION permission:android.permission.ACCESS_FINE_LOCATION permission:com.google.android.gms.permission.CAR_SPEED permission:android.permission.ACCESS_COARSE_LOCATION group:android.permission-group.STORAGE permission:android.permission.READ_EXTERNAL_STORAGE permission:android.permission.WRITE_EXTERNAL_STORAGE group:com.sina.weibo.permission-group permission:com.sina.weibo.permission.USER group:android.permission-group.MICROPHONE permission:android.permission.RECORD_AUDIO group:android.permission-group.SMS permission:android.permission.READ_SMS permission:android.permission.RECEIVE_WAP_PUSH permission:android.permission.RECEIVE_MMS permission:android.permission.RECEIVE_SMS permission:android.permission.SEND_SMS permission:android.permission.READ_CELL_BROADCASTS
从上面的权限列表中能够看出危险权限都是分组的,若是应用请求其清单中列出的危险权限,而应用在同一权限组中已有另外一项危险权限,则系统会当即授予该权限,而无需与用户进行任何交互。例如,若是某应用已经请求而且被授予了 READ_CONTACTS 权限,而后它又请求 WRITE_CONTACTS,系统将当即授予该权限。github
这里以申请日历读写权限为例shell
<uses-permission android:name="android.permission.READ_CALENDAR"/> <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
private fun checkPermissions(): Boolean { return when (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CALENDAR)) { PackageManager.PERMISSION_GRANTED -> {//有此权限 true } PackageManager.PERMISSION_DENIED -> {//无此权限 false } else -> false } }
这里用到系统提供的 ContextCompat.checkSelfPermission 方法,用于检测某个权限是否已经被授予,方法返回值为 PackageManager.PERMISSION_GRANTED 表示已权限,为PackageManager.PERMISSION_DENIED 表示无此权限须要进行申请受权。数组
<span id = "requestPermission"></span>网络
private fun requestPermissions() { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CALENDAR)) { // 是否须要向用户解释为什么申请权限 toast(this,"须要此权限管理日历") } else { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CALENDAR), 1) } }
ActivityCompat.shouldShowRequestPermissionRationale 方法 用于在实际显示权限对话框以前是否显示一个对正在请求权限的解释,在app第一次安装的时候。这个方法会返回false,所以你能够直接请求任何须要的权限。
若是用户之前拒绝了一个请求,则分为两种状况:app
ActivityCompat.requestPermissions 方法 用于申请权限,第二个参数为 所需权限数组,也就是可申请一个,或多个权限。第三个参数为 requestCode 回调的时候使用
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) when (requestCode) { 1 -> { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { toast(this, "已受权") } else { toast(this, "未受权") } } else -> { } } }
处理权限要实现 onRequestPermissionsResult 方法,该方法有三个参数
完整的代码以下:
fun click(view: View?) { when (view?.id) { R.id.bt_query_permissions -> when (checkPermissions()) { true -> toast(this, "有权限") false -> toast(this, "无权限") } R.id.bt_request_permissions -> requestPermissions() } } private fun checkPermissions(): Boolean { return when (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CALENDAR)) { PackageManager.PERMISSION_GRANTED -> {//有此权限 true } PackageManager.PERMISSION_DENIED -> {//无此权限 false } else -> false } } private fun requestPermissions() { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CALENDAR)) { toast(this,"须要此权限管理日历") } else { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CALENDAR), 1) } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) when (requestCode) { 1 -> { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { toast(this, "已受权") } else { toast(this, "未受权") } } else -> { } } }
RxPermissions 是一个基于 RxJava 实现的权限框架,比使用 Android 自带的 API 方便不少,可扩展性高。GitHub 地址
这里以 Rxjava2 为例
repositories { jcenter() // If not already there } dependencies { //compile 'com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar' // Rxjava1 compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar' // Rxjava2 compile "io.reactivex.rxjava2:rxjava:2.1.7" compile 'io.reactivex.rxjava2:rxandroid:2.0.1' }
request 可申请一个或多个权限 直接返回是否受权成功
val rxPermissions = RxPermissions(this) rxPermissions.request(Manifest.permission.READ_CALENDAR) .subscribe({ t -> if (t) { toast(this, "已受权") } else { toast(this, "未受权") } })
requestEach or ensureEach 来分别获取每个权限请求的结果
rxPermissions.requestEach(Manifest.permission.READ_CALENDAR, Manifest.permission.CAMERA) .subscribe({ t -> when { t.granted -> toast(this, "${t.name} 已受权") t.shouldShowRequestPermissionRationale -> toast(this, "${t.name} 未受权") else -> toast(this, "${t.name} 已拒绝,并不提示") } })
这里的 shouldShowRequestPermissionRationale 参照上文 权限申请
权限申请的坑还有不少,特别是在国产手机上有各类各样的bug,这个就要具体踩坑,具体解决了