android 6.0權限管理

Android 6.0 Marshmallow首次加入了運行時權限管理,這對用戶來說,可以更好的瞭解、控 制 app 涉及到的權限。然而對開發者來說卻是一件比較蛋疼的事情,需要兼容適配,並保證程序功能的正常運行。 
什麼叫運行時權限管理呢?在Android 6.0以下的系統中,當我們在安裝應用的時候,該應用就會提示我們這個應用所需要的權限,如果你要安裝,那就必須同意賦予所有權限,但是如果不同意,那就只能取消安裝了,有點流氓。而且安裝完後,你不可以收回這個權限。 
而6.0就做到了運行時權限管理,即使安裝的時候給了權限,也可以到系統設置裏,去關閉該權限。 
下面分幾種情況來講,因爲運行時權限只有在Android6.0及以上的手機版本纔有,所以這裏只考慮設備版本大於6.0的手機,低版本的手機在安裝時就已經賦予了所有的權限,也不可能收回,就不考慮了,下面的情況只分targetSdkVersion:

  1. targetSDKVersion大於等於23的時候,那麼權限是可以被回收(revoke),這裏還要分權限,google將權限分爲兩種,一種是normal permission,另一種是dangerous permission。normal permission是指與用戶隱私無關的權限,可以理解爲無關緊要的權限,比如說訪問網絡的權限,對用戶來說沒什麼關係;dangerous permission就是會涉及到用戶隱私的權限,例如讀取用戶手機聯繫人、短信等等。如果是normal permission的話,那麼在安裝的時候就會給,而且不會開放接口讓用戶回收該權限,app會一直擁有該權限,所以不用考慮這種類型的權限。如果是dangerous permission的話,在安裝的時候並未授予權限,系統開放接口允許用戶回收或者賦予權限。下面是某個應用的權限,第一張圖是dangerous permission,可以回收和賦予的。 
    這裏寫圖片描述 
    點擊上面的所有權限,可以查看到該應用所有的權限。 
    這是所有的權限,包括normal and dangerous 
    那麼對於dangerous permission的話,在使用前需要去檢查該permission是否已經被授予
checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED
  • 1
  • 1

如果該權限已經被授予,那麼可繼續執行你的代碼,如果未授予,則需要向用戶詢問是否需要授予權限,彈出的框是系統界面,界面如下: 
這裏寫圖片描述 
調用代碼:

requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, 1);
  • 1
  • 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, "權限不足,支付失敗");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  1. 如果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);
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

看下這裏是直接打開另一個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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

這裏看到其實是調用mHost請求權限的方法,mHost就是這個fragment的宿主Activity,所以Fragment請求權限實際上也是通過宿主Activity,當權限結果回調時,activity判斷是從Fragment中來的還是從自己Activity中來的,再進行分發結果。

Github上也有一些比較好用的權限庫:https://github.com/hotchemi/PermissionsDispatcher

發佈了46 篇原創文章 · 獲贊 7 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章