溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android權(quán)限機(jī)制與適配的方法

發(fā)布時(shí)間:2022-03-16 13:42:44 來源:億速云 閱讀:132 作者:iii 欄目:web開發(fā)

本文小編為大家詳細(xì)介紹“Android權(quán)限機(jī)制與適配的方法”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Android權(quán)限機(jī)制與適配的方法”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識(shí)吧。

一、概要

Android M已經(jīng)發(fā)布一段時(shí)間了,市面上很多應(yīng)用都已經(jīng)適配Android M。權(quán)限機(jī)制,作為Android M的一大特性,受到了很多開發(fā)者的關(guān)注。

二、Android權(quán)限機(jī)制

已經(jīng)了解過基本知識(shí)的,建議直接跳到第三點(diǎn)(QQ音樂的權(quán)限適配經(jīng)驗(yàn))。

Android6.0以前,Android的權(quán)限機(jī)制比較簡(jiǎn)單,開發(fā)者在AndroidManifest文件中聲明需要的權(quán)限,APP安裝時(shí),系統(tǒng)提示用戶APP將獲取的權(quán)限,需要用戶同意授權(quán)才能繼續(xù)安裝,從此APP便永久的獲得了授權(quán)。然而,同期的iOS對(duì)于權(quán)限的處理會(huì)更加靈活,權(quán)限的授予并不是在安裝時(shí),而是在APP運(yùn)行時(shí),用戶可以根據(jù)自身的需要,決定是否授予APP某一權(quán)限,同時(shí),用戶也可以很方便回收授予的權(quán)限。顯然,動(dòng)態(tài)權(quán)限管理的機(jī)制,對(duì)于用戶的隱私保護(hù)是更加適用的,Android過于簡(jiǎn)單的權(quán)限機(jī)制也受到了不少人的吐槽。終于,Android6.0也發(fā)布了動(dòng)態(tài)權(quán)限的機(jī)制。

開始適配和如何兼容

APP要適配Android6.0非常簡(jiǎn)單,只需要將targetSdkVersion和compileSdkVersion都升級(jí)到23及以上,同時(shí)加入權(quán)限檢查申請(qǐng)等代碼邏輯即可。這里很多人會(huì)有一些疑惑,如果針對(duì)舊版本的APP在Android6.0機(jī)型上運(yùn)行或者針對(duì)Android6.0適配了的APP在Android6.0以下機(jī)型上運(yùn)行,會(huì)有什么表現(xiàn)呢?是如何兼容的呢?

1、首先,舊版本APP(targetSdkVersion低于23),因?yàn)闆]有適配權(quán)限的申請(qǐng)相關(guān)邏輯,在Android6.0以上機(jī)型運(yùn)行的時(shí)候,仍然采用安裝時(shí)授權(quán)的方案。

2、適配了Android6.0的APP,在低版本Android系統(tǒng)上運(yùn)行的時(shí)候,仍然采用安裝時(shí)授權(quán)的方案,但是開發(fā)者需要注意的是,權(quán)限申請(qǐng)的代碼邏輯只應(yīng)該在Android6.0及以上的機(jī)型被執(zhí)行。

危險(xiǎn)權(quán)限與普通權(quán)限

一開始,聽到要加入權(quán)限判斷和申請(qǐng)代碼邏輯的程序員內(nèi)心可能是崩潰的:正常的一個(gè)有一定規(guī)模的APP,很容易就七七八八的聲明了很多權(quán)限,如果每個(gè)權(quán)限都申請(qǐng)豈不是非常麻煩?

好歹,Google還算比較明智,并不是所有的權(quán)限都需要運(yùn)行時(shí)申請(qǐng)才能使用。Google對(duì)每個(gè)權(quán)限的隱私危害性進(jìn)行了評(píng)估。將權(quán)限分為了兩大類:普通權(quán)限和危險(xiǎn)權(quán)限。舉個(gè)例子,控制手機(jī)震動(dòng)的權(quán)限對(duì)于用戶并沒有什么危害,只要開發(fā)者聲明了這個(gè)權(quán)限,安裝后就可以一直被授權(quán),也不能被回收,但是,像讀取sd卡數(shù)據(jù)這類權(quán)限,很顯然就是危險(xiǎn)權(quán)限了,APP必須向用戶申請(qǐng)這個(gè)權(quán)限。

Google還是很體貼我們開發(fā)者的,為了進(jìn)一步減少開發(fā)的工作量和申請(qǐng)權(quán)限對(duì)用戶的騷擾,對(duì)危險(xiǎn)權(quán)限根據(jù)各自的屬性進(jìn)行了分組。舉個(gè)例子,讀sd卡和寫sd卡,這兩個(gè)權(quán)限通常都是成對(duì)聲明和使用的,因此,它們被分為一組,而且,只要我們獲取了這個(gè)權(quán)限組里面的任意一個(gè)權(quán)限,就可以獲取整個(gè)權(quán)限組的權(quán)限。Google對(duì)于危險(xiǎn)權(quán)限的定義和分組見下圖。

權(quán)限相關(guān)API說明

首先,在動(dòng)態(tài)權(quán)限申請(qǐng)的流程中,開發(fā)者主要關(guān)注流程和API如下:

1、檢查權(quán)限是否授予。

Activity.java

public int checkSelfPermission(permission)

2、申請(qǐng)權(quán)限。

Activity.java    

public final void requestPermissions( new String[permission1,permission2,...], requestCode)

這個(gè)時(shí)候,會(huì)彈出系統(tǒng)授權(quán)彈窗(授權(quán)彈窗是不支持自定義的,原因理所當(dāng)然)。

3、權(quán)限回調(diào)。

用戶在系統(tǒng)彈窗里面選擇后,結(jié)果會(huì)通過Activity的onRequestPermissionsResult方法回調(diào)APP。

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

    //繼續(xù)執(zhí)行邏輯或者提示權(quán)限獲取失敗

}

4、權(quán)限說明。

用戶如果選擇了拒絕,下一次在需要聲明該權(quán)限的時(shí)候,Google建議APP開發(fā)者給予用戶更多的說明,因此提供了下面這個(gè)API,這個(gè)方法返回值在使用過程中會(huì)發(fā)現(xiàn)有點(diǎn)糾結(jié)(具體解析見下面代碼塊說明)。

public boolean shouldShowRequestPermissionRationale(permission)

{

    1、APP沒有申請(qǐng)這個(gè)權(quán)限的話,返回false

    2、用戶拒絕時(shí),勾選了不再提示的話,返回false

    3、用戶拒絕,但是沒有勾選不再提示的話,返回true

    因此如果想在第一次就給用戶提示,需要記錄權(quán)限是否申請(qǐng)過,沒有申請(qǐng)過的話,強(qiáng)制彈窗提示,而不能根據(jù)這個(gè)方法的返回值來。

}

三、QQ音樂的權(quán)限適配經(jīng)驗(yàn)

1、不同權(quán)限,申請(qǐng)的時(shí)機(jī)不同

QQ音樂作為一個(gè)比較復(fù)雜的流媒體應(yīng)用,也需要不少權(quán)限,但是究竟在什么時(shí)候來申請(qǐng)這些權(quán)限就成了適配6.0時(shí)首當(dāng)其沖問題。針對(duì)這個(gè)問題,我們也對(duì)需要的權(quán)限進(jìn)行了思考,大致認(rèn)為申請(qǐng)權(quán)限需要分為兩個(gè)時(shí)機(jī)。

用戶觸發(fā):這個(gè)很好理解,有些和特性相關(guān)的權(quán)限,比如說聽歌識(shí)曲的錄音權(quán)限、自建歌單封面拍照權(quán)限等,這類權(quán)限平時(shí)APP運(yùn)行時(shí)并不需要,那么我們選擇在用戶觸發(fā)或者進(jìn)入該功能的時(shí)候,進(jìn)行授權(quán)受阻邏輯。

應(yīng)用啟動(dòng)時(shí):我們?cè)谑崂淼臅r(shí)候發(fā)現(xiàn),有些權(quán)限(讀取設(shè)備信息,讀寫sd卡等)并不是由用戶或者特性觸發(fā)的,而是網(wǎng)絡(luò)免流,登錄安全,日志系統(tǒng)這些底層邏輯無時(shí)不刻觸發(fā)的。對(duì)于這些權(quán)限,就比較糾結(jié)了。不過回過頭來看,這些權(quán)限通常是開發(fā)者或者APP不能妥協(xié)的權(quán)限,因?yàn)槿绻脩舨皇跈?quán)的話,將會(huì)影響整個(gè)APP的功能和數(shù)據(jù)。所以,我們選擇比較暴力的方式,在應(yīng)用啟動(dòng)的時(shí)候,就受阻。這也是Google建議的一種方式。

但是需要注意的是,一開始就申請(qǐng)授權(quán)也不要冷冰冰地直接拉起系統(tǒng)彈窗授權(quán),建議先用APP自己的彈窗向用戶禮貌地說明為什么需要這幾個(gè)權(quán)限,比如,讀取不到設(shè)備信息無法聯(lián)通免流,無法保證登錄安全,讀取不到SD卡無法播放歌曲等,避免太生硬引起用戶的反感。特別是,因?yàn)楸镜鼗g的原因,Google對(duì)于權(quán)限的彈窗說明很不local,例如我們申請(qǐng)讀取設(shè)備信息的權(quán)限時(shí),系統(tǒng)的彈窗是“電話權(quán)限”,這里很容易引起用戶的誤解,所以,合理的引導(dǎo)和解釋是必不可少的。

2、應(yīng)用啟動(dòng)授權(quán),需要一個(gè)殼

剛剛已經(jīng)說到了,很多隱形的權(quán)限和特性無關(guān)。那么,如果我們直接啟動(dòng)APP,用戶又還沒有授權(quán)的情況下,很多初始化邏輯很容易就因?yàn)闆]有權(quán)限crash了,即使沒有crash,后面也可能會(huì)有或多或少其他的問題。因此,我們需要在這些權(quán)限完全授予前,禁止這些邏輯的執(zhí)行。

做過啟動(dòng)相關(guān)的同學(xué)都知道,攔截一個(gè)APP正常的啟動(dòng)后面再恢復(fù),是很復(fù)雜的一件事情,往往我們需要一個(gè)外殼來把業(yè)務(wù)邏輯的內(nèi)殼隔絕開。就QQ音樂而言,我們很容易的就想到了dex加載的殼,需求也很類似,dex加載也需要優(yōu)先于業(yè)務(wù)來做。順著這個(gè)思路,很自然地,我們就選擇了在dex的殼里面做權(quán)限的受阻邏輯,而且也很快很好的達(dá)到了預(yù)期的效果。相信現(xiàn)在大部分APP都是分dex的了,因此建議按照這個(gè)方式來做,可以節(jié)省很多的工作量。

四、Android權(quán)限機(jī)制“亂象”

這里要說的亂象,其實(shí)是和Android嚴(yán)重的碎片化有一定的關(guān)系。隨著國(guó)產(chǎn)ROM越來越個(gè)性,很多ROM在嘗試建立自己的權(quán)限機(jī)制,有些甚至基于Android5.x就開放了原生的或者開發(fā)了自己的權(quán)限機(jī)制。而面對(duì)這些情況,我們往往能做的非常有限,舉幾個(gè)例子。

1、讀取運(yùn)動(dòng)數(shù)據(jù)權(quán)限

開發(fā)QQ音樂跑步電臺(tái)的過程中發(fā)現(xiàn),在某國(guó)產(chǎn)ROM的一些機(jī)型上會(huì)提示“應(yīng)用讀取運(yùn)動(dòng)數(shù)據(jù)權(quán)限”的系統(tǒng)彈窗。可是,反復(fù)查閱相關(guān)API發(fā)現(xiàn),我們使用的計(jì)步相關(guān)的Sensor并不需要申請(qǐng)什么權(quán)限。可如果用戶選擇了拒絕,即使APP注冊(cè)了Sensor,也收不到系統(tǒng)的回調(diào)。后來聯(lián)系該廠商的相關(guān)人員后,給出的答復(fù)是,第三方APP無法檢查和申請(qǐng)這個(gè)權(quán)限,這個(gè)權(quán)限本身也屬于該廠商ROM自己的權(quán)限機(jī)制。

類似的案例還有一個(gè),就是在某廠商的手機(jī)管家,會(huì)一直提示QQ音樂嘗試讀取應(yīng)用程序列表。其實(shí),我們并沒有讀取應(yīng)用程序列表,只是調(diào)用了PackageManager相關(guān)的一些API,就是觸發(fā)這個(gè)告警。

對(duì)于這類問題,我們懷疑,第三方ROM是在運(yùn)行時(shí)檢測(cè)到了APP調(diào)用了相關(guān)的API后,進(jìn)行權(quán)限阻斷。這里開發(fā)同學(xué)需要注意的是,被阻斷的API不一定會(huì)導(dǎo)致crash,但是可能導(dǎo)致我們獲取不到正確的返回值或者收不到系統(tǒng)的一些消息回調(diào)。

2、無法添加快捷方式

本來<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>聲明后,我們就可以在桌面上創(chuàng)建快捷方式了,而且這個(gè)權(quán)限也不是危險(xiǎn)權(quán)限??墒悄承﹪?guó)產(chǎn)ROM,對(duì)于APP添加快捷方式限制的比較嚴(yán),必須要用戶在設(shè)置里面手動(dòng)允許添加快捷方式后,APP才能最終成功的添加。這種情況,APP也不能知道是否能添加快捷方式,只能默默的添加失敗了。不過好在這里受影響并不是主快捷方式,而且某些功能的快捷方式入口。

3、消失的桌面歌詞,懸浮窗權(quán)限

QQ音樂桌面歌詞采用了向WindowManager里面添加View的方式實(shí)現(xiàn)??墒呛芏鄧?guó)產(chǎn)ROM很早就具備了懸浮窗權(quán)限。一開始,我們將type改為L(zhǎng)ayoutParams.TYPE_TOAST同時(shí)聲明<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>這個(gè)普通權(quán)限,躲避了大多數(shù)系統(tǒng)的問題。可是,2016年底,隨著某ROM系統(tǒng)的升級(jí),這一招也沒用了,大批用戶反饋爆發(fā)。

我們繼續(xù)嘗試檢測(cè)懸浮窗權(quán)限,發(fā)現(xiàn)checkPermission("android.permission.SYSTEM_ALERT_WINDOW")返回的結(jié)果永遠(yuǎn)是true,因此這條路也走不通。

最終,經(jīng)過各種查閱,發(fā)現(xiàn)這個(gè)懸浮窗權(quán)限并不在Android6.0標(biāo)準(zhǔn)的權(quán)限機(jī)制內(nèi),而是AppOpsManager里面已經(jīng)被隱藏了的一個(gè)開關(guān)位,對(duì)應(yīng)于第24個(gè)開關(guān)。需要注意的是,AppOpsManager這個(gè)類很早就有了,但是很多ROM隱藏了checkOp的方法,好在最后發(fā)現(xiàn)通過反射仍舊可以調(diào)用這個(gè)方法檢測(cè)權(quán)限是否打開。

AppOpsManager manager = (AppOpsManager) context.getSystemService("appops");

try {

    Object object = invokeMethod(manager, "checkOp", op, Binder.getCallingUid(), getPackageName(context));

    return AppOpsManager.MODE_ALLOWED == (Integer) object;

} catch (Exception e) {

    MLog.e(TAG, "CheckPermission " + e.toString());

}

不過,要打開懸浮窗權(quán)限,不同ROM的路徑還不一樣,有的是在設(shè)置里面,有的是在系統(tǒng)自帶的管家里面,最后我們只能根據(jù)不同的ROM,給予用戶不同的引導(dǎo),終于將反饋量降了下去。

讀到這里,這篇“Android權(quán)限機(jī)制與適配的方法”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI