Android 運行時權限RuntimePermission

引言:運行時權限是版本升級的一個更新點,學起來挺容易的,寫一篇筆記感覺真費勁。

時間:2017年04月18日23:45:50

作者:JustDo23

01. 前言

運行時權限Android 6.0 變更中尤為突出的一點。6以下的手機在安裝時候提示權限列表,用戶全部同意后才能安裝程序;6以后的手機直接安裝,在運行過程中動態的向用戶申請所需權限,另外用戶可以在設置界面對程序的各個權限進行管理。

Android 中的權限可以分為三類:

  • 普通權限(Normal Permissions)
  • 危險權限(Dangerous Permissions)
  • 特殊權限(Special Permissions)

普通權限不涉及用戶隱私,在AndroidManifest.xml中聲明即獲取;危險權限涉及用戶的隱私,在用戶授權之后方能使用。另外,Google 對危險權限進行了分組,當某一個組中的某一個權限被授權之后應用同時就獲取到了整個組的所有權限。而且,調用 API 申請權限時系統將向用戶顯示一個標準對話框,該對話框上的提示權限說明是針對整個組的說明,應用無法配置或更改此對話框。

02. 聲明權限

官方文檔中提到:為了保護系統的完整性和用戶隱私權,Android 在訪問受限的沙盒中運行每款應用。如果應用需要使用其沙盒以外的資源或信息,則必須明確請求權限。根據應用請求的權限類型,系統可能會自動授予權限,也可能會要求用戶授予權限。可以在應用清單中列出相應的權限,聲明應用需要此權限。

聲明權限,將<uses-permission>元素置于頂級<manifest>元素的子項。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.snazzyapp">

    <uses-permission android:name="android.permission.SEND_SMS"/>
    
    <application ...>
        ...
    </application>

</manifest>

03. 檢查權限

/**
 * Determine whether you have been granted a particular permission.
 *
 * @param permission The name of the permission being checked.
 */
ContextCompat.checkSelfPermission(@NonNull Context context, @NonNull String permission)

以上為核心 API 檢查是否擁有權限,簡單封裝如下:

/**
 * 檢查是否具有某權限
 *
 * @return true, 有權限 false,無權限
 */
private boolean checkPermission(Context context, String permission) {
  boolean checkPermission = false;
  int permissionCheck = ContextCompat.checkSelfPermission(context, permission);// 檢查權限
  switch (permissionCheck) {
    case PackageManager.PERMISSION_GRANTED:// 有權限
      checkPermission = true;
      break;
    case PackageManager.PERMISSION_DENIED:// 無權限
      checkPermission = false;
      break;
  }
  return checkPermission;
}
  • 返回的結果是int類型
  • 常量PackageManager.PERMISSION_GRANTED表示有權限
  • 常量PackageManager.PERMISSION_DENIED表示無權限
// 檢查日歷權限
ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);

04. 請求權限

/**
 * 請求指定的權限集合
 *
 * @param activity The target activity.
 * @param permissions The requested permissions. Must me non-null and not empty.
 * @param requestCode Application specific request code.
 */
ActivityCompat.requestPermissions(
                      final @NonNull Activity activity,
                      final @NonNull String[] permissions,
                      final @IntRange(from = 0) int requestCode);
  • 此方法為異步方法
  • 第二參數指定一個權限的字符數組
// 請求一個相機權限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 23);
// 同時請求三個權限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_CALENDAR, Manifest.permission.READ_SMS}, 32);

05. 請求響應

/**
 * Callback for the result from requesting permissions.
 *
 * @param requestCode The request code.
 * @param permissions The requested permissions. Never null.
 * @param grantResults The grant results.
 */
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
    switch (requestCode) {
      case 23:
        if (grantResults.length > 0) {
          if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            ToastUtil.showShortToast(MainActivity.this, "授權");
          } else {
            ToastUtil.showShortToast(MainActivity.this, "拒絕");
          }
        }
        break;
      case 32:
        break;
    }
}
  • 第二個參數是請求的權限數組
  • 第三個參數是與請求數組對應的授權結果數組

06. 提供解釋

/**
 * Gets whether you should show UI with rationale for requesting a permission.
 *
 * @param activity The target activity.
 * @param permission A permission your app wants to request.
 * @return Whether you can show permission rationale UI.
 */
public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,
        @NonNull String permission) {
    if (Build.VERSION.SDK_INT >= 23) {
        return ActivityCompatApi23.shouldShowRequestPermissionRationale(activity, permission);
    }
    return false;// 低版本直接返回 false
}
  • 如果應用之前請求過此權限但用戶拒絕了請求,此方法將返回 true
  • 如果用戶在過去拒絕了權限請求,并在權限請求系統對話框中選擇了 Don't ask again 選項,此方法將返回 false
  • 如果設備規范禁止應用具有該權限,此方法也會返回 false

這部分的內容Android M 權限最佳實踐這篇文章寫得很好。

07. 官方例子

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);
    }
}

08. 兼容問題

首先明確一下在什么情況下需要使用運行時權限動態申請:

  1. 危險權限
  2. Android 版本 >= 6.0
  3. targetSdkVersion >= 23

在這三個條件同時具備的情況下必須使用運行時權限機制。當targetSdkVersion < 23的時候不用調用運行時權限機制,當targetSdkVersion >= 23的時候必須調用運行時權限機制以確保程序不會出現崩潰。另外,運行時權限機制的相關 API 都是在support.v4包下,說明做了低版本兼容,相關 API 運行在低版本時候均有默認的返回值。在此基礎上兼容適配問題可以考慮從兩個因素Android 版本targetSdkVersion入手,用一張表來簡單分析兼容適配問題:

targetSdkVersion Android 版本 兼容適配
targetSdkVersion < 23 SDK < 23 安裝時授權,正常使用
targetSdkVersion < 23 SDK >= 23 直接安裝并授權,用戶管理權限,可能崩潰
targetSdkVersion >= 23 SDK < 23 安裝時授權,運行時權限 API 有默認返回值,正常使用
targetSdkVersion >= 23 SDK >= 23 直接安裝,運行時授權,用戶管理權限,正常使用

從表格中看出如果應用targetSdkVersion < 23運行在Android 6.0的手機上,由于用戶可以自主管理權限,取消某些授權,便會引起程序崩潰。因此,盡快提升目標版本同時添加運行時權限判斷申請 API 是很有必要的。

注意:對于以 Android 6.0 或更高版本為目標平臺的應用,請務必在運行時檢查和請求權限。即使不以 Android 6.0 為目標平臺,也應該在新權限模式下測試應用。

09. 其他小點

  • 如果您的應用需要危險權限,則每次執行需要這一權限的操作時您都必須檢查自己是否具有該權限。用戶始終可以自由調用此權限,因此,即使應用昨天使用了相機,它不能假設自己今天仍具有該權限。
  • 用戶只需要為每個權限組授予一次權限。當請求已經被授予的權限時,系統會調用您的 onRequestPermissionsResult() 回調方法,并傳遞 PERMISSION_GRANTED
  • 當系統要求用戶授予權限時,用戶可以選擇指示系統不再要求提供該權限。這種情況下,無論應用在什么時候使用 requestPermissions() 再次要求該權限,系統都會立即拒絕此請求。系統會調用您的 onRequestPermissionsResult() 回調方法,并傳遞 PERMISSION_DENIED

10. 奇思怪想

  • 同時申請多條相同權限時,只有一個權限提示。
  • 同時申請同組的多條權限時,只有一個權限提示。
  • onRequestPermissionsResult方法中的權限字符數組與requestPermissions方法中的相同。
  • 先檢查權限再申請權限。原因是第一次申請權限勾選允許,再次申請權限勾選拒絕,程序崩潰。同時申請多個權限,有的拒絕有的允許,再次申請時應該先檢查并剔除已經允許的權限。注意:崩潰出現在6.0的手機上,在7.0上回自動返回授權或者自動剔除。

11. 推薦文章

有幾篇非常不錯的文章值得閱讀學習:

  1. 張鴻洋 Android 6.0 運行時權限處理完全解析
  2. Android M 權限最佳實踐
  3. 嚴振杰 Android 6.0 運行時權限管理最佳實踐
  4. android permission權限與安全機制解析(下)
  5. 聊一聊 Android 6.0 的運行時權限
  6. Android 權限管理 —— AppOps
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,268評論 2 375

推薦閱讀更多精彩內容