懂得這些,不再懼怕Android許可權請求
Android的許可權請求是一個坑,開發的時候總是有些害怕Android的許可權請求問題,確切的說應該是怕麻煩,不過這都是在沒了解怎麼“填坑”之前。於是,自己就針對Android的許可權請求問題,在網上查資料進行研究。雖然說網上的資料很多,但是都覺得沒有說到確切的要點,因此寫下這篇文章,對自己做的一些功課進行記錄。
首先,先看下我在Demo上執行的例子:
其次是基本知識的一些介紹:
Android 是一個許可權分隔的作業系統,其中每個應用都有其獨特的系統標識(Linux 使用者 ID 和組 ID)。系統各部分也分隔為不同的標識。Linux 據此將不同的應用以及應用與系統分隔開來。
其他更詳細的安全功能通過“許可權”機制提供,此機制會限制特定程序可以執行的具體操作,並且根據 URI 許可權授權臨時訪問特定的資料段。
本文件介紹應用開發者可以如何使用 Android 提供的安全功能。一般性的 Android 安全性概覽在“Android 開源專案”中提供。
一、安全架構
Android 安全架構的中心設計點是:在預設情況下任何應用都沒有許可權執行對其他應用、作業系統或使用者有不利影響的任何操作。這包括讀取或寫入使用者的私有資料(例如聯絡人或電子郵件)、讀取或寫入其他應用程式的檔案、執行網路訪問、使裝置保持喚醒狀態等。
由於每個 Android 應用都是在程序沙盒中執行,因此應用必須顯式共享資源和資料。它們的方法是宣告需要哪些許可權來獲取基本沙盒未提供的額外功能。應用以靜態方式宣告它們需要的許可權,然後 Android 系統提示使用者同意。
應用沙盒不依賴用於開發應用的技術。特別是,Dalvik VM 不是安全邊界,任何應用都可執行原生程式碼(請參閱 Android NDK)。各類應用 — Java、原生和混合 — 以同樣的方式放在沙盒中,彼此採用相同程度的安全防護。
二、使用許可權
基本 Android 應用預設情況下未關聯許可權,這意味著它無法執行對使用者體驗或裝置上任何資料產生不利影響的任何操作。要利用受保護的裝置功能,必須在應用清單中包含一個或多個 標記。
例如,需要監控傳入的簡訊的應用要指定:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.app.myapp" >
<uses-permission android:name="android.permission.RECEIVE_SMS" />
...
</manifest>
如果您的應用在其清單中列出正常許可權(即,不會對使用者隱私或裝置操作造成很大風險的許可權),系統會自動授予這些許可權。如果您的應用在其清單中列出危險許可權(即,可能影響使用者隱私或裝置正常操作的許可權),系統會要求使用者明確授予這些許可權。Android 發出請求的方式取決於系統版本,而系統版本是應用的目標:
如果裝置執行的是 Android 6.0(API 級別 23)或更高版本,並且應用的 targetSdkVersion 是 23 或更高版本,則應用在執行時向用戶請求許可權。使用者可隨時呼叫許可權,因此應用在每次執行時均需檢查自身是否具備所需的許可權。如需瞭解有關在應用中請求許可權的詳細資訊,請參閱使用系統許可權培訓指南。
如果裝置執行的是 Android 5.1(API 級別 22)或更低版本,並且應用的 targetSdkVersion 是 22 或更低版本,則系統會在使用者安裝應用時要求使用者授予許可權。如果將新許可權新增到更新的應用版本,系統會在使用者更新應用時要求授予該許可權。使用者一旦安裝應用,他們撤銷許可權的唯一方式是解除安裝應用。
通常,許可權失效會導致 SecurityException 被扔回應用。但不能保證每個地方都是這樣。例如,sendBroadcast(Intent) 方法在資料傳遞到每個接收者時會檢查許可權,在方法呼叫返回後,即使許可權失效,您也不會收到異常。但在幾乎所有情況下,許可權失效會記入系統日誌。
Android 系統提供的許可權請參閱 Manifest.permission。此外,任何應用都可定義並實施自己的許可權,因此這不是所有可能許可權的詳盡列表。
可能在程式執行期間的多個位置實施特定許可權:
在呼叫系統時,防止應用執行某些功能。
在啟動 Activity 時,防止應用啟動其他應用的 Activity。
在傳送和接收廣播時,控制誰可以接收您的廣播,誰可以向您傳送廣播。
在訪問和操作內容提供程式時。
繫結至服務或啟動服務。
三、自動許可權調整
隨著時間的推移,平臺中可能會加入新的限制,要想使用特定 API,您的應用可能必須請求之前不需要的許可權。因為現有應用假設可隨意獲取這些 API 應用的訪問許可權,所以 Android 可能會將新的許可權請求應用到應用清單,以免在新平臺版本上中斷應用。Android 將根據為 targetSdkVersion 屬性提供的值決定應用是否需要許可權。如果該值低於在其中新增許可權的版本,則 Android 會新增該許可權。
例如,API 級別 4 中加入了 WRITE_EXTERNAL_STORAGE 許可權,用以限制訪問共享儲存空間。如果您的 targetSdkVersion 為 3 或更低版本,則會向更新 Android 版本裝置上的應用新增此許可權。
注意:如果某許可權自動新增到應用,則即使您的應用可能實際並不需要這些附加許可權,Google Play 上的應用列表也會列出它們。
為避免這種情況,並且刪除您不需要的預設許可權,請始終將 targetSdkVersion 更新至最高版本。可在 Build.VERSION_CODES 文件中檢視各版本新增的許可權。
四、正常許可權和危險許可權
系統許可權分為幾個保護級別。需要了解的兩個最重要保護級別是正常許可權和危險許可權:
正常許可權涵蓋應用需要訪問其沙盒外部資料或資源,但對使用者隱私或其他應用操作風險很小的區域。例如,設定時區的許可權就是正常許可權。如果應用宣告其需要正常許可權,系統會自動向應用授予該許可權。如需當前正常許可權的完整列表,請參閱正常許可權。
危險許可權涵蓋應用需要涉及使用者隱私資訊的資料或資源,或者可能對使用者儲存的資料或其他應用的操作產生影響的區域。例如,能夠讀取使用者的聯絡人屬於危險許可權。如果應用宣告其需要危險許可權,則使用者必須明確嚮應用授予該許可權。
特殊許可權
有許多許可權其行為方式與正常許可權及危險許可權都不同。SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS 特別敏感,因此大多數應用不應該使用它們。如果某應用需要其中一種許可權,必須在清單中宣告該許可權,並且傳送請求使用者授權的 intent。系統將向用戶顯示詳細管理螢幕,以響應該 intent。
許可權組
所有危險的 Android 系統許可權都屬於許可權組。如果裝置執行的是 Android 6.0(API 級別 23),並且應用的 targetSdkVersion 是 23 或更高版本,則當用戶請求危險許可權時系統會發生以下行為:
如果應用請求其清單中列出的危險許可權,而應用目前在許可權組中沒有任何許可權,則系統會向用戶顯示一個對話方塊,描述應用要訪問的許可權組。對話方塊不描述該組內的具體許可權。例如,如果應用請求 READ_CONTACTS 許可權,系統對話方塊只說明該應用需要訪問裝置的聯絡資訊。如果使用者批准,系統將嚮應用授予其請求的許可權。
如果應用請求其清單中列出的危險許可權,而應用在同一許可權組中已有另一項危險許可權,則系統會立即授予該許可權,而無需與使用者進行任何互動。例如,如果某應用已經請求並且被授予了 READ_CONTACTS 許可權,然後它又請求 WRITE_CONTACTS,系統將立即授予該許可權。
任何許可權都可屬於一個許可權組,包括正常許可權和應用定義的許可權。但許可權組僅當權限危險時才影響使用者體驗。可以忽略正常許可權的許可權組。
如果裝置執行的是 Android 5.1(API 級別 22)或更低版本,並且應用的 targetSdkVersion 是 22 或更低版本,則系統會在安裝時要求使用者授予許可權。再次強調,系統只告訴使用者應用需要的許可權組,而不告知具體許可權。
五、所有許可權區分和說明
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.robin.permission">
<!-- PROTECTION_NORMAL 普通許可權+++++++++++++++++++++++++++++++++++++++++++++++++++++++- Start -->
<!-- 允許應用程式訪問額外的位置提供程式命令 -->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<!-- 允許應用程式訪問有關網路的資訊 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- 允許應用程式訪問有關Wi-Fi網路的資訊 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- 允許應用程式連線至已配對的藍芽裝置 -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!-- 允許應用程式發現和配對藍芽裝置 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!-- 允許應用程式廣播粘性意圖。
這些是其資料在完成之後由系統儲存的廣播,使得客戶端可以快速檢索該資料,而不必等待下一個廣播 -->
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<!-- 允許應用更改網路連線狀態 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!-- 允許應用程式進入Wi-Fi多播模式 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<!-- 允許應用程式在不安全的情況下禁用鍵盤鎖 -->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<!-- 允許應用程式展開或摺疊狀態列 -->
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
<!-- 允許應用程式查詢任何包所使用的空間 -->
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>
<!-- 允許應用程式在Launcher中安裝快捷方式 -->
<uses-permission android:name="android.permission.INSTALL_SHORTCUT"/>
<!-- 允許應用程式開啟網路套接字 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 允許應用程式呼叫killBackgroundProcesses(String) -->
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
<!-- 允許應用修改全域性音訊設定 -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<!-- 允許應用程式執行I/O操作在NFC -->
<uses-permission android:name="android.permission.NFC"/>
<!-- 允許應用程式讀取同步設定 -->
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<!-- 允許應用程式讀取同步統計資訊 -->
<uses-permission android:name="android.permission.READ_SYNC_STATS"/>
<!-- 允許應用程式接收系統完成引導後廣播的ACTION_BOOT_COMPLETED。
如果您不請求此許可權,您將不會在當時收到廣播。雖然擁有此許可權沒有任何安全隱患,
但它可能會對使用者體驗產生負面影響,即增加系統啟動所需的時間,並允許應用程式
在使用者不知情的情況下執行應用程式。因此,您必須明確宣告您使用此工具使其對使用者可見。 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- 允許應用更改任務的Z順序 -->
<uses-permission android:name="android.permission.REORDER_TASKS"/>
<!-- 必須持有應用程式的許可權才能使用ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS。
這是一個正常的許可權:請求它的應用程式將始終被授予許可權,使用者無需批准或檢視它。 -->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<!-- 允許應用程式請求安裝軟體包。
指定大於22的API的應用程式必須擁有此許可權才能使用ACTION_INSTALL_PACKAGE。 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<!-- 允許應用程式廣播用於為使用者設定鬧鐘的意圖。 -->
<uses-permission android:name="android.permission.SET_ALARM"/>
<!-- 允許應用程式設定系統時區。 -->
<uses-permission android:name="android.permission.SET_TIME_ZONE"/>
<!-- 允許應用程式設定桌布。 -->
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
<!-- 允許應用程式設定桌布提示。 -->
<uses-permission android:name="android.permission.SET_WALLPAPER_HINTS"/>
<!-- 允許使用裝置的紅外發射器(如果有)。 -->
<uses-permission android:name="android.permission.TRANSMIT_IR"/>
<!-- 不再支援此許可權。。 -->
<uses-permission android:name="android.permission.UNINSTALL_SHORTCUT"/>
<!-- 允許應用使用指紋硬體。 -->
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<!-- 允許訪問振動器。。 -->
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- 允許使用PowerManager WakeLocks防止處理器休眠或螢幕變暗。 -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- 允許應用程式寫入同步設定。 -->
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<!-- PROTECTION_NORMAL 普通許可權++++++++++++++++++++++++++++++++++++++++++++++++++++++++- End -->
<!-- 11111111111111111111 === 我是分割線 === 1111111111111111111111 -->
<!-- 表 1. 危險許可權和許可權組。========================================================= Start -->
<!-- 用於與使用者日曆相關的執行時許可權 -->
<permission-group android:name="android.permission-group.CALENDAR"/>
<!-- 允許應用程式讀取使用者的日曆資料。 -->
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<!-- 允許應用程式寫入使用者的日曆資料。 -->
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<!-- 用於與訪問攝像頭或從裝置捕獲影象/視訊相關聯的許可權。 -->
<permission-group android:name="android.permission-group.CAMERA"/>
<!-- 需要能夠訪問攝像機裝置。這將自動強制所有相機功能的}清單元素。
如果您不需要所有相機功能,或者如果相機不可用則可以正常操作,
則必須根據需要修改清單,以便在不支援所有相機功能的裝置上進行安裝。 -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- 用於與此裝置上的聯絡人和個人資料相關的執行時許可權 -->
<permission-group android:name="android.permission-group.CONTACTS"/>
<!-- Allows an application to read the user's contacts data. -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!-- Allows an application to write the user's contacts data. -->
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<!-- 允許訪問帳戶服務中的帳戶列表。 -->
<!-- 注意:從Android 6.0(API級別23)開始,如果應用程式共享管理帳戶的驗證器的簽名,
則它不需要“GET_ACCOUNTS”許可權來讀取有關該帳戶的資訊。在Android 5.1及更低版本中,
所有應用程式都需要“GET_ACCOUNTS”許可權才能讀取任何帳戶的相關資訊。-->
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!-- 用於允許訪問裝置位置的許可權 -->
<permission-group android:name="android.permission-group.LOCATION"/>
<!-- 允許應用程式訪問精確位置。或者,你可能想access_coarse_location。 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 允許應用程式訪問近似位置。或者,你可能想access_fine_location。 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- 用於與從裝置訪問麥克風音訊相關聯的許可權。
請注意,電話呼叫也會捕獲音訊,但是位於單獨(更可見)許可權組中。 -->
<permission-group android:name="android.permission-group.MICROPHONE"/>
<!-- Allows an application to record audio. -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!-- 用於關聯電話功能的許可權。 -->
<permission-group android:name="android.permission-group.PHONE"/>
<!-- 允許只讀訪問電話狀態,包括裝置的電話號碼,當前蜂窩網路資訊,
任何正在進行的通話的狀態,以及在裝置上註冊的任何PhoneAccount列表 -->
<!-- 注意:如果您的minSdkVersion和targetSdkVersion值都設定為3或更低,
系統會向您的應用程式隱式授予此許可權。如果您不需要此許可權,請確保您的targetSdkVersion為4或更高。-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- 允許應用程式發起電話呼叫,而無需通過撥號器使用者介面讓使用者確認呼叫. -->
<uses-permission android:name="android.permission.CALL_PHONE"/>
<!-- Allows an application to read the user's call log. -->
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<!-- Allows an application to write (but not read) the user's call log data.-->
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<!-- 允許應用程式向系統中新增語音郵件-->
<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>
<!-- Allows an application to use SIP service. 會話發起協議 -->
<uses-permission android:name="android.permission.USE_SIP"/>
<!-- 允許應用程式檢視在撥出呼叫期間撥打的號碼,以及將呼叫重定向到其他號碼或完全中止該呼叫的選項。-->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<!-- 用於與訪問攝像頭或從裝置捕獲影象/視訊相關聯的許可權。 -->
<permission-group android:name="android.permission-group.SENSORS"/>
<!-- 允許應用程式訪問來自感測器的資料,使用者使用這些感測器來測量他/她身體內部發生的情況,例如心率。 -->
<uses-permission android:name="android.permission.BODY_SENSORS"/>
<!-- 用於與使用者的SMS訊息相關的執行時許可權 -->
<permission-group android:name="android.permission-group.SMS"/>
<!-- Allows an application to send SMS messages. -->
<uses-permission android:name="android.permission.SEND_SMS"/>
<!-- Allows an application to receive SMS messages. -->
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<!-- Allows an application to read SMS messages. -->
<uses-permission android:name="android.permission.READ_SMS"/>
<!-- 允許應用程式接收WAP推式訊息。-->
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
<!-- 允許應用程式監視傳入的彩信。-->
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
<!--用於與共享外部儲存相關的執行時許可權。 -->
<permission-group android:name="android.permission-group.STORAGE"/>
<!-- 允許應用程式從外部儲存裝置讀取。 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 允許應用程式寫入外部儲存。-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 表 1. 危險許可權和許可權組。========================================================= End -->
<uses-feature android:name="android.hardware.camera" />
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
Android的所有許可權都在上面的程式碼中,同時我也根據組別進行了分組。Demo中用的是一個開源的框架(見下圖)進行許可權的請求,具體的使用方法大家可以到github上檢視。