Android 6.0權限管理
關於權限管理
Android6.0 發布之后,Android 的權限系統被重新設計。在 23 之前 App 的權限只會在用戶安裝的時候詢問一次,App一旦安裝后就可以使用所有的權限了,而從 23 之后,App 可以直接安裝,App 只有在運行時需要使用某些權限時才會向用戶詢問是否授權,此時系統會彈出一個對話框讓用戶選擇確認或者取消授權,同時用戶也可以在設置頁面對每個 App 的權限進行管理。重要:這個對話框需要開發者手動調用,且不可自行定制樣式
Android Developer 文章:
System Permissions
Requesting Permissions at Run Time
Permissions Best Practices
通用權限和危險權限
通用權限
通用權限是指不涉及用戶隱私,只需要在Manifest
中聲明即可的權限,比如網絡、藍牙等,只要 app 安裝,這些權限默認都是被app允許使用的。
通用權限列表:
- 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
危險權限
所有危險的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需要什么權限組,而不是個別的某個權限。
(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.
}
}
}
權限申請流程
checkSelfPermission()
1、檢查某一個權限的當前狀態,在請求某個權限時應該檢查這個權限是否已經被用戶授權,已經授權的權限應該跳過申請。
2、該方法有一個參數是權限名稱,有一個int的返回值,可判斷檢查的權限當前的狀態。
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// 沒有權限
}else{
// 有權限了
}
requestPermissions()
申請權限,調用后系統會顯示一個請求用戶授權的提示對話框,App不能配置和修改這個對話框。
1、 如果需要提示用戶這個權限相關的信息或說明,需要在調用 requestPermissions() 之前處理,該方法有兩個參數:
int requestCode //會在回調onRequestPermissionsResult()時返回,用來判斷是哪個授權申請的回調。
String[] permissions//權限數組,你需要申請的的權限的數組
2、當用戶處理完授權操作時,會回調Activity或者Fragment的onRequestPermissionsResult()
方法。
onRequestPermissionsResult()
處理權限結果回調,當用戶處理完授權操作時,系統會自動回調該方法,此時返回三個參數,可以判斷用戶是否允許了申請的權限
int requestCode // 在調用requestPermissions()時的第一個參數。
String[] permissions //權限數組,在調用requestPermissions()時的第二個參數。
int[] grantResults //授權結果數組,對應permissions,具體值和上方提到的PackageManager中的兩個常量做比較。
shouldShowRequestPermissionRationale()
是否應該顯示請求權限的說明。
1、當第一次請求權限時,用戶拒絕了,此時再調用shouldShowRequestPermissionRationale()
后會返回true,顯示為什么需要這個權限的說明。
2、用戶在第一次拒絕某個權限后,下次再次申請時,授權的dialog中將會出現“不再提醒”選項,一旦選中勾選了,那么下次申請將不會提示用戶。此時調用shouldShowRequestPermissionRationale()
會返回false
3、設備的策略禁止當前應用獲取這個權限的授權:shouldShowRequestPermissionRationale()
返回false
Permission Builder
一個自己實現的Permission輔助庫,幫助我們能夠快速而簡潔的在Android上申請權限。
Github地址:PermissiongBuilder
博客地址:cpacm