Permission的處理

為了保護(hù)系統(tǒng)的整體性和用戶隱私,Android系統(tǒng)中的每個App都是運行在一個帶限制的sandbox中,如果一個app想要從sandbox外獲取信息或資源,app就需要請求permission,而具體請求什么permission則要視你的具體情況而定,請求之后系統(tǒng)會根據(jù)不同的請求來自動授權(quán)或者讓用戶來選擇是否授權(quán).

1. 聲明Permission

如果你要請求某些permission來進(jìn)行相關(guān)操作,你需要在Manifest中聲明這些permission,系統(tǒng)會根據(jù)permission的敏感程度來決定授權(quán)方式,比如:

  • 你的app請求permission來打開閃關(guān)燈,系統(tǒng)會自動授權(quán).
  • 你的app請求讀取聯(lián)系人的權(quán)限,系統(tǒng)就會詢問用戶是同意授權(quán)該請求.

還有,不同的系統(tǒng)版本系統(tǒng)的授權(quán)方式也會不同:

  • Android 5.1及以下是安裝的時候請求授權(quán).
  • Android 6.0及以上是app真正操作需要是才請求授權(quán).

1.1 確定你的App需要的Permission

如何確定什么樣的操作需要請求permission?請求哪一種permission?
通常,如果你要獲取一些app外部的信息或資源,或者執(zhí)行一些會影響到設(shè)備或其他app的行為,這就需要permission,比如連接網(wǎng)絡(luò),使用攝像頭,操作wifi開關(guān)等.而要申請哪種permission則可以查看系統(tǒng)提供的permission列表,具體在Normal and Dangerous Permissions中.

要注意的是你只需要申請你直接操作的action所需要的permission即可,如果你調(diào)用其他的app去獲取一些信息或資源再返回給你,你就不需要申請相應(yīng)的permission.比如:

  • 你直接去讀取通訊錄,就需要有READ_CONTACTS permission.
  • 但是如果你使用Intent來啟動通訊錄app,然后返回給你結(jié)果,你就不需要READ_CONTACTS permission,而需要該permission的則是通訊錄app.

1.2 在Manifest中添加permission

如下示例:

<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>

2.運行時請求Permission

從Android 6.0(API 23)開始,系統(tǒng)的授權(quán)方式有變,從之前的安裝時授權(quán)變成使用時授權(quán).這會簡化應(yīng)用的安裝流程,也會給用戶在功能上更多的控制權(quán).比如,很多相機(jī)需要打開攝像頭的權(quán)限和獲取位置信息的權(quán)限,現(xiàn)在當(dāng)app請求這兩個權(quán)限時,你可以只授權(quán)獲取相機(jī)但是不授權(quán)獲取位置信息的permission.系統(tǒng)的permission分為兩類:normaldangeroous:

  • Normal Permission: 無獲取用戶隱私信息的風(fēng)險,如果在manifest中聲明了這些權(quán)限,系統(tǒng)會自動授權(quán).
  • Dangerous Permission: 需要獲取用戶隱私數(shù)據(jù),在manifest中聲明后,還需要在使用中讓用戶來決定同意是否授權(quán).

對于任何系統(tǒng)版本,都需要在menifest中聲明要使用的permission,但是normal和dangerous的permission還是有不同的影響:

  • Android 5.1(API 22)及以下,在安裝某個app的時候,如果你不同意列出的dangerous permissions,系統(tǒng)就不會安裝該app.
  • Android 6.0(API 23)及以上,app安裝時不需要授權(quán),在運行時需要授權(quán)時用戶來決定是否同意授權(quán),如果不同意app還是可以繼續(xù)運行只是某些功能可能會不能用.

下面將介紹如何使用Android Support Library來檢查和請求權(quán)限,與Android 6.0相似,但是這個support類庫能夠兼容之前的版本,所以無需判斷系統(tǒng)版本,會更簡單.

2.1 檢查Permission

dangerous permission需要你每次使用時都檢查是否有權(quán)限,可以調(diào)用 ContextCompat.checkSelfPermission()方法來檢查,如下示例:

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

返回的結(jié)果為PackageManager中的兩個常量:PERMISSION_GRANTEDPERMISSION_DENIED.

2.2 請求Permission

如果你在manifest中聲明了dangerous permission,就必須要詢問用戶是否同意授權(quán)該permission.Android系統(tǒng)中提供了幾種請求permission的方法,使用這些方法會調(diào)起一個標(biāo)準(zhǔn)的Android dialog,里面有一些選項,這個dialog你是不能定制的.

2.2.1 解釋為什么app需要這些permission

在一些情況下,你可能需要幫助用戶理解為什么你的app需要這些權(quán)限.比如你的應(yīng)用是一個攝影類app,很正常要請求攝像頭相關(guān)的permission,但是用戶可能不理解為什么你的app要獲取地址或者通訊錄信息.在你請求這些可能不好理解的權(quán)限時,你應(yīng)該給用戶提供一些解釋說明,不要太復(fù)雜.

有一個方法可以幫助你確定合適需要提供一個解釋說明,就是ActivityCompat類中的shouldShowRequestPermissionRationale()方法.如果你之前請求過某個請求并被拒絕,該方法會返回true.

  • 注意: 當(dāng)用戶拒絕該請求時并勾選了"不再詢問"時,shouldShowRequestPermissionRationale()會返回false,同時如果permission為設(shè)備的政策禁止app要請求的permission時,也會返回false.

2.2.2 只請求需要的permission

如果你的app沒拿到需要的permission,你需要使用requestPermissions()來請求,是異步的,但是你取消不了dialog,除非選擇,代碼如下:

// 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.
    }
}
  • 注意: requestPermissions()中的第三個參數(shù)是請求碼,方便回調(diào)處理.并且請求碼只能使用(0-255內(nèi)的數(shù)值)(lower 8 bits).

2.2.3 處理回調(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
    }
}

上面的處理結(jié)果是按組permission group來分的,也就是只要你這個組中有個permission被授權(quán),這個組中的其他permission也會被授權(quán).比如你請求READ_CONTACTS和WRITE_CONTACTS兩個permission,如果系統(tǒng)授權(quán)了一個則另一個也會自動會被授權(quán). 但是要注意的是permission的分組有可能在以后改變,所以不能依賴具體分組來做操作.

3. Permission的最佳實踐

Permission的良好請求也是用戶體驗的一部分,用不好分分鐘被卸載,還是要重視的.

3.1 考慮使用Intent

很多情況下你會有兩個選擇:

a. 直接請求permission來執(zhí)行相關(guān)操作.

b. 使用Intent來調(diào)起其他的app來執(zhí)行相關(guān)操作.

比如拍照:

a. 你可以請求你可以請求CAMERA權(quán)限,然后直接操作攝像頭,利用相關(guān)API來拍照,這樣你可以完全控制拍照過程和自定義拍照UI.

b. 你可以使用ACTION_IMAGE_CAPTURE Intent來調(diào)起相機(jī),然后在onActivityResult()中處理返回結(jié)果,具體可以看下這個

相似的,在打電話,訪問通訊錄等你也有上述兩種選擇,現(xiàn)在說說這兩種選擇的優(yōu)點和缺點:

a. 直接請求permission來執(zhí)行相關(guān)操作:

*   你的App擁有完全的控制權(quán),同時又帶來復(fù)雜的工作量.
*   如果用戶沒有給你授權(quán)或者授權(quán)之后撤銷了,你的相關(guān)功能就不能運行.

b. 使用Intent:

*   無需考慮操作的UI,工作量小,執(zhí)行該intent的app會負(fù)責(zé)這些,也就是你對于這些UI沒有控制權(quán).
*   如果有多個處理該Intent的app,則用戶需要選擇一個來操作,如果用戶沒有將其設(shè)為默認(rèn),則每次處理該Intent用戶都要選一次,可能會麻煩.

3.2 測試Permission模型

Android 6.0開始permission的授權(quán)方式改變了,下面有一些tips可以幫助你識別Android 6.0及以后的設(shè)備中permission相關(guān)的問題:

  • 識別app當(dāng)前的permission和相關(guān)代碼的路徑.
  • Test user flows across permission-protected services and data.
  • 測試授權(quán)或撤銷各種組合.
  • 使用adb工具類管理permission.
// List permissions and status by group:
$ adb shell pm list permissions -d -g
// Grant or revoke one or more permissions:
$ adb shell pm [grant|revoke] <permission-name> ...
  • 分析你的app使用權(quán)限的services

Reference

  1. Working with System Permissions
  2. Declaring Permissions
  3. Requesting Permissions at Run Time
  4. Permissions Best Practices
  5. DESIGN PATTERNS--Permissions
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市贞盯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌闷愤,老刑警劉巖件余,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遭居,死亡現(xiàn)場離奇詭異旬渠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)告丢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門岖免,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人话侧,你說我怎么就攤上這事闯参。” “怎么了赢赊?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵释移,是天一觀的道長。 經(jīng)常有香客問我涩蜘,道長熏纯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任误窖,我火速辦了婚禮秩贰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毒费。我一直安慰自己,他們只是感情好想际,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布胡本。 她就那樣靜靜地躺著,像睡著了一般侧甫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天僻爽,我揣著相機(jī)與錄音贾惦,去河邊找鬼。 笑死碰镜,一個胖子當(dāng)著我的面吹牛习瑰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甜奄,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼课兄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搬俊?” 一聲冷哼從身側(cè)響起蜒茄,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎楔敌,沒想到半個月后驻谆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庆聘,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡勺卢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年黑忱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菇曲。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡抚吠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出喊式,到底是詐尸還是另有隱情萧朝,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布献联,位于F島的核電站厕吉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏头朱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一班眯、第九天 我趴在偏房一處隱蔽的房頂上張望烁巫。 院中可真熱鬧,春花似錦磁餐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嗤谚,卻和暖如春怔蚌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背桦踊。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工钞钙, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留声离,地道東北人。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓本刽,卻偏偏與公主長得像赠涮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子笋除,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

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