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