運(yùn)行時(shí)請(qǐng)求權(quán)限

系統(tǒng)權(quán)限分為兩類:正常權(quán)限危險(xiǎn)權(quán)限

  • 正常權(quán)限不會(huì)直接給用戶隱私權(quán)帶來(lái)風(fēng)險(xiǎn)针贬。如果您的應(yīng)用在其清單中列出了正常權(quán)限,系統(tǒng)將自動(dòng)授予該權(quán)限赋兵。
  • 危險(xiǎn)權(quán)限會(huì)授予應(yīng)用訪問(wèn)用戶機(jī)密數(shù)據(jù)的權(quán)限笔咽。如果您的應(yīng)用在其清單中列出了正常權(quán)限,系統(tǒng)將自動(dòng)授予該權(quán)限霹期。如果您列出了危險(xiǎn)權(quán)限叶组,則用戶必須明確批準(zhǔn)您的應(yīng)用使用這些權(quán)限。

如需了解詳細(xì)信息历造,請(qǐng)參閱正常權(quán)限和危險(xiǎn)權(quán)限甩十。

在所有版本的 Android 中船庇,您的應(yīng)用都需要在其應(yīng)用清單中同時(shí)聲明它需要的正常權(quán)限和危險(xiǎn)權(quán)限,如聲明權(quán)限中所述侣监。不過(guò)鸭轮,該聲明的影響因系統(tǒng)版本和應(yīng)用的目標(biāo) SDK 級(jí)別的不同而有所差異:

  • 如果設(shè)備運(yùn)行的是 Android 5.1 或更低版本,或者應(yīng)用的目標(biāo) SDK 為 22 或更低:如果您在清單中列出了危險(xiǎn)權(quán)限橄霉,則用戶必須在安裝應(yīng)用時(shí)授予此權(quán)限窃爷;如果他們不授予此權(quán)限,系統(tǒng)根本不會(huì)安裝應(yīng)用姓蜂。
  • 如果設(shè)備運(yùn)行的是 Android 6.0 或更高版本按厘,或者應(yīng)用的目標(biāo) SDK 為 23 或更高:應(yīng)用必須在清單中列出權(quán)限,并且它必須在運(yùn)行時(shí)請(qǐng)求其需要的每項(xiàng)危險(xiǎn)權(quán)限钱慢。用戶可以授予或拒絕每項(xiàng)權(quán)限刻剥,且即使用戶拒絕權(quán)限請(qǐng)求,應(yīng)用仍可以繼續(xù)運(yùn)行有限的功能滩字。

:從 Android 6.0(API 級(jí)別 23)開(kāi)始,用戶可以隨時(shí)從任意應(yīng)用調(diào)用權(quán)限御吞,即使應(yīng)用面向較低的 API 級(jí)別也可以調(diào)用麦箍。無(wú)論您的應(yīng)用面向哪個(gè) API 級(jí)別,您都應(yīng)對(duì)應(yīng)用進(jìn)行測(cè)試陶珠,以驗(yàn)證它在缺少需要的權(quán)限時(shí)行為是否正常挟裂。

本課將介紹如何使用 Android 支持庫(kù)來(lái)檢查和請(qǐng)求權(quán)限。Android 框架從 Android 6.0(API 級(jí)別 23)開(kāi)始提供類似方法揍诽。不過(guò)诀蓉,使用支持庫(kù)更簡(jiǎn)單,因?yàn)樵谡{(diào)用方法前暑脆,您的應(yīng)用不需要檢查它在哪個(gè)版本的 Android 上運(yùn)行渠啤。

檢查權(quán)限

如果您的應(yīng)用需要危險(xiǎn)權(quán)限,則每次執(zhí)行需要這一權(quán)限的操作時(shí)您都必須檢查自己是否具有該權(quán)限添吗。用戶始終可以自由調(diào)用此權(quán)限沥曹,因此,即使應(yīng)用昨天使用了相機(jī)碟联,它不能假設(shè)自己今天仍具有該權(quán)限妓美。

要檢查您是否具有某項(xiàng)權(quán)限,請(qǐng)調(diào)用 ContextCompat.checkSelfPermission() 方法鲤孵。例如壶栋,以下代碼段顯示了如何檢查 Activity 是否具有在日歷中進(jìn)行寫入的權(quán)限:

// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);

如果應(yīng)用具有此權(quán)限,方法將返回 PackageManager.PERMISSION_GRANTED普监,并且應(yīng)用可以繼續(xù)操作贵试。如果應(yīng)用不具有此權(quán)限琉兜,方法將返回 PERMISSION_DENIED,且應(yīng)用必須明確向用戶要求權(quán)限锡移。

請(qǐng)求權(quán)限

如果您的應(yīng)用需要應(yīng)用清單中列出的危險(xiǎn)權(quán)限呕童,那么,它必須要求用戶授予該權(quán)限淆珊。Android 為您提供了多種權(quán)限請(qǐng)求方式夺饲。調(diào)用這些方法將顯示一個(gè)標(biāo)準(zhǔn)的 Android 對(duì)話框,不過(guò)施符,您不能對(duì)它們進(jìn)行自定義往声。

解釋應(yīng)用為什么需要權(quán)限
image

圖 1. 提示用戶授予或拒絕權(quán)限的系統(tǒng)對(duì)話框。

在某些情況下戳吝,您可能需要幫助用戶了解您的應(yīng)用為什么需要某項(xiàng)權(quán)限浩销。例如,如果用戶啟動(dòng)一個(gè)攝影應(yīng)用听哭,用戶對(duì)應(yīng)用要求使用相機(jī)的權(quán)限可能不會(huì)感到吃驚慢洋,但用戶可能無(wú)法理解為什么此應(yīng)用想要訪問(wèn)用戶的位置或聯(lián)系人。在請(qǐng)求權(quán)限之前陆盘,不妨為用戶提供一個(gè)解釋普筹。請(qǐng)記住,您不需要通過(guò)解釋來(lái)說(shuō)服用戶隘马;如果您提供太多解釋太防,用戶可能發(fā)現(xiàn)應(yīng)用令人失望并將其移除。

您可以采用的一個(gè)方法是僅在用戶已拒絕某項(xiàng)權(quán)限請(qǐng)求時(shí)提供解釋酸员。如果用戶繼續(xù)嘗試使用需要某項(xiàng)權(quán)限的功能蜒车,但繼續(xù)拒絕權(quán)限請(qǐng)求,則可能表明用戶不理解應(yīng)用為什么需要此權(quán)限才能提供相關(guān)功能幔嗦。對(duì)于這種情況酿愧,比較好的做法是顯示解釋。

為了幫助查找用戶可能需要解釋的情形邀泉,Android 提供了一個(gè)實(shí)用程序方法寓娩,即 [shouldShowRequestPermissionRationale()](https://developer.android.google.cn/reference/android/support/v4/app/ActivityCompat.html#shouldShowRequestPermissionRationale(android.app.Activity, java.lang.String))。如果應(yīng)用之前請(qǐng)求過(guò)此權(quán)限但用戶拒絕了請(qǐng)求呼渣,此方法將返回 true棘伴。

:如果用戶在過(guò)去拒絕了權(quán)限請(qǐng)求,并在權(quán)限請(qǐng)求系統(tǒng)對(duì)話框中選擇了 Don't ask again 選項(xiàng)屁置,此方法將返回 false焊夸。如果設(shè)備規(guī)范禁止應(yīng)用具有該權(quán)限,此方法也會(huì)返回 false蓝角。

請(qǐng)求您需要的權(quán)限

如果應(yīng)用尚無(wú)所需的權(quán)限阱穗,則應(yīng)用必須調(diào)用一個(gè) requestPermissions() 方法饭冬,以請(qǐng)求適當(dāng)?shù)臋?quán)限。應(yīng)用將傳遞其所需的權(quán)限揪阶,以及您指定用于識(shí)別此權(quán)限請(qǐng)求的整型請(qǐng)求代碼昌抠。此方法異步運(yùn)行:它會(huì)立即返回,并且在用戶響應(yīng)對(duì)話框之后鲁僚,系統(tǒng)會(huì)使用結(jié)果調(diào)用應(yīng)用的回調(diào)方法炊苫,將應(yīng)用傳遞的相同請(qǐng)求代碼傳遞到 requestPermissions()

以下代碼可以檢查應(yīng)用是否具備讀取用戶聯(lián)系人的權(quán)限冰沙,并根據(jù)需要請(qǐng)求該權(quán)限:

// Here, thisActivity is the current activity
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);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

:當(dāng)您的應(yīng)用調(diào)用 requestPermissions() 時(shí)侨艾,系統(tǒng)將向用戶顯示一個(gè)標(biāo)準(zhǔn)對(duì)話框。您的應(yīng)用無(wú)法配置或更改此對(duì)話框拓挥。如果您需要為用戶提供任何信息或解釋唠梨,您應(yīng)在調(diào)用 requestPermissions() 之前進(jìn)行,如解釋應(yīng)用為什么需要權(quán)限中所述侥啤。

處理權(quán)限請(qǐng)求響應(yīng)

當(dāng)應(yīng)用請(qǐng)求權(quán)限時(shí)当叭,系統(tǒng)將向用戶顯示一個(gè)對(duì)話框。當(dāng)用戶響應(yīng)時(shí)盖灸,系統(tǒng)將調(diào)用應(yīng)用的 onRequestPermissionsResult() 方法科展,向其傳遞用戶響應(yīng)。您的應(yīng)用必須替換該方法糠雨,以了解是否已獲得相應(yīng)權(quán)限∨枪颍回調(diào)會(huì)將您傳遞的相同請(qǐng)求代碼傳遞給 requestPermissions()甘邀。例如,如果應(yīng)用請(qǐng)求 READ_CONTACTS 訪問(wèn)權(quán)限垮庐,則它可能采用以下回調(diào)方法:

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

系統(tǒng)顯示的對(duì)話框說(shuō)明了您的應(yīng)用需要訪問(wèn)的權(quán)限組松邪;它不會(huì)列出具體權(quán)限。例如哨查,如果您請(qǐng)求 READ_CONTACTS 權(quán)限逗抑,系統(tǒng)對(duì)話框只顯示您的應(yīng)用需要訪問(wèn)設(shè)備的聯(lián)系人。用戶只需要為每個(gè)權(quán)限組授予一次權(quán)限寒亥。如果您的應(yīng)用請(qǐng)求該組中的任何其他權(quán)限(已在您的應(yīng)用清單中列出)邮府,系統(tǒng)將自動(dòng)授予應(yīng)用這些權(quán)限。當(dāng)您請(qǐng)求此權(quán)限時(shí)溉奕,系統(tǒng)會(huì)調(diào)用您的 onRequestPermissionsResult() 回調(diào)方法褂傀,并傳遞 PERMISSION_GRANTED,如果用戶已通過(guò)系統(tǒng)對(duì)話框明確同意您的權(quán)限請(qǐng)求加勤,系統(tǒng)將采用相同方式操作仙辟。

:您的應(yīng)用仍需要明確請(qǐng)求其需要的每項(xiàng)權(quán)限同波,即使用戶已向應(yīng)用授予該權(quán)限組中的其他權(quán)限。此外叠国,權(quán)限分組在將來(lái)的 Android 版本中可能會(huì)發(fā)生變化未檩。您的代碼不應(yīng)依賴特定權(quán)限屬于或不屬于相同組這種假設(shè)。

例如粟焊,假設(shè)您在應(yīng)用清單中列出了 READ_CONTACTSWRITE_CONTACTS冤狡。如果您請(qǐng)求 READ_CONTACTS 且用戶授予了此權(quán)限,那么吆玖,當(dāng)您請(qǐng)求 WRITE_CONTACTS 時(shí)筒溃,系統(tǒng)將立即授予您該權(quán)限,不會(huì)與用戶交互沾乘。

如果用戶拒絕了某項(xiàng)權(quán)限請(qǐng)求怜奖,您的應(yīng)用應(yīng)采取適當(dāng)?shù)牟僮鳌@绯嵴螅膽?yīng)用可能顯示一個(gè)對(duì)話框歪玲,解釋它為什么無(wú)法執(zhí)行用戶已經(jīng)請(qǐng)求但需要該權(quán)限的操作。

當(dāng)系統(tǒng)要求用戶授予權(quán)限時(shí)掷匠,用戶可以選擇指示系統(tǒng)不再要求提供該權(quán)限滥崩。這種情況下,無(wú)論應(yīng)用在什么時(shí)候使用 requestPermissions() 再次要求該權(quán)限讹语,系統(tǒng)都會(huì)立即拒絕此請(qǐng)求钙皮。系統(tǒng)會(huì)調(diào)用您的 onRequestPermissionsResult() 回調(diào)方法,并傳遞 PERMISSION_DENIED顽决,如果用戶再次明確拒絕了您的請(qǐng)求短条,系統(tǒng)將采用相同方式操作。這意味著當(dāng)您調(diào)用 requestPermissions() 時(shí)才菠,您不能假設(shè)已經(jīng)發(fā)生與用戶的任何直接交互茸时。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赋访,隨后出現(xiàn)的幾起案子可都,更是在濱河造成了極大的恐慌,老刑警劉巖蚓耽,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渠牲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡步悠,警方通過(guò)查閱死者的電腦和手機(jī)嘱兼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贤徒,“玉大人芹壕,你說(shuō)我怎么就攤上這事汇四。” “怎么了踢涌?”我有些...
    開(kāi)封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵通孽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我睁壁,道長(zhǎng)背苦,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任潘明,我火速辦了婚禮行剂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钳降。我一直安慰自己厚宰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布遂填。 她就那樣靜靜地躺著铲觉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吓坚。 梳的紋絲不亂的頭發(fā)上撵幽,一...
    開(kāi)封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天,我揣著相機(jī)與錄音礁击,去河邊找鬼盐杂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛哆窿,可吹牛的內(nèi)容都是我干的链烈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼更耻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了捏膨?” 一聲冷哼從身側(cè)響起秧均,我...
    開(kāi)封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎号涯,沒(méi)想到半個(gè)月后目胡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡链快,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年誉己,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片域蜗。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巨双,死狀恐怖噪猾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情筑累,我是刑警寧澤袱蜡,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站慢宗,受9級(jí)特大地震影響坪蚁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜镜沽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一敏晤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缅茉,春花似錦嘴脾、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至筹我,卻和暖如春扶平,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蔬蕊。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工结澄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人岸夯。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓麻献,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親猜扮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子勉吻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

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