本文小編為大家詳細介紹“Android權(quán)限機制與適配的方法”,內(nèi)容詳細,步驟清晰,細節(jié)處理妥當,希望這篇“Android權(quán)限機制與適配的方法”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。
網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、成都小程序開發(fā)、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了郊區(qū)免費建站歡迎大家使用!
一、概要
Android M已經(jīng)發(fā)布一段時間了,市面上很多應(yīng)用都已經(jīng)適配Android M。權(quán)限機制,作為Android M的一大特性,受到了很多開發(fā)者的關(guān)注。
二、Android權(quán)限機制
已經(jīng)了解過基本知識的,建議直接跳到第三點(QQ音樂的權(quán)限適配經(jīng)驗)。
Android6.0以前,Android的權(quán)限機制比較簡單,開發(fā)者在AndroidManifest文件中聲明需要的權(quán)限,APP安裝時,系統(tǒng)提示用戶APP將獲取的權(quán)限,需要用戶同意授權(quán)才能繼續(xù)安裝,從此APP便永久的獲得了授權(quán)。然而,同期的iOS對于權(quán)限的處理會更加靈活,權(quán)限的授予并不是在安裝時,而是在APP運行時,用戶可以根據(jù)自身的需要,決定是否授予APP某一權(quán)限,同時,用戶也可以很方便回收授予的權(quán)限。顯然,動態(tài)權(quán)限管理的機制,對于用戶的隱私保護是更加適用的,Android過于簡單的權(quán)限機制也受到了不少人的吐槽。終于,Android6.0也發(fā)布了動態(tài)權(quán)限的機制。
開始適配和如何兼容
APP要適配Android6.0非常簡單,只需要將targetSdkVersion和compileSdkVersion都升級到23及以上,同時加入權(quán)限檢查申請等代碼邏輯即可。這里很多人會有一些疑惑,如果針對舊版本的APP在Android6.0機型上運行或者針對Android6.0適配了的APP在Android6.0以下機型上運行,會有什么表現(xiàn)呢?是如何兼容的呢?
1、首先,舊版本APP(targetSdkVersion低于23),因為沒有適配權(quán)限的申請相關(guān)邏輯,在Android6.0以上機型運行的時候,仍然采用安裝時授權(quán)的方案。
2、適配了Android6.0的APP,在低版本Android系統(tǒng)上運行的時候,仍然采用安裝時授權(quán)的方案,但是開發(fā)者需要注意的是,權(quán)限申請的代碼邏輯只應(yīng)該在Android6.0及以上的機型被執(zhí)行。
危險權(quán)限與普通權(quán)限
一開始,聽到要加入權(quán)限判斷和申請代碼邏輯的程序員內(nèi)心可能是崩潰的:正常的一個有一定規(guī)模的APP,很容易就七七八八的聲明了很多權(quán)限,如果每個權(quán)限都申請豈不是非常麻煩?
好歹,Google還算比較明智,并不是所有的權(quán)限都需要運行時申請才能使用。Google對每個權(quán)限的隱私危害性進行了評估。將權(quán)限分為了兩大類:普通權(quán)限和危險權(quán)限。舉個例子,控制手機震動的權(quán)限對于用戶并沒有什么危害,只要開發(fā)者聲明了這個權(quán)限,安裝后就可以一直被授權(quán),也不能被回收,但是,像讀取sd卡數(shù)據(jù)這類權(quán)限,很顯然就是危險權(quán)限了,APP必須向用戶申請這個權(quán)限。
Google還是很體貼我們開發(fā)者的,為了進一步減少開發(fā)的工作量和申請權(quán)限對用戶的騷擾,對危險權(quán)限根據(jù)各自的屬性進行了分組。舉個例子,讀sd卡和寫sd卡,這兩個權(quán)限通常都是成對聲明和使用的,因此,它們被分為一組,而且,只要我們獲取了這個權(quán)限組里面的任意一個權(quán)限,就可以獲取整個權(quán)限組的權(quán)限。Google對于危險權(quán)限的定義和分組見下圖。
權(quán)限相關(guān)API說明
首先,在動態(tài)權(quán)限申請的流程中,開發(fā)者主要關(guān)注流程和API如下:
1、檢查權(quán)限是否授予。
Activity.java
public int checkSelfPermission(permission)
2、申請權(quán)限。
Activity.java
public final void requestPermissions( new String[permission1,permission2,...], requestCode)
這個時候,會彈出系統(tǒng)授權(quán)彈窗(授權(quán)彈窗是不支持自定義的,原因理所當然)。
3、權(quán)限回調(diào)。
用戶在系統(tǒng)彈窗里面選擇后,結(jié)果會通過Activity的onRequestPermissionsResult方法回調(diào)APP。
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
//繼續(xù)執(zhí)行邏輯或者提示權(quán)限獲取失敗
}
4、權(quán)限說明。
用戶如果選擇了拒絕,下一次在需要聲明該權(quán)限的時候,Google建議APP開發(fā)者給予用戶更多的說明,因此提供了下面這個API,這個方法返回值在使用過程中會發(fā)現(xiàn)有點糾結(jié)(具體解析見下面代碼塊說明)。
public boolean shouldShowRequestPermissionRationale(permission)
{
1、APP沒有申請這個權(quán)限的話,返回false
2、用戶拒絕時,勾選了不再提示的話,返回false
3、用戶拒絕,但是沒有勾選不再提示的話,返回true
因此如果想在第一次就給用戶提示,需要記錄權(quán)限是否申請過,沒有申請過的話,強制彈窗提示,而不能根據(jù)這個方法的返回值來。
}
三、QQ音樂的權(quán)限適配經(jīng)驗
1、不同權(quán)限,申請的時機不同
QQ音樂作為一個比較復(fù)雜的流媒體應(yīng)用,也需要不少權(quán)限,但是究竟在什么時候來申請這些權(quán)限就成了適配6.0時首當其沖問題。針對這個問題,我們也對需要的權(quán)限進行了思考,大致認為申請權(quán)限需要分為兩個時機。
用戶觸發(fā):這個很好理解,有些和特性相關(guān)的權(quán)限,比如說聽歌識曲的錄音權(quán)限、自建歌單封面拍照權(quán)限等,這類權(quán)限平時APP運行時并不需要,那么我們選擇在用戶觸發(fā)或者進入該功能的時候,進行授權(quán)受阻邏輯。
應(yīng)用啟動時:我們在梳理的時候發(fā)現(xiàn),有些權(quán)限(讀取設(shè)備信息,讀寫sd卡等)并不是由用戶或者特性觸發(fā)的,而是網(wǎng)絡(luò)免流,登錄安全,日志系統(tǒng)這些底層邏輯無時不刻觸發(fā)的。對于這些權(quán)限,就比較糾結(jié)了。不過回過頭來看,這些權(quán)限通常是開發(fā)者或者APP不能妥協(xié)的權(quán)限,因為如果用戶不授權(quán)的話,將會影響整個APP的功能和數(shù)據(jù)。所以,我們選擇比較暴力的方式,在應(yīng)用啟動的時候,就受阻。這也是Google建議的一種方式。
但是需要注意的是,一開始就申請授權(quán)也不要冷冰冰地直接拉起系統(tǒng)彈窗授權(quán),建議先用APP自己的彈窗向用戶禮貌地說明為什么需要這幾個權(quán)限,比如,讀取不到設(shè)備信息無法聯(lián)通免流,無法保證登錄安全,讀取不到SD卡無法播放歌曲等,避免太生硬引起用戶的反感。特別是,因為本地化翻譯的原因,Google對于權(quán)限的彈窗說明很不local,例如我們申請讀取設(shè)備信息的權(quán)限時,系統(tǒng)的彈窗是“電話權(quán)限”,這里很容易引起用戶的誤解,所以,合理的引導(dǎo)和解釋是必不可少的。
2、應(yīng)用啟動授權(quán),需要一個殼
剛剛已經(jīng)說到了,很多隱形的權(quán)限和特性無關(guān)。那么,如果我們直接啟動APP,用戶又還沒有授權(quán)的情況下,很多初始化邏輯很容易就因為沒有權(quán)限crash了,即使沒有crash,后面也可能會有或多或少其他的問題。因此,我們需要在這些權(quán)限完全授予前,禁止這些邏輯的執(zhí)行。
做過啟動相關(guān)的同學(xué)都知道,攔截一個APP正常的啟動后面再恢復(fù),是很復(fù)雜的一件事情,往往我們需要一個外殼來把業(yè)務(wù)邏輯的內(nèi)殼隔絕開。就QQ音樂而言,我們很容易的就想到了dex加載的殼,需求也很類似,dex加載也需要優(yōu)先于業(yè)務(wù)來做。順著這個思路,很自然地,我們就選擇了在dex的殼里面做權(quán)限的受阻邏輯,而且也很快很好的達到了預(yù)期的效果。相信現(xiàn)在大部分APP都是分dex的了,因此建議按照這個方式來做,可以節(jié)省很多的工作量。
四、Android權(quán)限機制“亂象”
這里要說的亂象,其實是和Android嚴重的碎片化有一定的關(guān)系。隨著國產(chǎn)ROM越來越個性,很多ROM在嘗試建立自己的權(quán)限機制,有些甚至基于Android5.x就開放了原生的或者開發(fā)了自己的權(quán)限機制。而面對這些情況,我們往往能做的非常有限,舉幾個例子。
1、讀取運動數(shù)據(jù)權(quán)限
開發(fā)QQ音樂跑步電臺的過程中發(fā)現(xiàn),在某國產(chǎn)ROM的一些機型上會提示“應(yīng)用讀取運動數(shù)據(jù)權(quán)限”的系統(tǒng)彈窗??墒?,反復(fù)查閱相關(guān)API發(fā)現(xiàn),我們使用的計步相關(guān)的Sensor并不需要申請什么權(quán)限??扇绻脩暨x擇了拒絕,即使APP注冊了Sensor,也收不到系統(tǒng)的回調(diào)。后來聯(lián)系該廠商的相關(guān)人員后,給出的答復(fù)是,第三方APP無法檢查和申請這個權(quán)限,這個權(quán)限本身也屬于該廠商ROM自己的權(quán)限機制。
類似的案例還有一個,就是在某廠商的手機管家,會一直提示QQ音樂嘗試讀取應(yīng)用程序列表。其實,我們并沒有讀取應(yīng)用程序列表,只是調(diào)用了PackageManager相關(guān)的一些API,就是觸發(fā)這個告警。
對于這類問題,我們懷疑,第三方ROM是在運行時檢測到了APP調(diào)用了相關(guān)的API后,進行權(quán)限阻斷。這里開發(fā)同學(xué)需要注意的是,被阻斷的API不一定會導(dǎo)致crash,但是可能導(dǎo)致我們獲取不到正確的返回值或者收不到系統(tǒng)的一些消息回調(diào)。
2、無法添加快捷方式
本來
3、消失的桌面歌詞,懸浮窗權(quán)限
QQ音樂桌面歌詞采用了向WindowManager里面添加View的方式實現(xiàn)??墒呛芏鄧a(chǎn)ROM很早就具備了懸浮窗權(quán)限。一開始,我們將type改為LayoutParams.TYPE_TOAST同時聲明
我們繼續(xù)嘗試檢測懸浮窗權(quán)限,發(fā)現(xiàn)checkPermission("android.permission.SYSTEM_ALERT_WINDOW")返回的結(jié)果永遠是true,因此這條路也走不通。
最終,經(jīng)過各種查閱,發(fā)現(xiàn)這個懸浮窗權(quán)限并不在Android6.0標準的權(quán)限機制內(nèi),而是AppOpsManager里面已經(jīng)被隱藏了的一個開關(guān)位,對應(yīng)于第24個開關(guān)。需要注意的是,AppOpsManager這個類很早就有了,但是很多ROM隱藏了checkOp的方法,好在最后發(fā)現(xiàn)通過反射仍舊可以調(diào)用這個方法檢測權(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īng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。