Android動態權限總結

從Android6.0開始,Android系統提供動態申請權限的機制, APP在使用危險權限時,須要用戶的受權纔可進一步操做。java

權限申請方式

Android系統中權限申請的方式有兩種,以下圖所示: git

靜態申請

Android6.0之前的系統(API < 23)採用的這種方式,只要用戶在AndroidManifest.xml中註冊了權限,安裝APP後默認就獲取了這些權限。這種受權方式安全性極低,若是用戶安裝後沒有關閉相應的權限,用戶的私密數據很容易被哪些垃圾APP竊取。爲了解決這種問題,國內的各大手機廠商爲Android5.0如下的系統,針對某些權限作了必定的限制,即使在Android5.0如下,也須要用戶進行手動受權纔可以使用,這在某種程度上提升了安全性,但也因沒有統一的標準,從而出現了各類兼容問題。github

動態申請

隨着系統的升級,Google也意識到靜態申請權限的弊端,因此在Android6.0中,對權限進行了從新梳理,將權限分爲普通權限和危險權限:數組

  • 正常權限:不會給用戶隱私帶來危險的權限,只要開發者在AndroidManifest.xml中註冊了,系統將自動受權;
  • 危險權限:能夠訪問用戶隱私數據的權限,必須獲取用戶的贊成纔可得到受權;
危險權限彙總

在Android開發中咱們應該儘量使用隔離式申請權限,用戶沒有受權時屏蔽相應功能便可。如今不少內容性APP,用戶進去什麼都沒看到,就須要各類權限,沒有權限還不能使用,這可能會引發用戶的反感,固然,也是對用戶安全意識的一種衝擊,時間久了,用戶可能會以爲使用APP就應該受權,從而給一些惡意APP做惡的餘地。安全

動態申請權限的過程

核心API介紹

檢查權限是否已獲取:

// ContextCompat.java
public static int checkSelfPermission(@NonNull Context context, @NonNull String permission)

// PermissionChecker.java
public static int checkSelfPermission(@NonNull Context context,
            @NonNull String permission)
複製代碼

這兩個方法都是檢查權限是否獲取的方法,但ContextCompat.checkSelfPermission在某些系統上(如基於Android8.0的MIUI10檢查短信權限時)有bug, 不能準確判斷權限是否已獲取,此時可結合PermissionChecker.checkSelfPermission進行判斷, 因此判斷權限是否已獲取可採用如下實現:ide

public static boolean hasPermission(@NonNull Context context, @NonNull String permission) {
    if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED
            || PermissionChecker.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
        return false;
    }

    return true;
}
複製代碼

申請權限

當未獲取權限時,須要向系統請求,請求時使用requestPermissions方法:工具

// ActivityCompat.java
// 在Activity中申請權限
public static void requestPermissions(final @NonNull Activity activity,
            final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode)
        

// Fragment.java
// 在Fragment中申請權限
public final void requestPermissions(@NonNull String[] permissions, int requestCode)
複製代碼

在Fragment使用ActivityCompat.requestPermissions申請權限時,若是用戶拒絕了(且勾線了再也不提示)請求,Fragment中的onRequestPermissionsResult不會被回調,也就不能引導用戶開啓權限。因此在Fragment中應該使用Fragment的成員方法requestPermissions來請求權限。學習

檢查APP是否應該向用於展現申請權限的解釋

// ActivtyCompat.java
// 檢查APP是否應該向用於展現申請權限的解釋
public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity, @NonNull String permission);
複製代碼

此方法的返回值解釋以下:this

  • 當APP從未申請過指定的權限或申請了指定權限,但被用戶拒絕,且勾選了【再也不提示】,返回false;
  • APP申請指定權限時被用戶拒絕,但未勾選【再也不提示】,返回true

因此在使用此方法時,咱們要先判斷APP是否已申請過權限,不然難以判斷返回false的兩種狀況。spa

申請權限的結果回調

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
複製代碼

這是Activity和Fragment中申請權限的結果回調方法,其中permissions表示申請的權限數組,grantResults表示每一個權限的請求結果。取值爲:

// 得到受權
public static final int PERMISSION_GRANTED = 0;
// 未獲受權
public static final int PERMISSION_DENIED = -1;
複製代碼

一般申請權限後的處理邏輯都是在該方法中實現。

動態權限申請的實現

動態申請權限的條件:

  • targetSdkVersion >= 23;
  • Android系統版本在6.0及以上;

對於不能同時知足以上條件的狀況,默認使用的靜態申請權限的方式,但不一樣的ROM爲了安全性,可能對其機制進行了修改,因此可能因ROM不一樣而有所差別。

瞭解了申請權限的核心API,接下來就介紹一下在Activity中申請權限的實現過程,下面以點擊申請拍照權限爲例:

private void startPhoto() {
    if (hasPermission(this, new String[]{Manifest.permission.CAMERA})) {
        // 執行拍照的邏輯
    } else {
         ActivityCompat.requestPermissions(context, rnew String[]{Manifest.permission.ACCESS_FINE_LOCATION}),
                        PERMISSION_REQUEST_CODE);
    }
}
複製代碼

而後在onRequestPermissionsResult中監聽權限申請的結果:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
	super.onRequestPermissionsResult(requestCode, permissions, grantResults);
	
    if (hasPermission(permissions)) {
        // 執行拍照的邏輯
    } else {
        if (ActivityCompat.shouldShowRequestPermissionRationale(context, permissions[refusedPermissionIndex])) {
            // 向用戶展現申請權限的理由
        } else {
            // 引用用戶去開啓權限
        }
    }
}
複製代碼

上面只是一個申請權限的基本流程,真正實現時還要考慮多權限問題,版本的兼容問題,ROM的兼容問題等。

固然,在開發中也不會這樣在每一個須要申請權限的Activity/Fragment中寫這一段代碼,即使封裝成工具類也須要在每一個Activity/Fragment引用,耦合性過高。一般可將權限申請在一個透明的Activity中實現,這樣在申請權限時,直接跳轉到該Activity便可。下面推薦一個動態申請權限的庫供參考。

PermissionManager

PermissionManager是一個基於AOP實現的動態申請權限的開源庫,目的是讓申請權限的過程更簡單。固然,也可當作學習Aspectj的的參考項目。具備如下優勢:

  • 支持多權限申請;
  • 簡單易用,一行註解實現權限申請
  • 提供了可擴展的權限說明和引導設置方式;
  • 提供了阻塞/非阻塞的申請方式;

具體的介紹可參考其源碼地址:PermissionManager

總結

因爲Android碎片化嚴重,國內的各大廠商對權限這塊也作了不一樣的處理,因此在動態申請時確定存在失敗的狀況,若是在使用PermissionManager的時候發現問題,歡迎隨時提issue & pull request。

相關文章
相關標籤/搜索