Android 開發(fā)者必知必會(huì)的權(quán)限管理知識(shí)(轉(zhuǎn)載)

導(dǎo)語(yǔ)

感覺分析的挺全面手幢,故轉(zhuǎn)載歌溉,有小細(xì)節(jié)刪改,原文請(qǐng)點(diǎn)擊:
原文在這里

本文主要講解了Android 權(quán)限管理方面幾個(gè)點(diǎn):

  • Android 權(quán)限背景知識(shí)瓶颠;
  • 權(quán)限檢查及權(quán)限兼容拟赊;
  • 跳轉(zhuǎn)到app管理權(quán)限頁(yè)面

一、Android 權(quán)限背景知識(shí)

提到Android 權(quán)限管理粹淋,業(yè)內(nèi)人士都知道Google 在Android 6.0時(shí)提出了運(yùn)行時(shí)權(quán)限管理機(jī)制吸祟,在Android 6.0之前,所申請(qǐng)的權(quán)限只需要在AndroidManifest.xml列舉就可以桃移,從而容易導(dǎo)致一些安全隱患屋匕,因此,在Android 6.0 時(shí)谴轮,Google 為了更好的保護(hù)用戶隱私提出了新的權(quán)限管理機(jī)制(官網(wǎng) :Working with System Permissions)炒瘟,同時(shí)將其分為兩大類:

(1)Normal Permissions

Normal Permissions 一般不涉及用戶隱私吹埠,是不需要用戶進(jìn)行授權(quán)的第步,比如手機(jī)震動(dòng)、訪問網(wǎng)絡(luò)等缘琅;

(2)Dangerous Permission

Dangerous Permission一般是涉及到用戶隱私的粘都,需要用戶進(jìn)行授權(quán)(動(dòng)態(tài)申請(qǐng)),比如讀取SIM卡狀態(tài)刷袍、訪問通訊錄翩隧、SD卡讀寫等。

通過 adb shell pm list permissions -d -g 可以查看 Dangerous Permission (以權(quán)限組形式)

Dangerous Permission group

如上圖所示 :Dangerous Permission 一般以 Permission group 形式存在呻纹,只要 Permission group中某一個(gè) permission 被Granted堆生,則整個(gè)Permission group下的權(quán)限均被Granted (目前是這樣,以后規(guī)則說不定會(huì)變)雷酪。

二淑仆、權(quán)限檢查及權(quán)限兼容

本節(jié)主要介紹介紹如何進(jìn)行權(quán)限檢查及權(quán)限兼容,主要分為以下幾類:

(1)targetSdkVersion>=23哥力,終端設(shè)備是6.0(api 23)以上系統(tǒng)蔗怠;

安裝的時(shí)候不會(huì)獲得權(quán)限墩弯,在運(yùn)行時(shí)向用戶申請(qǐng)對(duì)應(yīng)權(quán)限。這部分權(quán)限檢查比較簡(jiǎn)單寞射,不涉及權(quán)限兼容渔工,使用官方方案就可以 ,使用 Context::checkSelfPermisson 桥温,建議使用ContextCompat::checkSelfPermisson檢查權(quán)限 即可 引矩,一般檢查流程 如下:

1 判斷是否有對(duì)應(yīng)權(quán)限
(ContextCompat::checkSelfPermisson)

2 判斷是否需要解釋對(duì)應(yīng)權(quán)限用途(ActivityCompat::shouldShowRequestPermissionRationale)
如果需要解釋,則現(xiàn)實(shí)自定義權(quán)限界面即可

3 不需要解釋的話侵浸,直接請(qǐng)求對(duì)應(yīng)權(quán)限
(ActivityCompat::requestPermissions)

上述情況較為簡(jiǎn)單脓魏,在此不再贅述。

(2)targetSdkVersion<23通惫,終端設(shè)備是6.0(api 23)以上系統(tǒng)茂翔;

使用的是老的權(quán)限機(jī)制,在app 安裝時(shí)會(huì)詢問AndroidManifest.xml文件中的權(quán)限履腋,但是用戶可以在設(shè)置列表中關(guān)閉相關(guān)權(quán)限珊燎,這種情況可能會(huì)對(duì)app正常運(yùn)行造成一定影響。

(3) 終端設(shè)備系統(tǒng)小于6.0(api 23)

大家可能要問遵湖,終端設(shè)備系統(tǒng)小于6.0情況還需要考慮嗎悔政,肯定是用的老的權(quán)限管理機(jī)制,在app 安裝時(shí)會(huì)詢問AndroidManifest.xml文件中的權(quán)限延旧,用戶關(guān)閉不了谋国,真的是這樣嗎 ?

答案是否定的迁沫,在實(shí)測(cè)中發(fā)現(xiàn)芦瘾,目前有不少國(guó)產(chǎn)Rom 手機(jī)在6.0之前就有關(guān)閉權(quán)限的開關(guān)。這種情況也是我們兼容的對(duì)象集畅。

下面將會(huì)以自己開發(fā)過程中遇到的問題進(jìn)行展開 近弟,目前企鵝FM支持免流了,需要使用READ_PHONE_STATE權(quán)限 (讀取SIM卡狀態(tài))挺智,由于之前未對(duì)改權(quán)限是否關(guān)閉沒有進(jìn)行相關(guān)判斷祷愉,因此收到了很多例因?yàn)樯鲜鰴?quán)限關(guān)閉,導(dǎo)致免流失敗的情況赦颇。

適配過程如下 :

(1)使用 try catch 來檢查權(quán)限是否關(guān)閉

想法很簡(jiǎn)單二鳄,如果改權(quán)限被用戶禁止了,那肯定會(huì)異常媒怯,因此可以在catch 中做文章订讼,結(jié)果發(fā)現(xiàn)這一招根本沒有用,為啥了 沪摄?因?yàn)槭褂?READ_PHONE_STATE 權(quán)限的方法內(nèi)部已經(jīng)try catch 躯嫉,外面無(wú)法捕獲纱烘,因此該方法失效。

(2)ContextCompat::checkSelfPermisson

既然在6.0 可以使用Context::checkSelfPermisson進(jìn)行權(quán)限檢查祈餐,那能否使用support v4 中的ContextCompat::checkSelfPermisson 方法了擂啥,試一下,發(fā)現(xiàn)在api 23 以下失效帆阳,為了探究原因哺壶,查看了ActivityCompat::requestPermissons 內(nèi)部實(shí)現(xiàn),如下

ActivityCompat::requestPermissons

內(nèi)部權(quán)限檢查方法在api 23 以下蜒谤,使用的是 PackageManager::checkPermission山宾,再去查看PackageManager::checkPermission方法,如下:發(fā)現(xiàn)只要權(quán)限在AndroidManifest.xml中注冊(cè)過鳍徽,均會(huì)認(rèn)為該權(quán)限granted 资锰,因此上述方法在api 23 以下也失效。

PackageManager::checkPermission

查閱相關(guān)資料和請(qǐng)教組內(nèi)同事阶祭,發(fā)現(xiàn)Support V4 下面有一個(gè)專門檢查權(quán)限的工具類PermissionChecker绷杜。

(3)PermissionChecker

查看PermissionChecker源碼發(fā)現(xiàn) ,PermissionChecker內(nèi)部實(shí)際上使用的是AppOpsManagerCompt濒募,而AppOpsManager是在api 19 加入進(jìn)入的(AppOpsManager后面介紹)

PermissionChecker::checkPermission

進(jìn)而查看AppOpsManagerCompat 內(nèi)部實(shí)現(xiàn)

AppOpsManagerCompat::permissionToOp

IMPL實(shí)現(xiàn)如下:

IMPL實(shí)現(xiàn)

從上圖可以看出:在api 23以下鞭盟, AppOpsManagerImpl::permissionToOp 直接返回為null ,這直接導(dǎo)致api 23以下權(quán)限檢查將會(huì)返回 granted 瑰剃,因此齿诉,該方法在api 23 下,權(quán)限檢查方法也會(huì)失效晌姚。

(4)AppOpsManager

API 19以上 粤剧,Google 官方提供了 AppOpsManager 類來檢查權(quán)限,看到這個(gè)api 時(shí)舀凛,腦海浮現(xiàn)出 “天無(wú)絕人之路啊”俊扳,里面有兩個(gè)比較重要的方法 :AppOpsManager::checkOp(int op ,int uid ,String packageName) (hide方法)和AppOpsManager::checkOp(String op,int uid ,String packageName)(public 方法 ,api 23 以上可用)猛遍,不經(jīng)思考,直接寫出了如下兩個(gè)方法

1)AppOpsManager::checkOp(int op ,int uid ,String packageName)

需要使用反射

2)AppOpsManager::checkOp(String op,int uid ,String packageName)

API >= 23 才可以使用 :

同時(shí)也仔細(xì)看了一下AppOpsManager 類介紹号坡,并不是為開發(fā)者設(shè)計(jì)的懊烤,不過其他權(quán)限兼容可以使用這種方法,前提是 要看OP_*是在什么版本才有的宽堆,需做兼容方案 腌紧。

(5)最后查看了幾個(gè)第三方權(quán)限庫(kù)(暫未看完)

PermissionsDispatcher

AndPermission

三、跳轉(zhuǎn)到app管理權(quán)限頁(yè)面

既然在這里講解跳轉(zhuǎn)到app 管理權(quán)限頁(yè)面的方法畜隶,可想而之壁肋,事情絕對(duì)不太簡(jiǎn)單号胚。Android 碎片化不僅在存在于ui適配 ,同樣也存在于這里浸遗,導(dǎo)致我們無(wú)法使用同一種方式跳轉(zhuǎn)到app管理權(quán)限頁(yè)面(適配猫胁,Android 開發(fā)永遠(yuǎn)的痛)。

那有沒有辦法可以簡(jiǎn)化適配工作跛锌,減少開發(fā)量弃秆,方法當(dāng)然有,不過需要我們自己去總結(jié)和探索的髓帽,目前已有方法:

(1)直接跳轉(zhuǎn)到系統(tǒng)設(shè)置頁(yè)

Intent intent =newIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package",getPackageName(), null));

try{
    startActivity(intent);
}catch(Exception exception) {
    exception.printStackTrace();
}

記得要添加上 try catch 菠赚,不加可能會(huì)crash。這種方式就不需要適配各個(gè)廠商的不同版本rom郑藏,缺點(diǎn)是衡查,用戶只能跳轉(zhuǎn)到系統(tǒng)設(shè)置頁(yè),然后去找對(duì)應(yīng)app 的權(quán)限管理(總會(huì)有一些用戶找不到)

(2)站在前人的肩上

引用前人經(jīng)驗(yàn):Android各大手機(jī)品牌手機(jī)跳轉(zhuǎn)到權(quán)限管理界面 (未一一驗(yàn)證必盖,畢竟沒那么多手機(jī))

那是不是前人經(jīng)驗(yàn)一定對(duì)了峡捡,那就不一定了,在當(dāng)時(shí)可能是對(duì)的筑悴,在現(xiàn)在可能就行不通了们拙,現(xiàn)在以MIUI跳轉(zhuǎn)到app 權(quán)限管理頁(yè)面為例進(jìn)行說明。

1)MIUI 6/7

Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
localIntent.putExtra("extra_pkgname", context.getPackageName());

try{
    startActivity(intent);
}catch(Exception exception) {
    exception.printStackTrace();
}

2)MIUI 8

Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
localIntent.putExtra("extra_pkgname", context.getPackageName());

try{
    startActivity(intent);
}catch(Exception exception) {
    exception.printStackTrace();
}

對(duì)比1)和2)發(fā)現(xiàn)阁吝,在MIUI 6/7 和MIUI 8 上面砚婆,權(quán)限管理頁(yè)面的activity名字不一樣了,因此使用MIUI6/7的方法在MIUI8上就會(huì)失效突勇,如果沒有加上try catch 装盯,就會(huì)直接crash。

對(duì)于上述變化甲馋,作為一個(gè)開發(fā)者一般都是不知道的埂奈,即便通過反饋發(fā)現(xiàn)了這個(gè)問題,也有可能不知道對(duì)應(yīng)的activity是什么定躏,此刻要么搜索網(wǎng)上有沒有類似解決方案账磺,要么求助于對(duì)應(yīng)rom 開發(fā)廠商的開發(fā)者論壇 (有時(shí)解決回應(yīng)速度相當(dāng)慢),那有沒有更好的辦法了痊远,方法詳見(3)部分垮抗。

(3)查看某個(gè)ROM的某個(gè)版本的權(quán)限管理頁(yè)面的activity

這里以華為p8為例簡(jiǎn)要說明,詳細(xì)步驟如下:

1)通過設(shè)置找到對(duì)應(yīng)app的權(quán)限管理頁(yè)面碧聪,如下:

企鵝fm在華為p8上的權(quán)限管理頁(yè)面

2)找到對(duì)應(yīng)頁(yè)面的activity

方法一:通過add 工具查看棧頂Activity

adb shell dumpsys activity | grep "mFocusedActivity"

詳細(xì)的堆棧信息見命令窗口

方法二:使用Activity Tracer工具

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末冒版,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逞姿,更是在濱河造成了極大的恐慌辞嗡,老刑警劉巖捆等,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異续室,居然都是意外死亡栋烤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門猎贴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來班缎,“玉大人,你說我怎么就攤上這事她渴〈镏罚” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵趁耗,是天一觀的道長(zhǎng)沉唠。 經(jīng)常有香客問我,道長(zhǎng)苛败,這世上最難降的妖魔是什么满葛? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮罢屈,結(jié)果婚禮上嘀韧,老公的妹妹穿的比我還像新娘竭讳。我一直安慰自己儡炼,他們只是感情好坑鱼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布愕难。 她就那樣靜靜地躺著,像睡著了一般四康。 火紅的嫁衣襯著肌膚如雪古涧。 梳的紋絲不亂的頭發(fā)上馍乙,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天哑芹,我揣著相機(jī)與錄音炎辨,去河邊找鬼。 笑死聪姿,一個(gè)胖子當(dāng)著我的面吹牛碴萧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咳燕,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼勿决,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了招盲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嘉冒,失蹤者是張志新(化名)和其女友劉穎曹货,沒想到半個(gè)月后咆繁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡顶籽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年玩般,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片礼饱。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坏为,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镊绪,到底是詐尸還是另有隱情匀伏,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布蝴韭,位于F島的核電站够颠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏榄鉴。R本人自食惡果不足惜履磨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庆尘。 院中可真熱鬧剃诅,春花似錦、人聲如沸驶忌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)位岔。三九已至如筛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抒抬,已是汗流浹背杨刨。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留擦剑,地道東北人妖胀。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像惠勒,于是被迫代替她去往敵國(guó)和親赚抡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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