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