歡迎訪問個人我的博客 傳送門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,這個就要具體踩坑,具體解決了