Android 運行時權(quán)限RuntimePermission

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

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

作者:JustDo23

01. 前言

運行時權(quán)限Android 6.0 變更中尤為突出的一點锰茉。6以下的手機在安裝時候提示權(quán)限列表嫂用,用戶全部同意后才能安裝程序沐寺;6以后的手機直接安裝书在,在運行過程中動態(tài)的向用戶申請所需權(quán)限缩多,另外用戶可以在設置界面對程序的各個權(quán)限進行管理友浸。

Android 中的權(quán)限可以分為三類:

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

普通權(quán)限不涉及用戶隱私峰尝,在AndroidManifest.xml中聲明即獲取收恢;危險權(quán)限涉及用戶的隱私武学,在用戶授權(quán)之后方能使用。另外伦意,Google 對危險權(quán)限進行了分組火窒,當某一個組中的某一個權(quán)限被授權(quán)之后應用同時就獲取到了整個組的所有權(quán)限。而且驮肉,調(diào)用 API 申請權(quán)限時系統(tǒng)將向用戶顯示一個標準對話框熏矿,該對話框上的提示權(quán)限說明是針對整個組的說明,應用無法配置或更改此對話框离钝。

02. 聲明權(quán)限

官方文檔中提到:為了保護系統(tǒng)的完整性和用戶隱私權(quán)票编,Android 在訪問受限的沙盒中運行每款應用。如果應用需要使用其沙盒以外的資源或信息卵渴,則必須明確請求權(quán)限慧域。根據(jù)應用請求的權(quán)限類型,系統(tǒng)可能會自動授予權(quán)限奖恰,也可能會要求用戶授予權(quán)限吊趾。可以在應用清單中列出相應的權(quán)限瑟啃,聲明應用需要此權(quán)限论泛。

聲明權(quán)限,將<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. 檢查權(quán)限

/**
 * 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 檢查是否擁有權(quán)限屁奏,簡單封裝如下:

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

04. 請求權(quán)限

/**
 * 請求指定的權(quán)限集合
 *
 * @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);
  • 此方法為異步方法
  • 第二參數(shù)指定一個權(quán)限的字符數(shù)組
// 請求一個相機權(quán)限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 23);
// 同時請求三個權(quán)限
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, "授權(quán)");
          } else {
            ToastUtil.showShortToast(MainActivity.this, "拒絕");
          }
        }
        break;
      case 32:
        break;
    }
}
  • 第二個參數(shù)是請求的權(quán)限數(shù)組
  • 第三個參數(shù)是與請求數(shù)組對應的授權(quán)結(jié)果數(shù)組

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
}
  • 如果應用之前請求過此權(quán)限但用戶拒絕了請求,此方法將返回 true错负。
  • 如果用戶在過去拒絕了權(quán)限請求坟瓢,并在權(quán)限請求系統(tǒng)對話框中選擇了 Don't ask again 選項,此方法將返回 false犹撒。
  • 如果設備規(guī)范禁止應用具有該權(quán)限折联,此方法也會返回 false

這部分的內(nèi)容Android M 權(quán)限最佳實踐這篇文章寫得很好识颊。

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. 兼容問題

首先明確一下在什么情況下需要使用運行時權(quán)限動態(tài)申請:

  1. 危險權(quán)限
  2. Android 版本 >= 6.0
  3. targetSdkVersion >= 23

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

targetSdkVersion Android 版本 兼容適配
targetSdkVersion < 23 SDK < 23 安裝時授權(quán),正常使用
targetSdkVersion < 23 SDK >= 23 直接安裝并授權(quán)检号,用戶管理權(quán)限腌歉,可能崩潰
targetSdkVersion >= 23 SDK < 23 安裝時授權(quán),運行時權(quán)限 API 有默認返回值谨敛,正常使用
targetSdkVersion >= 23 SDK >= 23 直接安裝究履,運行時授權(quán),用戶管理權(quán)限脸狸,正常使用

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

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

09. 其他小點

  • 如果您的應用需要危險權(quán)限,則每次執(zhí)行需要這一權(quán)限的操作時您都必須檢查自己是否具有該權(quán)限官辽。用戶始終可以自由調(diào)用此權(quán)限蛹磺,因此,即使應用昨天使用了相機同仆,它不能假設自己今天仍具有該權(quán)限萤捆。
  • 用戶只需要為每個權(quán)限組授予一次權(quán)限。當請求已經(jīng)被授予的權(quán)限時俗批,系統(tǒng)會調(diào)用您的 onRequestPermissionsResult() 回調(diào)方法俗或,并傳遞 PERMISSION_GRANTED
  • 當系統(tǒng)要求用戶授予權(quán)限時岁忘,用戶可以選擇指示系統(tǒng)不再要求提供該權(quán)限辛慰。這種情況下,無論應用在什么時候使用 requestPermissions() 再次要求該權(quán)限干像,系統(tǒng)都會立即拒絕此請求昆雀。系統(tǒng)會調(diào)用您的 onRequestPermissionsResult() 回調(diào)方法辱志,并傳遞 PERMISSION_DENIED

10. 奇思怪想

  • 同時申請多條相同權(quán)限時狞膘,只有一個權(quán)限提示。
  • 同時申請同組的多條權(quán)限時什乙,只有一個權(quán)限提示挽封。
  • onRequestPermissionsResult方法中的權(quán)限字符數(shù)組與requestPermissions方法中的相同。
  • 先檢查權(quán)限再申請權(quán)限臣镣。原因是第一次申請權(quán)限勾選允許辅愿,再次申請權(quán)限勾選拒絕,程序崩潰忆某。同時申請多個權(quán)限点待,有的拒絕有的允許,再次申請時應該先檢查并剔除已經(jīng)允許的權(quán)限弃舒。注意:崩潰出現(xiàn)在6.0的手機上癞埠,在7.0上回自動返回授權(quán)或者自動剔除。

11. 推薦文章

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

  1. 張鴻洋 Android 6.0 運行時權(quán)限處理完全解析
  2. Android M 權(quán)限最佳實踐
  3. 嚴振杰 Android 6.0 運行時權(quán)限管理最佳實踐
  4. android permission權(quán)限與安全機制解析(下)
  5. 聊一聊 Android 6.0 的運行時權(quán)限
  6. Android 權(quán)限管理 —— AppOps
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末聋呢,一起剝皮案震驚了整個濱河市苗踪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌削锰,老刑警劉巖通铲,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異器贩,居然都是意外死亡颅夺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門蛹稍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吧黄,“玉大人,你說我怎么就攤上這事稳摄≈勺郑” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵厦酬,是天一觀的道長胆描。 經(jīng)常有香客問我,道長仗阅,這世上最難降的妖魔是什么昌讲? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮减噪,結(jié)果婚禮上短绸,老公的妹妹穿的比我還像新娘车吹。我一直安慰自己,他們只是感情好醋闭,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布窄驹。 她就那樣靜靜地躺著,像睡著了一般证逻。 火紅的嫁衣襯著肌膚如雪乐埠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天囚企,我揣著相機與錄音丈咐,去河邊找鬼。 笑死龙宏,一個胖子當著我的面吹牛棵逊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播银酗,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辆影,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了花吟?” 一聲冷哼從身側(cè)響起秸歧,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衅澈,沒想到半個月后键菱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡今布,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年经备,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片部默。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡侵蒙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出傅蹂,到底是詐尸還是另有隱情纷闺,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布份蝴,位于F島的核電站犁功,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏婚夫。R本人自食惡果不足惜浸卦,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望案糙。 院中可真熱鬧限嫌,春花似錦靴庆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至稚叹,卻和暖如春端礼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背入录。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留佳镜,地道東北人僚稿。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像蟀伸,于是被迫代替她去往敵國和親蚀同。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容