從 Android 6.0(API 級別 23)開始,用戶開始在應用運行時向其授予權限,而不是在應用安裝時授予。因此若是你的應用使用到了一些危險權限,就必須在AndroidManifest.xml 中靜態地聲明須要用到的權限,並在使用到該功能時要動態的申請,不然在調用到相應權限功能時候,會拋出 SecurityException異常。因此本文探討一下動態權限的申請的正確流程,並把它封裝成一個庫,簡化了申請過程。java
在講解以前,先看一下android權限的分類,android權限分爲四類,以下:android
普通權限也叫正常權限,它不須要動態申請,你只須要在用到它的時候在AndroidManifest.xml 中靜態地聲明,而後系統在app運行時就會自動的授予該app相應的權限。這類權限主要在你的app想要接觸app沙盒外的數據或資源的時用到,它不會涉及到系統的操做,也不會泄漏或篡改用戶的隱私數據。以下:git
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
FOREGROUND_SERVICE
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MANAGE_OWN_CALLS
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_COMPANION_RUN_IN_BACKGROUND
REQUEST_COMPANION_USE_DATA_IN_BACKGROUND
REQUEST_DELETE_PACKAGES
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
SET_ALARM
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
複製代碼
該類權限只對擁有相同簽名的應用開放。例如某個應用自定義了一個permission 且在權限標籤中加入 android:protectionLevel=」signature」,其餘應用想要訪問該應用中的某些數據時,必需要在AndroidManifest.xml中聲明該權限,並且還要與該應用具備相同的簽名,系統會在app運行時自動授予該權限。這類咱們用的比較少。github
也叫敏感權限,運行時權限,跟普通權限相反,一旦某個應該獲取了該類權限,用戶的隱私數據就面臨被泄露篡改的風險。因此你想使用該權限就必須在AndroidManifest.xml 中靜態地聲明須要用到的權限,並在使用到該功能時要動態的申請,除非用戶贊成該權限,不然你不能使用該權限對應的功能。以下:app
能夠看到android把危險權限分爲10組,因此申請危險權限的時候都是按組申請,咱們只要申請組內的任意一個危險權限就行,當用戶一旦贊成受權該危險權限,那麼該權限所對應的權限組中的全部其餘權限也會同時被受權。ide
特殊權限我瞭解的有三個,以下:測試
它也是要要申請的,可是它不一樣於危險權限的申請,危險權限的申請會彈出一個對話框詢問你是否贊成,而特殊權限的申請須要跳轉到指定的界面,讓你手動確認贊成。ui
因此動態權限的申請就是申請危險權限或特殊權限,權限的申請在不一樣的Android版本有不一樣的行爲,以下:this
我這裏討論的是6.0後的動態申請,因此從 Android 6.0開始,不管您的應用面向哪一個 API 級別,您都應對應用進行測試,以驗證它在缺乏須要的權限時行爲是否正常。google
若是還不瞭解動態權限申請的詳細步驟,能夠看一下這篇文章:Android 6.0運行權限解析(高級篇)。
這裏我假設你們已經知道那些方法了,我把權限申請的流程分爲單個和多個權限申請,分別畫了個圖。
上面兩個圖有有提到自定義提示權限組,那麼它主要包含如下內容:
注意:若是用戶不受權,則不能使用該功能或應用沒法運行,能夠考慮取消第3步的取消按鈕,即沒法取消這個提示框,必定要用戶去「Settings」受權。
除了特殊權限外,還有一個location權限也比較特殊,須要經過 **LocationManager的isProviderEnabled(LocationManager.GPS_PROVIDER)**判斷是否打開定位開關後再進行權限申請,以下:
lm = (LocationManager) this.getSystemService(this.LOCATION_SERVICE);
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {//開了定位服務
//請求定位功能
PermissionHelper.getInstance().with(this).requestPermission(
Manifest.permission.ACCESS_FINE_LOCATION,
new IPermissionCallback() {
@Override
public void onAccepted(Permission permission) {
//...
}
@Override
public void onDenied(Permission permission) {
//...
}
}
);
} else {
//跳轉到開啓定位的地方
Toast.makeText(this, "系統檢測到未開啓GPS定位服務,請開啓", Toast.LENGTH_SHORT).show();
Intent intent = new Intent();
intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, PRIVATE_CODE);
}
}
複製代碼
本文主要讓讓你們對權限的申請流程有進一步的認識,而後能夠經過對動態權限的封裝,將檢測動態權限,請求動態權限,權限設置跳轉,監聽權限設置結果等處理和業務功能隔離開來,業務之後能夠很是快速的接入動態權限支持,提升開發效率,更多細節查看PermissionHelper。
參考資料: