Android6.0權限管理以及使用權限該註意的地方
Android 6.0 Marshmallow首次增加了執行時權限管理,這對用戶來說,能夠更好的了解、控 制 app 涉及到的權限。然而對開發人員來說卻是一件比較蛋疼的事情。須要兼容適配,並保證程序功能的正常執行。
什麽叫執行時權限管理呢?在Android 6.0以下的系統中,當我們在安裝應用的時候,該應用就會提示我們這個應用所須要的權限,假設你要安裝。那就必須允許賦予全部權限,可是假設不允許,那就僅僅能取消安裝了,有點流氓。並且安裝完後,你不能夠收回這個權限。
而6.0就做到了執行時權限管理。即使安裝的時候給了權限,也能夠到系統設置裏。去關閉該權限。
以下分幾種情況來講,由於執行時權限僅僅有在Android6.0及以上的手機版本號才有,所以這裏僅僅考慮設備版本號大於6.0的手機。低版本號的手機在安裝時就已經賦予了全部的權限。也不可能收回,就不考慮了,以下的情況僅僅分targetSdkVersion:
- targetSDKVersion大於等於23的時候,那麽權限是能夠被回收(revoke)。這裏還要分權限。google將權限分為兩種,一種是normal permission,還有一種是dangerous permission。
normal permission是指與用戶隱私無關的權限。能夠理解為無關緊要的權限,比方說訪問網絡的權限。對用戶來說沒什麽關系。dangerous permission就是會涉及到用戶隱私的權限。比如讀取用戶手機聯系人、短信等等。假設是normal permission的話,那麽在安裝的時候就會給,並且不會開放接口讓用戶回收該權限。app會一直擁有該權限,所以不用考慮這樣的類型的權限。假設是dangerous permission的話,在安裝的時候並未授予權限。系統開放接口允許用戶回收或者賦予權限。以下是某個應用的權限,第一張圖是dangerous permission。能夠回收和賦予的。
點擊上面的全部權限,能夠查看到該應用全部的權限。
那麽對於dangerous permission的話,在使用前須要去檢查該permission是否已經被授予
checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED
假設該權限已經被授予,那麽可繼續執行你的代碼,假設未授予,則須要向用戶詢問是否須要授予權限。彈出的框是系統界面,界面例如以下:
調用代碼:
requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, 1 );
系統詢問是否授予權限的頁面結束後會有回調
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
//your implementations
}else{
ToastUtil.show(this, "權限不足。支付失敗");
}
}
}
- 假設targetSdkVersion是小於23的。那麽將覺得app沒實用23新權限測試過,那麽繼續使用老規則:系統在安裝的時候會默認給app賦予全部的權限,app能夠照常執行。可是!可是!可是!
用戶依舊能夠回收權限,只是此回收非彼回收。先看下關閉權限時彈的頁面:
看到了麽。假設targetSDKVersion小於23的話,在關閉權限的時候。會彈一個警告框,告訴你這是舊版的android,關閉會有問題,假設你按拒絕。那麽該權限將會關閉。並且界面上。權限的開關會顯示關。可是這個權限卻沒有被回收(nexus 5x的手機親測。當然其它的機子我也不敢打包票)。checkSelfPermission返回granted。我看了下。假設targetSDKVersion等於23的話。系統日誌是:
假設targetSDKVersion是小於23的話,則日誌是:
Permission related app op changed.
只是我猜想假設你要支持runtime permission的話,還是要把targetSDKVersion設為23。假設你的targetSDKVersion是小於23的話,那麽還是要加上checkSelfPermission,以防萬一。誰知道google會出什麽坑。
還有就是權限的話,有分組的概念,看例如以下圖:
假設一組中有一個被授予了,那麽組內的也會默認被授予。
並且也支持同一時候申請多個權限,詳細情況android developer官網。
以下是stackoverflow問題的網址:
http://stackoverflow.com/questions/36328151/ive-revoke-the-android-permission-but-checkselfpermission-still-return-granted
如有問題和錯誤的地方請指出。
以下就是要講一些權限管理註意的地方。
對於權限的話,Activity和Fragment都有自己的requestPermissions和onRequestPermissionsResult回調,可是Activity是有checkSelfPermission。可是fragment是沒有的,所以fragment假設想要檢查權限,還得調用宿主activity的checkSelfPermission。
對了,平時直接調用checkSelfPermission和requestPermissions會報什麽api錯誤,盡管編譯不會通過,可是看著就是煩啊。能夠調用ActivityCompat.checkSelfPermission(在supportv4包中)。
先看下Activity的requestSelfPermission這種方法:
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
}
看下這裏是直接打開還有一個Activity進行操作,還用了startActivityForResult,回調會通過onRequestPermissionResult,我想這個回調應該是在onActivityResult裏面處理。然後調這個onRequestPermissionResult函數的。
那麽問題來了,假設我在onResume函數中申請某一個權限,調用requestPermissions,那麽現象是什麽樣的呢?
第一次進入頁面,彈出申請權限的對話框,假設點擊允許。則正常,對話框不會再顯示。可是假設第一次點擊拒絕,則點擊拒絕後重新彈出對話框來申請權限,假設你一直點拒絕。則對話框一直彈出,這是為什麽呢?由於第一次進入頁面並執行onResume函數時申請權限,進入還有一個頁面。彈出對話框,假設你點擊拒絕。先是回調onRequestPermissionResult,然後再執行onResume函數,這時又會再一次去檢查權限,由於發現無權限,則再一次請求,如是,進入一個循環之中,除非你點允許,否則是個無限循環。
所以申請權限不妨不要寫在onResume中,或者加一個標誌位推斷。
接下來再講講Fragment請求權限。
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mHost.onRequestPermissionsFromFragment(this, permissions,requestCode);
}
這裏看到事實上是調用mHost請求權限的方法。mHost就是這個fragment的宿主Activity,所以Fragment請求權限實際上也是通過宿主Activity,當權限結果回調時,activity推斷是從Fragment中來的還是從自己Activity中來的,再進行分發結果。
Github上也有一些比較好用的權限庫:https://github.com/hotchemi/PermissionsDispatcher
Android6.0權限管理以及使用權限該註意的地方