自定義權限 permissionandroid
<permission
android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="normal"
android:label="@string/permlab_install_shortcut"
android:description="@string/permdesc_install_shortcut" />shell
聲明的含義以下;瀏覽器
android:label:權限名字,顯示給用戶的,值但是一個 string 數據,例如這裏的「自定義權限」。安全
android:description:比 label 更長的對權限的描述。值是經過 resource 文件中獲取的,不能直接寫 string 值,例如這裏的」@string/test」。app
android:name:權限名字,若是其餘 app 引用該權限須要填寫這個名字。ide
android:protectionLevel:權限級別,分爲 4 個級別:this
○normal:低風險權限,在安裝的時候,系統會自動授予權限給 application。orm
○dangerous:高風險權限,系統不會自動授予權限給 app,在用到的時候,會給用戶提示。xml
○signature:簽名權限,在其餘 app 引用聲明的權限的時候,須要保證兩個 app 的簽名一致。這樣系統就會自動授予權限給第三方 app,而不提示給用戶。對象
○signatureOrSystem:這個權限是引用該權限的 app 須要有和系統一樣的簽名才能授予的權限,通常不推薦使用。
聲明和強制實施權限
要強制執行本身的權限,首先必須使用一個或多個<permission>標籤,在AndroidManifest.xml文件中來聲明它們。
例如,應用程序想要控制誰可以啓動它的一個Activity,就可以用下面的方法來爲這個操做聲明一個權限:
<manifestxmlns:android="http://schemas.android.com/apk/res/android"
package="com.me.app.myapp">
<permissionandroid:name="com.me.app.myapp.permission.DEADLY_ACTIVITY"
android:label="@string/permlab_deadlyActivity"
android:description="@string/permdesc_deadlyActivity"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="dangerous"/>
...
</manifest>
<protectionLevel>屬性是必須的,它告訴系統怎樣把應用程序須要的權限通知給用戶,或者是容許誰擁有這個權限。
<permissionGroup>屬性是可選的,而且只用於幫助系統把相關權限顯示給用戶。一般用標準的系統組來設置這個屬性,固然也可使用本身定義的組(但這不多見)。咱們推薦使用既存的分組,這樣會簡化給用戶的顯示的權限UI。
要注意的時,權限所支持的label和description屬性。它們是可以顯示給用戶的字符串資源,android:label屬性用於權限列表的顯示,android:description屬性用於單一權限的詳細介紹。label屬性值應該是簡短的,用幾個關鍵的單詞來描述被權限保護的功能。description屬性應該是權限的詳細描述,慣例是使用兩句話,第一句話來描述權限的功能,第二句話用來警告用戶,若是應用程序得到了這個權限會帶來的不利影響。
下面是一個申請CALL_PHONE權限的label和description屬性設置的例子:
<stringname="permlab_callPhone">directly call phone numbers</string>
<stringname="permdesc_callPhone">Allows the application to call
phone numbers without your intervention. Malicious applications may
cause unexpected calls on your phone bill. Note that this does not
allow the application to call emergency numbers.</string>
用系統的Settings應用程序和shell命令:adb shell pm list permissions,可以查看系統中當前定義的權限。Settings應用的使用方法是:Settings->Applications,選擇一個應用程序,向下滾動,能夠看到這個應用程序所使用的權限。對於開發者,帶有「-s」選項的adb命令能夠用與用戶查看格式相相似的格式來顯示權限:
$ adb shell pm list permissions -s
AllPermissions:
Network communication: view Wi-Fi state, create Bluetooth connections, full
Internet access, view network state
Your location: access extra location provider commands, fine (GPS) location,
mock location sources for testing, coarse (network-based) location
Services that cost you money: send SMS messages, directly call phone numbers
...
在AndroidManifest.xml中的強制權限
限制訪問系統或應用程序整個組件的高級別權限,可以經過應用程序的AndroidManifest.xml文件來設定。全部這些都要求在被指望的組件上包含android:permission屬性,以及用於控制訪問的命名權限。
Activity的權限(應用於<activity>標籤)限制了誰可以啓動被關聯的Activity。在Context.startActivity()方法和Activity.startActivityForResult()方法執行期間要檢查這個權限,若是調用者沒有要求的權限,那麼就會從調用中拋出一個SecurityException異常。
Service的權限(應用於<service>標籤)限制了誰可以啓動或綁定被關聯的服務。在Context.startService()方法、Context.stopService()方法和Context.bindService()方法執行期間會檢查這個權限,若是調用者沒有要求的權限,那麼就會從調用中拋出一個SecurityException異常。
BroadcastReceiver的權限(應用於<receiver>標籤)限制了誰可以發送廣播通知給關聯的接收器。在Context.sendBroadcast()方法返回後會檢查這個權限,也就是在系統試圖把提交的廣播通知發送給設定的接收器的時候。在因沒有權限而失敗的時候,它不會向調用者拋出一個異常,它只是不發送Intent對象。一樣,給Context.registerReceiver()方法提供的權限,是用來控制誰可以向程序中註冊的接收器發送廣播。另外一種方式是,在調用Context.sendBroadcast()方法時,提供一個權限,來限制那個BroadcastReceiver對象可以接收廣播通知。
ContentProvider的權限(應用於<provider>標籤)限制了誰可以訪問ContentProvider對象中的數據。(內容提供有一套額外的叫作URI權限的重要且易用的安全權限,稍後會介紹。)跟其餘組件不一樣,它有兩個獨立的權限屬性:android:readPermission用於限制誰可以從提供器中讀取數據;android:writePermission用於限制誰可以向提供器中寫入數據。要注意的是,若是提供器受到讀寫權限的保護,只擁有寫權限並不意味着可以從提供器中讀取數據。在首次獲取提供器和執行提供器相關的操做時,會進行權限的檢查(若是沒有權限,就會拋出一個SecurityException異常)。使用ContentResolver.query()方法查詢數據時,要求具備讀權限,使用ContentResolver.insert()方法、ContentResolver.update()方法、ContentResolver.delete()方法編輯數據時,要求具備寫權限。在全部的場景中,若是沒有要求的權限,這個調用就會致使一個SecurityException異常被拋出。
發送廣播時的強制權限
除了強制誰可以把Intent對象發送給一個BroadcastReceiver對象的權限以外,在發送一個廣播通知時,還能夠指定需求權限。經過調用帶有權限字符串的Context.sendBroadcast()方法,能夠要求接收器必需要擁有這個權限,纔可以接受這個廣播通知。
要注意的是,接收器和廣播器都可以要求權限,發生這種狀況時,雙方的權限都必須檢查經過後,才能夠把Intent對象發送給匹配的目標。
其餘強制性權限
在調用Service過程當中,能夠設置更細粒度的權限。這種設置是經過調用Context.checkCallingPermission()方法來完成的。調用時給這個方法傳入所指望的權限字符串,它會返回一個整數,它指明瞭所指望的權限是否被當前調用的進程所接受。要注意的是,這種方法只能在執行來自另外一個進程調用的時候使用。一般經過IDL接口來發布服務,或者是用其餘的方法提供給另外一個進程。
有不少有用的檢查權限的方法。若是有另外一個進程的PID,那麼就可使用Context.checkPermission(String, int, int)方法,針對這個PID來檢查權限。若是有另外一個應用程序的包名,就能夠直接使用包管理器的PackageManager.checkPermission(String, String)方法來找出這個包是否已經被授予了指定的權限。
URI權限
到目前爲止咱們所介紹的標準的權限系統不能知足內容提供器的使用須要。內容提供器可能要保護它本身的讀寫權限,可是爲了某些操做,它的客戶端也須要把指定的URI交給另外一個應用程序來處理。一個典型的示例是Mail應用程序中的附件。郵件的訪問應該是受到權限的保護,由於這個用戶敏感的數據。可是,若是要把一個圖片附件的URI提供給一個Image瀏覽器,那麼這個Image瀏覽器就會因沒有權限而不能打開這個圖片附件。
這個問題的解決方案是給每一個URI都分配一個權限,當啓動一個Activity或給一個Activity返回結果時,調用者可以設置Intent.FLAG_GRANT_READ_URI_PERMISSION和(或)Intent.FLAG_GRANT_WRITE_URI_PERMISSION權限。這樣就給接受Intent對象的Activity授予了訪問Intent對象中指定的數據URI的權限,而無論它是否有權訪問與這個Intent對象對應的內容提供器中的數據權限。
這種機制容許使用一種共同的能力樣式模型,這種模型利用用戶交互(打開一個附件、選擇一個通信錄等)來驅動設定更細粒度的權限。這種機制能夠有效的減小應用程序所須要的權限,只須要那些與它們直接相關行爲權限。
這種把權限細化到URI的作法,須要持有這些URI的內容提供器的配合。強烈推薦內容提供器實現這種機制,而且經過android:grantUriPermissions屬性或<grant-uri-permissiongs>標籤來聲明它們所提供的權限。
更多的信息可以在Context.grantUriPermission()、Context.revokeUriPermission()和Context.checkUriPermission()方法中找到。