前言
從android 6.0(API 級(jí)別 23)開(kāi)始景东,android引入了運(yùn)行時(shí)權(quán)限,用戶開(kāi)始在應(yīng)用運(yùn)行時(shí)向其授予權(quán)限奔誓,而不是在應(yīng)用安裝時(shí)向其授予權(quán)限耐薯,如果應(yīng)用的某項(xiàng)功能需要使用到受運(yùn)行時(shí)權(quán)限保護(hù)的資源(例如相機(jī)、位置丝里、麥克風(fēng)等)曲初,但在運(yùn)行該功能前沒(méi)有動(dòng)態(tài)地申請(qǐng)相應(yīng)的權(quán)限,那么在調(diào)用該功能時(shí)就會(huì)拋出SecurityException異常杯聚, android 6.0已經(jīng)推出了很多年了臼婆,相信大家對(duì)于運(yùn)行時(shí)權(quán)限的申請(qǐng)過(guò)程已經(jīng)非常的熟悉,但是android的運(yùn)行時(shí)權(quán)限的申請(qǐng)過(guò)程一直都是非常的繁瑣的幌绍,主要有兩步:
1颁褂、在需要申請(qǐng)權(quán)限的地方檢查該權(quán)限是否被同意故响,如果同意了就直接執(zhí)行,如果不同意就動(dòng)態(tài)申請(qǐng)權(quán)限颁独;
2彩届、重寫Activity或Fragment的onRequestPermissionsResult方法,在里面根據(jù)grantResults數(shù)組判斷權(quán)限是否被同意誓酒,如果同意就直接執(zhí)行樟蠕,如果不同意就要進(jìn)行相應(yīng)的提示,如果用戶勾選了“don't ask again”靠柑,還要引導(dǎo)用戶去“Settings”界面打開(kāi)權(quán)限寨辩,這時(shí)還要重寫onActivityResult判斷權(quán)限是否被同意.
就是這簡(jiǎn)單的兩步,卻夾雜了大量的if else語(yǔ)句歼冰,不但不優(yōu)雅靡狞,而且每次都要寫重復(fù)的樣板代碼,可能android的開(kāi)發(fā)者也意識(shí)到了這一點(diǎn)隔嫡,在最新androidx中引入了activity result api甸怕,通過(guò)activity result api你可以不需要自己管理requestCode,只需要提供需要請(qǐng)求的權(quán)限和處理結(jié)果的回調(diào)就行腮恩,讓權(quán)限請(qǐng)求簡(jiǎn)單了一點(diǎn)蕾各,但是如果在權(quán)限請(qǐng)求的過(guò)程中,用戶點(diǎn)擊拒絕或者拒絕并不再詢問(wèn)庆揪,那么我們還是需要自己處理這些情況,但是這些處理流程都是一樣的妨托,完全可以封裝起來(lái)缸榛,所以我就把以前的一個(gè)使用無(wú)界面fragment代理權(quán)限申請(qǐng)的庫(kù)重構(gòu)了一下,讓權(quán)限的請(qǐng)求流程更加簡(jiǎn)單兰伤,本文會(huì)先復(fù)習(xí)一下權(quán)限的分類内颗,然后再介紹PermissionHelper申請(qǐng)權(quán)限時(shí)的設(shè)計(jì),最后記錄一下從android 6.0后隨著系統(tǒng)的迭代跟權(quán)限申請(qǐng)相關(guān)的重要行為變更敦腔。
權(quán)限的分類
android中所有的預(yù)定義權(quán)限(不包括廠商自定義的)都可以在Manifest.permission這個(gè)靜態(tài)類中找到定義均澳,android把權(quán)限分為四類:普通權(quán)限、簽名權(quán)限符衔、危險(xiǎn)權(quán)限和特殊權(quán)限找前,每一種類型的權(quán)限都分配一個(gè)對(duì)應(yīng)的Protection Level,分別為:normal判族、signature躺盛、dangerous和appop,下面簡(jiǎn)單介紹一下這四種類型的權(quán)限
1形帮、普通權(quán)限
普通權(quán)限也叫正常權(quán)限槽惫,Protection Level為normal周叮,它不需要?jiǎng)討B(tài)申請(qǐng),你只需要在AndroidManifest.xml中靜態(tài)地聲明界斜,然后系統(tǒng)在應(yīng)用安裝時(shí)就會(huì)自動(dòng)的授予該應(yīng)用相應(yīng)的權(quán)限仿耽,當(dāng)應(yīng)用獲得授權(quán)時(shí),它就可以訪問(wèn)應(yīng)用沙盒外受該普通權(quán)限保護(hù)地?cái)?shù)據(jù)或操作各薇,這些數(shù)據(jù)或操作不會(huì)泄漏或篡改用戶的隱私项贺,對(duì)用戶或其他應(yīng)用幾乎沒(méi)有風(fēng)險(xiǎn)。
2得糜、簽名權(quán)限
這類權(quán)限我們用得比較少敬扛,它只對(duì)擁有相同簽名的應(yīng)用開(kāi)放,Protection Level為signature朝抖,它也不需要?jiǎng)討B(tài)申請(qǐng)啥箭,例如應(yīng)用A在AndroidManifest.xml中自定義了一個(gè)permission且在權(quán)限標(biāo)簽中加入android:protectionLevel=”signature”,表示應(yīng)用A聲明了一個(gè)簽名權(quán)限治宣,那么應(yīng)用B想要訪問(wèn)應(yīng)用A受該權(quán)限保護(hù)的數(shù)據(jù)時(shí)急侥,必須要在AndroidManifest.xml中聲明該權(quán)限,同時(shí)要用與應(yīng)用A相同的簽名打包侮邀,這樣系統(tǒng)在應(yīng)用B安裝時(shí)才會(huì)自動(dòng)地授予應(yīng)用B該權(quán)限坏怪,應(yīng)用B在獲得授權(quán)后就可以訪問(wèn)該權(quán)限控制的數(shù)據(jù),其他應(yīng)用即使知道這個(gè)權(quán)限绊茧,也在AndroidManifest.xml中聲明了該權(quán)限铝宵,但由于應(yīng)用簽名不同,安裝時(shí)系統(tǒng)不會(huì)授予它該權(quán)限华畏,這樣其他應(yīng)用就無(wú)法訪問(wèn)受該權(quán)限保護(hù)的數(shù)據(jù)鹏秋。
還有一些簽名權(quán)限不會(huì)供第三方應(yīng)用程序使用,只會(huì)供系統(tǒng)預(yù)裝應(yīng)用使用亡笑,這種簽名權(quán)限的Protection Level為signature和privileged侣夷。
3、危險(xiǎn)權(quán)限
危險(xiǎn)權(quán)限也叫運(yùn)行時(shí)權(quán)限仑乌,Protection Level為dangerous百拓,跟普通權(quán)限相反,一旦應(yīng)用獲取了該類權(quán)限晰甚,用戶的隱私數(shù)據(jù)就會(huì)面臨被泄露或篡改的風(fēng)險(xiǎn)衙传,所以如果你想使用該權(quán)限保護(hù)的數(shù)據(jù)或操作,就必須在AndroidManifest.xml中靜態(tài)地聲明需要用到的危險(xiǎn)權(quán)限厕九,并在訪問(wèn)這些數(shù)據(jù)或操作前動(dòng)態(tài)的申請(qǐng)權(quán)限粪牲,系統(tǒng)就會(huì)彈出一個(gè)權(quán)限請(qǐng)求彈窗征求用戶的同意,除非用戶同意該權(quán)限止剖,否則你不能使用該權(quán)限保護(hù)的數(shù)據(jù)或操作腺阳。
所有的危險(xiǎn)權(quán)限都有對(duì)應(yīng)的權(quán)限組落君,android預(yù)定義了11個(gè)權(quán)限組(根據(jù)android 11總結(jié)),這11個(gè)權(quán)限組中包含了30個(gè)危險(xiǎn)權(quán)限和幾個(gè)普通權(quán)限亭引,當(dāng)我們動(dòng)態(tài)的申請(qǐng)某個(gè)危險(xiǎn)權(quán)限時(shí)绎速,都是按權(quán)限組申請(qǐng)的,當(dāng)用戶一旦同意授權(quán)該危險(xiǎn)權(quán)限焙蚓,那么該權(quán)限所對(duì)應(yīng)的權(quán)限組中的其他在AndroidManifest.xml中注冊(cè)的權(quán)限也會(huì)同時(shí)被授權(quán)纹冤,android預(yù)定義的11個(gè)權(quán)限組包含的危險(xiǎn)權(quán)限如下:
Permission Group | Dangerous Permissions |
---|---|
CALENDAR (日歷) | READ_CALENDAR WRITE_CALENDAR |
CALL_LOG (通話記錄,Added in android 29) | READ_CALL_LOG WRITE_CALL_LOG PROCESS_OUTGOING_CALLS |
CAMERA (相機(jī)) | CAMERA |
CONTACTS (通訊錄) | READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS |
LOCATION (位置信息) | ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION ACCESS_BACKGROUND_LOCATION (Added in android 10) |
MICROPHONE (麥克風(fēng)) | RECORD_AUDIO |
PHONE (電話) | READ_PHONE_NUMBERS READ_PHONE_STATE CALL_PHONE ANSWER_PHONE_CALLS ADD_VOICEMAIL USE_SIP ACCEPT_HANDOVER (Added in android 9) |
SENSORS (身體傳感器) | BODY_SENSORS |
SMS (短信) | READ_SMS RECEIVE_WAP_PUSH RECEIVE_SMS RECEIVE_MMS SEND_SMS |
STORAGE (存儲(chǔ)空間) | READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE ACCESS_MEDIA_LOCATION (Added in android 10) |
ACTIVITY_RECOGNITION (身體活動(dòng)购公,Added in android 10) | ACTIVITY_RECOGNITION (Added in android 10) |
4萌京、特殊權(quán)限
特殊權(quán)限用于保護(hù)一些特定的應(yīng)用程序操作,Protection Level為appop宏浩,使用前也需要在AndroidManifest.xml中靜態(tài)地聲明知残,也需要動(dòng)態(tài)的申請(qǐng),但是它不同于危險(xiǎn)權(quán)限的申請(qǐng)比庄,危險(xiǎn)權(quán)限的申請(qǐng)會(huì)彈出一個(gè)對(duì)話框詢問(wèn)你是否同意求妹,而特殊權(quán)限的申請(qǐng)需要跳轉(zhuǎn)到指定的設(shè)置界面,讓你手動(dòng)點(diǎn)擊toggle按鈕確認(rèn)是否同意佳窑,截止到android 11制恍,我了解到的常用的5個(gè)特殊權(quán)限為:
- SYSTEM_ALERT_WINDOW:允許應(yīng)用在其他應(yīng)用的頂部繪制懸浮窗,當(dāng)你創(chuàng)建的懸浮窗是TYPE_APPLICATION_OVERLAY類型時(shí)需要申請(qǐng)這個(gè)權(quán)限神凑;
- WRITE_SETTINGS:允許應(yīng)用修改系統(tǒng)設(shè)置净神,當(dāng)你需要修改系統(tǒng)參數(shù)Settings.System時(shí)需要申請(qǐng)?jiān)摍?quán)限,例如修改系統(tǒng)屏幕亮度等溉委;
- REQUEST_INSTALL_PACKAGES: 允許應(yīng)用安裝未知來(lái)源應(yīng)用鹃唯,android 8.0以后當(dāng)你在應(yīng)用中安裝第三方應(yīng)用時(shí)需要申請(qǐng)這個(gè)權(quán)限,否則不會(huì)跳轉(zhuǎn)到安裝界面薛躬;
- PACKAGE_USAGE_STATS:允許應(yīng)用收集其他應(yīng)用的使用信息,當(dāng)你使用UsageStatsManager相關(guān)Api獲取其他應(yīng)用的信息時(shí)需要申請(qǐng)這個(gè)權(quán)限呆细;
- MANAGE_EXTERNAL_STORAGE(Added in android 11):允許應(yīng)用訪問(wèn)作用域存儲(chǔ)(scoped storage)中的外部存儲(chǔ)型宝,android 11以后強(qiáng)制新安裝的應(yīng)用使用作用域存儲(chǔ),但是對(duì)于文件管理器這一類的應(yīng)用它們需要管理整個(gè)SD卡上的文件絮爷,所以針對(duì)這些特殊應(yīng)用可以申請(qǐng)這個(gè)權(quán)限來(lái)獲得對(duì)整個(gè)SD卡的讀寫權(quán)限趴酣,當(dāng)應(yīng)用授予這個(gè)權(quán)限后,它就可以訪問(wèn)文件的真實(shí)路徑坑夯,注意這個(gè)權(quán)限是很危險(xiǎn)的岖寞,聲明這個(gè)權(quán)限上架應(yīng)用時(shí)可能需要進(jìn)行審核.
除了特殊權(quán)限,LOCATION權(quán)限組中的位置權(quán)限也有點(diǎn)特殊柜蜈,需要注意一下仗谆,位置信息的獲取不僅依賴位置權(quán)限的動(dòng)態(tài)申請(qǐng)還依賴系統(tǒng)定位開(kāi)關(guān)指巡,如果你沒(méi)有打開(kāi)定位開(kāi)關(guān)就申請(qǐng)了位置權(quán)限,那么就算用戶同意授權(quán)位置權(quán)限隶垮,應(yīng)用通過(guò)Location相關(guān)Api也無(wú)法獲取到位置信息藻雪,所以申請(qǐng)位置權(quán)限前,最好先通過(guò)LocationManager#isProviderEnabled方法判斷是否打開(kāi)定位開(kāi)關(guān)后再進(jìn)行位置權(quán)限的申請(qǐng)狸吞,如果沒(méi)有打開(kāi)定位開(kāi)關(guān)需要先跳轉(zhuǎn)到設(shè)置界面打開(kāi)定位開(kāi)關(guān)勉耀,偽代碼如下:
val locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) or locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
//請(qǐng)求位置權(quán)限
} else {
//跳轉(zhuǎn)到開(kāi)啟定位的地方
Toast.makeText(this, "檢測(cè)到未開(kāi)啟定位服務(wù),請(qǐng)開(kāi)啟", Toast.LENGTH_SHORT).show()
val intent = Intent().apply {
action = Settings.ACTION_LOCATION_SOURCE_SETTINGS
}
startActivityForResult(intent, REQUEST_CODE_LOCATION_PROVIDER)
}
當(dāng)然,上面危險(xiǎn)權(quán)限和特殊權(quán)限的判斷與申請(qǐng)蹋偏,PermissionHelper都已經(jīng)替你做好了封裝便斥,你只需要像平常一樣在AndroidManifest.xml中靜態(tài)地聲明權(quán)限,然后在代碼中動(dòng)態(tài)地申請(qǐng)就行威始,下面我把危險(xiǎn)權(quán)限和特殊權(quán)限都統(tǒng)稱為動(dòng)態(tài)權(quán)限枢纠,因?yàn)樗鼈兌际切枰獎(jiǎng)討B(tài)申請(qǐng)的。
動(dòng)態(tài)權(quán)限申請(qǐng)?jiān)O(shè)計(jì)
動(dòng)態(tài)權(quán)限的申請(qǐng)依據(jù)不同的android版本和應(yīng)用targetSdkVersion有著不同的行為字逗,主要有兩種處理京郑,如下:
- android版本 <= 5.1 或者 應(yīng)用的targetSdkVersion <= 22:當(dāng)用戶同意安裝應(yīng)用時(shí),系統(tǒng)會(huì)要求用戶授權(quán)應(yīng)用聲明的所有權(quán)限葫掉,包括動(dòng)態(tài)權(quán)限些举,如果用戶不同意授權(quán),只能拒絕安裝應(yīng)用俭厚,如果用戶同意全部授權(quán)户魏,他們撤銷權(quán)限的唯一方式就是卸載應(yīng)用;
- android版本 >= 6.0 且 應(yīng)用的targetSdkVersion >= 23:當(dāng)用戶同意安裝應(yīng)用時(shí)挪挤,系統(tǒng)不再?gòu)?qiáng)制用戶必須授權(quán)動(dòng)態(tài)權(quán)限叼丑,系統(tǒng)只會(huì)授權(quán)應(yīng)用除動(dòng)態(tài)權(quán)限之外的普通權(quán)限,而動(dòng)態(tài)權(quán)限需要應(yīng)用使用到相關(guān)功能時(shí)才動(dòng)態(tài)申請(qǐng)扛门,當(dāng)申請(qǐng)動(dòng)態(tài)權(quán)限時(shí)鸠信,用戶可以選擇授權(quán)或拒絕每項(xiàng)權(quán)限,即使用戶同意授權(quán)權(quán)限论寨,用戶也可以隨時(shí)進(jìn)入應(yīng)用的“Settings”中調(diào)整應(yīng)用的動(dòng)態(tài)權(quán)限授權(quán)星立,所以你每次使用到該權(quán)限的功能時(shí),都要?jiǎng)討B(tài)申請(qǐng),因?yàn)橛脩粲锌赡茉凇癝ettings”界面中把它再次關(guān)閉掉.
在android版本 <= 5.1 或者 應(yīng)用的targetSdkVersion <= 22時(shí),系統(tǒng)使用的是AppOps來(lái)進(jìn)行權(quán)限管理嘶朱,這是android在4.4推出的一套應(yīng)用程序操作權(quán)限管理咧七,AppOps所管理的是所有可能涉及用戶隱私和安全的操作,例如access notification、keep weak lock、display toast 等等吟逝,而運(yùn)行時(shí)權(quán)限管理是android 6.0才出現(xiàn)占业,是基于AppOps的實(shí)現(xiàn)绒怨,進(jìn)一步做了動(dòng)態(tài)請(qǐng)求封裝和明確的規(guī)范,同時(shí)當(dāng)targetSdkVersion <= 22的應(yīng)用運(yùn)行在 >= 6.0的android系統(tǒng)上時(shí)纺酸,動(dòng)態(tài)權(quán)限可以在“Settings”界面中關(guān)閉窖逗,應(yīng)用運(yùn)行過(guò)程中使用到相關(guān)功能時(shí)就會(huì)由于沒(méi)有權(quán)限而出現(xiàn)崩潰,這時(shí)只能使用AppOps的 checkOp方法來(lái)檢測(cè)對(duì)應(yīng)的權(quán)限是否已經(jīng)授權(quán)餐蔬,沒(méi)有權(quán)限就跳轉(zhuǎn)到“Settings”界面碎紊,考慮到目前android 6.0已經(jīng)推出了很久,應(yīng)用商店也不允許targetSdkVersion < 23的應(yīng)用上架樊诺,所以為了減少框架的復(fù)雜度仗考,動(dòng)態(tài)權(quán)限申請(qǐng)?jiān)O(shè)計(jì)就沒(méi)有考慮兼容AppOps的權(quán)限管理操作,所以當(dāng)你使用PermissionHelper時(shí)應(yīng)用的targetSdkVersion要 >= 23词爬。
PermissionHelper支持危險(xiǎn)權(quán)限和特殊權(quán)限的申請(qǐng)秃嗜,只需要一行代碼就可以發(fā)起權(quán)限請(qǐng)求,具有生命周期感應(yīng)能力顿膨,只在界面可見(jiàn)時(shí)才發(fā)起請(qǐng)求和回調(diào)結(jié)果锅锨,同時(shí)當(dāng)系統(tǒng)配置更改例如屏幕旋轉(zhuǎn)后能夠恢復(fù)之前權(quán)限申請(qǐng)流程,不會(huì)中斷權(quán)限申請(qǐng)流程恋沃,靈活性高必搞,可以設(shè)置請(qǐng)求前、拒絕后回調(diào)囊咏,在回調(diào)發(fā)生時(shí)暫停權(quán)限申請(qǐng)流程恕洲,然后根據(jù)用戶意愿再?zèng)Q定是否繼續(xù)權(quán)限申請(qǐng)流程,整個(gè)申請(qǐng)過(guò)程如圖:
PermissionHelper可以通過(guò)設(shè)置回調(diào)在權(quán)限申請(qǐng)開(kāi)始前和權(quán)限被拒絕后把要請(qǐng)求的權(quán)限和被拒絕的權(quán)限回調(diào)出去梅割,在回調(diào)中你可以通過(guò)彈窗向用戶解釋要申請(qǐng)的權(quán)限對(duì)應(yīng)用的必要性霜第,引導(dǎo)用戶繼續(xù)授權(quán)或再次授權(quán),PermissionHelper不定制彈窗UI户辞,彈窗的UI由開(kāi)發(fā)者自定義泌类,開(kāi)發(fā)者只需要在用戶同意或拒絕后調(diào)用回調(diào)中的Process實(shí)例的相應(yīng)方法就能讓被暫停的權(quán)限申請(qǐng)流程恢復(fù),然后在最終的結(jié)果回調(diào)中處理結(jié)果就行底燎,整個(gè)過(guò)程都是鏈?zhǔn)降娜姓ィP(guān)于向用戶解釋權(quán)限申請(qǐng)?jiān)虻膹棿埃瑥棿皟?nèi)容建議包含下面的3點(diǎn):
1书蚪、包含需要授權(quán)的權(quán)限列表的描述喇澡;
2迅栅、包含確認(rèn)按鈕殊校,用戶可以點(diǎn)擊確認(rèn)按鈕再次授權(quán)或跳轉(zhuǎn)到”Settings“;
3读存、包含取消按鈕为流,用戶可以點(diǎn)擊取消按鈕放棄授權(quán).
如果用戶不授權(quán)這個(gè)權(quán)限呕屎,就會(huì)導(dǎo)致應(yīng)用無(wú)法繼續(xù)運(yùn)行下去,可以考慮取消第3步的取消按鈕敬察,即無(wú)法取消這個(gè)彈窗秀睛,一定要用戶再次授權(quán)或跳轉(zhuǎn)到”Settings“去授權(quán)。
PermissionHelper整個(gè)框架的設(shè)計(jì)參考了okhttp的攔截器模式莲祸,通過(guò)責(zé)任鏈模式的形式把危險(xiǎn)權(quán)限申請(qǐng)蹂安、特殊權(quán)限申請(qǐng)、申請(qǐng)前處理和申請(qǐng)后處理劃分為一個(gè)個(gè)節(jié)點(diǎn)锐帜,然后通過(guò)Chain串聯(lián)起各個(gè)節(jié)點(diǎn)田盈,每個(gè)節(jié)點(diǎn)只負(fù)責(zé)對(duì)應(yīng)的內(nèi)容,如下:
val originalRequest = Request()
val interceptors = listOf(
StartRequestNode(),
RequestLocationNode(),
RequestNormalNode(),
RequestSpecialNode(),
PostRequestNode(),
FinishRequestNode()
)
DefaultChain(originalRequest, interceptors).process(originalRequest)
通過(guò)這樣的形式PermissionHelper就可以很靈活的控制權(quán)限申請(qǐng)流程缴阎,對(duì)于生命周期感應(yīng)能力的實(shí)現(xiàn)PermissionHelper使用了Lifecycle+LiveData組件允瞧,這兩個(gè)都是官方支持的用于實(shí)現(xiàn)需要響應(yīng)生命周期感應(yīng)的操作,可以編寫更輕量級(jí)和更易于維護(hù)的代碼蛮拔,避免界面銷毀后的內(nèi)存泄漏述暂,對(duì)于系統(tǒng)配置更改后的數(shù)據(jù)恢復(fù)則使用到了ViewModel組件,這是官方支持的用于保存需要在配置更改后恢復(fù)的數(shù)據(jù)建炫,例如一些UI相關(guān)的數(shù)據(jù)畦韭,通過(guò)這三件套 + 責(zé)任鏈模式實(shí)現(xiàn)了一個(gè)簡(jiǎn)單易用的權(quán)限申請(qǐng)框架,更多詳細(xì)使用和實(shí)現(xiàn)細(xì)節(jié)可以查看代碼倉(cāng)庫(kù)踱卵。
權(quán)限申請(qǐng)相關(guān)變更
自android 6.0推出動(dòng)態(tài)權(quán)限申請(qǐng)之后廊驼,有一些申請(qǐng)行為也隨著系統(tǒng)的迭代發(fā)生變化,目的都是更好的保護(hù)用戶的隱私權(quán)惋砂,使得權(quán)限申請(qǐng)對(duì)用戶感知:
android 8.0以后并且應(yīng)用的targetSdkVersion >= 28時(shí)妒挎,應(yīng)用申請(qǐng)某個(gè)危險(xiǎn)權(quán)限授權(quán),用戶同意后西饵,系統(tǒng)不再錯(cuò)誤地把該危險(xiǎn)權(quán)限對(duì)應(yīng)的權(quán)限組中的其他在AndroidManifest.xml中注冊(cè)的權(quán)限一并授予給應(yīng)用酝掩,系統(tǒng)只會(huì)授予應(yīng)用明確請(qǐng)求的權(quán)限,然而眷柔,一旦用戶應(yīng)用同意授權(quán)某個(gè)危險(xiǎn)權(quán)限期虾,則后續(xù)對(duì)該危險(xiǎn)權(quán)限的權(quán)限組中的其他權(quán)限請(qǐng)求都會(huì)被自動(dòng)批準(zhǔn),而不會(huì)提示用戶驯嘱,例如某個(gè)應(yīng)用在AndroidManifest.xml中注冊(cè)READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE權(quán)限镶苞,應(yīng)用申請(qǐng)READ_EXTERNAL_STORAGE權(quán)限并且用戶同意,在android 8.0之前鞠评,系統(tǒng)在用戶同意后還會(huì)一并授予WRITE_EXTERNAL_STORAGE權(quán)限茂蚓,因?yàn)樗蚏EAD_EXTERNAL_STORAGE權(quán)限是同一個(gè)權(quán)限組并且也在AndroidManifest.xml中注冊(cè),但在android 8.0之后并且應(yīng)用的targetSdkVersion >= 28,系統(tǒng)在用戶同意后只會(huì)授予READ_EXTERNAL_STORAGE權(quán)限聋涨,但是如果后來(lái)應(yīng)用又申請(qǐng)WRITE_EXTERNAL_STORAGE權(quán)限晾浴,系統(tǒng)會(huì)立即授予該權(quán)限,而不會(huì)提示用戶牍白,換句話說(shuō)脊凰,如果只申請(qǐng)了外部存儲(chǔ)空間讀取權(quán)限,在低版本下(android < 8.0)對(duì)外部存儲(chǔ)空間使用寫入操作是沒(méi)有問(wèn)題的茂腥,但是在高版本(android >= 8.0 && targetSdkVersion >= 28)下是會(huì)出現(xiàn)問(wèn)題的狸涌,解決方案是將兩個(gè)讀和寫的權(quán)限一起申請(qǐng)。
android 9.0增加了CALL_LOG(通話記錄)權(quán)限組最岗,并把READ_CALL_LOG杈抢、WRITE_CALL_LOG]、PROCESS_OUTGOING_CALLS權(quán)限從PHONE(電話)權(quán)限組移動(dòng)到了CALL_LOG權(quán)限組仑性,CALL_LOG權(quán)限組使得用戶能夠更好地控制需要訪問(wèn)電話通話記錄敏感信息的應(yīng)用程序惶楼,例如讀取通話記錄和識(shí)別電話號(hào)碼。
android 10引入了很多隱私變更诊杆,新增了ACTIVITY_RECOGNITION(身體活動(dòng))權(quán)限和權(quán)限組歼捐,允許應(yīng)用檢測(cè)用戶的步數(shù)或分類用戶的身體活動(dòng)如步行、騎自行車等晨汹;同時(shí)android 10引入了作用域存儲(chǔ)豹储,當(dāng)應(yīng)用啟用作用域存儲(chǔ)時(shí),WRITE_EXTERNAL_STORAGE權(quán)限會(huì)失效淘这,應(yīng)用對(duì)WRITE_EXTERNAL_STORAGE權(quán)限的申請(qǐng)不會(huì)對(duì)應(yīng)用的存儲(chǔ)訪問(wèn)權(quán)限產(chǎn)生任何影響剥扣,并且WRITE_EXTERNAL_STORAGE會(huì)在未來(lái)被廢棄,因?yàn)樽饔糜虼鎯?chǔ)的目的就是不讓應(yīng)用隨意的修改應(yīng)用沙盒外的外部存儲(chǔ)铝穷;同時(shí)新增了ACCESS_BACKGROUND_LOCATION權(quán)限钠怯,歸屬于LOCATION權(quán)限組,用于后臺(tái)運(yùn)行的應(yīng)用訪問(wèn)用戶定位時(shí)申請(qǐng)曙聂,與ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION這些前臺(tái)定位權(quán)限區(qū)分開(kāi)晦炊,當(dāng)你的應(yīng)用targetSdkVersion >= 29并且運(yùn)行在android 10以上時(shí),應(yīng)用在后臺(tái)訪問(wèn)定位時(shí)需要?jiǎng)討B(tài)的申請(qǐng)后臺(tái)定位權(quán)限宁脊,當(dāng)你把后臺(tái)定位權(quán)限和前臺(tái)定位權(quán)限一起申請(qǐng)時(shí)断国,彈窗授權(quán)框會(huì)有2個(gè)允許選項(xiàng):始終允許
和僅在應(yīng)用使用過(guò)程中允許
,點(diǎn)擊始終允許
表示同時(shí)授權(quán)后臺(tái)定位權(quán)限和前臺(tái)定位權(quán)限榆苞,點(diǎn)擊僅在應(yīng)用使用過(guò)程中允許
表示僅授權(quán)前臺(tái)定位權(quán)限稳衬,然后下次再次申請(qǐng)時(shí)只會(huì)單獨(dú)申請(qǐng)后臺(tái)定位權(quán)限,并且也會(huì)有2個(gè)允許選項(xiàng)坐漏,并且要點(diǎn)擊始終允許
才會(huì)讓后臺(tái)定位權(quán)限申請(qǐng)通過(guò)薄疚,當(dāng)你的應(yīng)用targetSdkVersion < 29運(yùn)行在android 10以上時(shí)弄砍,應(yīng)用在申請(qǐng)前臺(tái)定位權(quán)限時(shí)系統(tǒng)會(huì)把后臺(tái)定位權(quán)限一并授予給應(yīng)用;android 10還新增了ACCESS_MEDIA_LOCATION權(quán)限输涕,歸屬于STORAGE (存儲(chǔ)空間) 權(quán)限組,android 10以后慨畸,因?yàn)殡[私問(wèn)題莱坎,默認(rèn)不再提供圖片的地理位置信息,要獲取該信息需要向用戶申請(qǐng)ACCESS_MEDIA_LOCATION權(quán)限寸士,并使用MediaStore.setRequireOriginal()接口更新文件Uri檐什。
android 11也引入了很多隱私變更,android 11強(qiáng)制新安裝的應(yīng)用(targetSdkVersion >= 30)啟用作用域存儲(chǔ)弱卡,新增MANAGE_EXTERNAL_STORAGE用于代替WRITE_EXTERNAL_STORAGE權(quán)限乃正,提供給手機(jī)管家、文件管理器這類需要管理整個(gè)SD卡上的文件的應(yīng)用申請(qǐng)婶博;android 11中當(dāng)用戶開(kāi)啟“安裝未知來(lái)源應(yīng)用”權(quán)限后返回應(yīng)用瓮具,應(yīng)用會(huì)被殺死重啟,該行為與強(qiáng)制分區(qū)存儲(chǔ)有關(guān)凡人;從android 11后名党,如果應(yīng)用對(duì)某個(gè)權(quán)限連續(xù)點(diǎn)擊多次拒絕,那么下一次請(qǐng)求該權(quán)限時(shí)系統(tǒng)會(huì)直接拒絕連授權(quán)彈窗都不會(huì)彈出挠轴,該行為等同于android 11之前勾選了don‘t ask again传睹;android 11后還新增了一次性權(quán)限(One-time permissions)和權(quán)限自動(dòng)重置功能(Permissions auto-reset),這些變更只要你正確的進(jìn)行運(yùn)行時(shí)權(quán)限請(qǐng)求就不需要做額外適配岸晦;同時(shí)android 11后當(dāng)targetSdkVersion < 30的應(yīng)用把后臺(tái)定位權(quán)限和前臺(tái)定位權(quán)限一起申請(qǐng)時(shí)欧啤,彈窗授權(quán)框的允許選項(xiàng)中不再會(huì)顯示始終允許
選項(xiàng),只有本次允許
和僅在應(yīng)用使用過(guò)程中允許
启上,也就說(shuō)點(diǎn)擊允許時(shí)只會(huì)授予你前臺(tái)定位權(quán)限不再默認(rèn)授予你后臺(tái)定位權(quán)限邢隧,而android 11后targetSdkVersion >= 30的應(yīng)用的ACCESS_BACKGROUND_LOCATION權(quán)限需要獨(dú)立申請(qǐng),不能與前臺(tái)權(quán)限一起申請(qǐng)冈在,如果與前臺(tái)權(quán)限一起申請(qǐng)府框,系統(tǒng)會(huì)直接拒絕連授權(quán)彈窗都不會(huì)彈出,系統(tǒng)推薦增量請(qǐng)求權(quán)限讥邻,這樣對(duì)用戶更友好迫靖,同時(shí)用戶必須先同意前臺(tái)權(quán)限后才能進(jìn)入后臺(tái)定位權(quán)限的申請(qǐng)。
可以看到從android 10引入ACCESS_BACKGROUND_LOCATION權(quán)限以來(lái)兴使,后臺(tái)定位權(quán)限的申請(qǐng)一直都非常特殊系宜,它在android 10可以和前臺(tái)定位權(quán)限一起申請(qǐng),而在android 11又不可以一起申請(qǐng)還有先后申請(qǐng)順序发魄,針對(duì)這種特殊情況盹牧,申請(qǐng)后臺(tái)定位權(quán)限時(shí)要做到:
- 1俩垃、先請(qǐng)求前臺(tái)定位權(quán)限,再請(qǐng)求后臺(tái)定位權(quán)限汰寓;
- 2口柳、單獨(dú)請(qǐng)求后臺(tái)定位權(quán)限,不要與其他權(quán)限一同請(qǐng)求.
上面這些PermissionHelper都已經(jīng)做好了處理有滑,申請(qǐng)時(shí)只需要把后臺(tái)定位權(quán)限和前臺(tái)定位權(quán)限一起傳進(jìn)去就行跃闹。
結(jié)語(yǔ)
本文主要讓讓大家對(duì)權(quán)限的申請(qǐng)流程有進(jìn)一步的認(rèn)識(shí),然后可以通過(guò)對(duì)動(dòng)態(tài)權(quán)限的封裝毛好,將檢測(cè)動(dòng)態(tài)權(quán)限望艺,請(qǐng)求動(dòng)態(tài)權(quán)限,權(quán)限設(shè)置跳轉(zhuǎn)肌访,監(jiān)聽(tīng)權(quán)限設(shè)置結(jié)果等處理和業(yè)務(wù)功能隔離開(kāi)來(lái)找默,業(yè)務(wù)以后可以非常快速的接入動(dòng)態(tài)權(quán)限支持吼驶,提高開(kāi)發(fā)效率惩激。
以上就是本文的全部?jī)?nèi)容!
參考資料: