概述
從Android6.0(API23)開始,用戶可以在應用運行時向其授予權限,而不是在應用安裝時授予。 在Android6.0以前,應用安裝會給出應用聲明的權限列表,用戶如果要繼續安裝,就得接受全部的權限,讓用戶很無奈; 從Android6.0開始的運行時權限,讓用戶可以對應用的功能進行更多的控制,例如,用戶可以選擇爲相機應用提供相機的訪問權限,而不提供設備位置的訪問權限。用戶可以隨時進入應用的“Settings”開關權限。
兼容性
- 如果設備的系統版本是Android5.1或者更低的版本,或者應用的
targetSdkVersion
爲22或更低:如果您在清單中列出了危險權限,則用戶必須在安裝應用時授予此權限;如果用戶不授予此權限,系統根本不會安裝應用。 - 如果設備的系統版本是Android6.0或者更高的版本,或者應用的
targetSdkVersion
爲23或更高:應用必須在清單中列出權限,並且它必須在運行時請求其需要的每項危險權限。用戶可以授權或拒絕每項權限,且即使用戶拒絕權限請求,應用仍可以繼續運行有限的功能。
權限分類
系統權限分爲兩類:正常權限和危險權限
Normal Permissions
正常權限,不會直接給用戶隱私權帶來風險。如果您的應用在其清單列出了正常權限,系統將自動授予該權限。
- ACCESSLOCATIONEXTRA_COMMANDS
- ACCESSNETWORKSTATE
- ACCESSNOTIFICATIONPOLICY
- ACCESSWIFISTATE
- BLUETOOTH
- BLUETOOTH_ADMIN
- BROADCAST_STICKY
- CHANGENETWORKSTATE
- CHANGEWIFIMULTICAST_STATE
- CHANGEWIFISTATE
- DISABLE_KEYGUARD
- EXPANDSTATUSBAR
- FOREGROUND_SERVICE
- GETPACKAGESIZE
- INSTALL_SHORTCUT
- INTERNET
- KILLBACKGROUNDPROCESSES
- MANAGEOWNCALLS
- MODIFYAUDIOSETTINGS
- NFC
- READSYNCSETTINGS
- READSYNCSTATS
- RECEIVEBOOTCOMPLETED
- REORDER_TASKS
- REQUESTCOMPANIONRUNINBACKGROUND
- REQUESTCOMPANIONUSEDATAIN_BACKGROUND
- REQUESTDELETEPACKAGES
- REQUESTIGNOREBATTERY_OPTIMIZATIONS
- SET_ALARM
- SET_WALLPAPER
- SETWALLPAPERHINTS
- TRANSMIT_IR
- USE_FINGERPRINT
- VIBRATE
- WAKE_LOCK
- WRITESYNCSETTINGS
Dangerous Permissions
危險權限,會授予應用訪問用戶機密數據的權限。如果您的應用在清單中列出了危險權限,則用戶必須明確批准您的應用使用這些權限。 危險權限是按權限組來劃分,如果你申請某個危險的權限,假設你的app早已被用戶授權了
同一組
的某個危險權限,那麼系統會立即授權,而不需要用戶去點擊授權。 例如,你的app對READ_CONTACTS
已經授權了,當你的app申請WRITE_CONTACTS
時,系統會直接授權通過。 NOTE:對應申請時彈出的Dialog上面的文本說明也是對整個權限組的說明,而不是單個權限。
權限組 | 權限 |
---|---|
CALENDAR | READCALENDARWRITECALENDAR |
CALL_LOG | READCALLLOGWRITECALLLOGPROCESSOUTGOINGCALLS |
CAMERA | CAMERA |
CONTACTS | READCONTACTSWRITECONTACTSGET_ACCOUNTS |
LOCATION | ACCESSFINELOCATIONACESSCOARSELOCATION |
MICROPHONE | RECORD_AUDIO |
PHONE | READPHONESTATEREADPHONENUMBERSCALLPHONEADDVOICEMAILUSE_SIP |
SENSORS | BODY_SENSORS |
SMS | SENDSMSRECEIVESMSREADSMSRECEIVEWAPPUSHRECEIVEMMS |
STORAGE | READEXTERNALSTORAGEWRITEEXTERNALSTORAGE |
運行時權限處理
檢查權限
如果你的應用需要危險權限,則每次執行需要這一權限的操作時都必須檢查自己是否具有該權限。因爲用戶可以自由的開關此權限,所以,即使應用昨天使用了相機,它不能假設自己今天仍具有該權限。
ContextCompat.checkSelfPermission:用於檢測某個權限是否已經被授予
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);
說明:如果應用具有此權限,方法將返回 PackageManager.PERMISSION_GRANTED
,並且允許應用可以繼續操作。如果應用不具有此權限,方法將返回 PackageManager.PERMISSION_DENIED
,且應用必須明確向用戶要求權限。
請求權限
如果應用尚無所需的權限,則應用必須調用
requestPermissions()
方法,來請求適當的權限。
ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
說明:從第二個參數可以看出,支持一次性請求多個權限,系統會通過對話框逐一詢問用戶是否授權。
處理權限請求響應
當應用請求權限時,系統將向用戶顯示一個對話框。當用戶響應時,系統將調用應用的
onRequestPermissionsResult()
方法。
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // contacts-related task you need to do. } else { // permission denied, boo! Disable the // functionality that depends on this permission. } return; } // other 'case' lines to check for other // permissions this app might request } }
解釋權限的用途
如果用戶繼續嘗試使用需要某項權限的功能,但拒絕權限請求,則可能表明用戶不理解應用爲什麼需要此權限才能提供相關的功能,這時就可以顯示解釋給用戶。
shouldShowRequestPermissionRationale()
: 如果應用之前請求過此權限但用戶拒絕了請求,此方法返回true
; 如果用戶過去拒絕了權限請求,並在權限請求系統對話框選擇了Don't ask again
選項,此方法返回false
。
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) { // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an // app-defined int constant. The callback method gets the // result of the request. } }
AndPermission的使用
AndPermission是嚴格按照
Android
系統的運行時權限
設計的,並最大限度上兼容了國產手機。 庫地址:https://github.com/yanzhenjie/AndPermission
導入
implementation 'com.yanzhenjie:permission:2.0.0-rc12'
使用
申請權限
AndPermission.with(this) .runtime() .permission(Permission.Group.STORAGE) .onGranted(permissions -> { // Storage permission are allowed. }) .onDenied(permissions -> { // Storage permission are not allowed. }) .start();
權限被拒絕,說明權限用途
private Rationale mRationale = new Rationale() { @Override public void showRationale(Context context, List<String> permissions, RequestExecutor executor) { // 這裏使用一個Dialog詢問用戶是否繼續授權。 // 如果用戶繼續: executor.execute(); // 如果用戶中斷: executor.cancel(); } }; AndPermission.with(this) .runtime() .permission(Permission.WRITE_EXTERNAL_STORAGE) .rationale(mRationale) .onGranted(...) .onDenied(...) .start();
權限總是被拒絕,前往設置頁授權
AndPermission.with(this) .runtime() .permission(...) .rationale(...) .onGranted(...) .onDenied(new Action() { @Override public void onAction(List<String> permissions) { if (AndPermission.hasAlwaysDeniedPermission(context, permissions)) { // 這些權限被用戶總是拒絕。 // 這裏使用一個Dialog展示沒有這些權限應用程序無法繼續運行,詢問用戶是否去設置中授權。 AndPermission.with(this) .runtime() .setting() .onComeback(new Setting.Action() { @Override public void onAction() { // 用戶從設置回來了。 } }) .start(); } } }) .start();
參考鏈接
- https://blog.csdn.net/lmj623565791/article/details/50709663
- https://blog.csdn.net/yanzhenjie1003/article/details/52503533
- https://edu.csdn.net/course/play/3539
- https://developer.android.com/training/permissions/requesting?hl=zh-cn
- https://developer.android.com/about/versions/marshmallow/android-6.0-changes?hl=zh-cn
- https://developer.android.com/training/permissions/best-practices?hl=zh-cn#testing
- http://www.yanzhenjie.com/AndPermission/cn/runtime/