Android6.0系統權限那些事
Android6.0帶來了新的權限管理方式,本文主要來源于官方文檔,加入了自己的理解,目的是想總結Android6.0權限管理的新方式,其他部分可能主要是總結式的帶過,后續再詳細分析。
<h3>
<strong><span style="color:#000000;">一.Security Architecture(安全體系結構)</span></strong> </h3>
<p>
<br />
</p>
<p>
<span style="font-size:18px;">Android安全體系結構的核心是:</span> </p>
<p>
<span style="font-size:18px;">默認情況下沒有任何應用有權限去執行對其他應用、操作系統、用戶有不利影響的操作。這是一個核心的設計理念。記住這句話對后面的權限管理可以很好的理解。</span> </p>
<p>
<br />
</p>
<p>
<span style="font-size:18px;">正式由于這樣的設計理念,默認情況下應用不能去讀寫用戶的私有數據(比如Email和Contacts),不能去讀寫其他App的文件,不能執行網絡訪問,不能保持設備始終喚醒等等。</span> </p>
<p>
<br />
</p>
<p>
<span style="font-size:18px;">因為每一個Android 應用都是在一個進程沙盒中運行的,應用必須明確分享的資源和數據,通過申明需要的額外權限這種方式(這些額外權限不由基本沙河提供)。應用靜態的聲明這些權限(在Manifest里面),然后Android系統會請求用戶同意這些權限。</span> </p>
<p>
<br />
</p>
<p>
<span style="font-size:18px;">Android應用沙盒不依賴于創建應用的技術(這句話不是很懂,懂的大神可以指
一下),特別的是Dalvik虛擬機并不是安全邊界的,所有的應用都可以運行native code(比如參見NDK),所有類型的應用-Java,native,hybird,都是以同樣的方式封裝在沙盒內并且相互之間是同樣的安全等級。</span> </p>
<h3>
<strong><span style="color:#000000;">二.Application signing(應用簽名)</span></strong> </h3>
<p>
<br />
</p>
<p>
<span style="font-size:18px;">所有的Apk文件都必須由他的開發者使用私有的簽名證書簽名,這個證書是開發者身份的唯一標識,這個證書是由開發者自己生成的開放式的證書,用于自己簽名應用。證書的目的是標識應用的身份,這樣可以讓系統知道是該允許還是拒絕應用訪問簽名級別的權限(<a href="/misc/goto?guid=4959649282402156441">signature-level permissions</a>),以及允許還是拒絕應用所請求的給予相同Linux身份來作為不同的應用。</span> </p>
<p>
<br />
</p>
<h3>
<strong><span style="color:#000000;">三.User IDs and File Access(用戶ID和文件訪問)</span></strong> </h3>
<p>
<br />
</p>
<p>
<span style="font-size:18px;">在安裝一個app
package的時候,android系統會給每一個package一個獨立的Linux user ID。這個User ID在這個應用在當前設備的生命周期內都是固定不變的,在不同的設備,相同的package的用戶ID可能各不相同,但可以確定的是在一臺設備上一個 package的用戶ID是固定不變的。</span> </p>
因為安全執行是發生在進程層面的,兩個不同的package不能運行在相同的進程中,他們會被作為不同的Linux用戶來運行。
但是你可以在manifest中使用sharedUserId屬性來指定不同的package有相同的User ID,這樣這兩個不同的package將會被視為相同的APP,會有相同的User ID和文件權限。
當然為了保證安全,只有兩個APP簽名一致且申明了相同的sharedUserId才會被給予相同的User ID。
<h3>
<strong><span style="text-decoration:none;color:#000000;">四.Using Permission(使用權限)</span></strong> </h3>
<p>
<br />
</p>
<p>
<span style="font-size:18px;">一個新建的Android應用默認是沒有權限的,這意味著它不能執行任何可能對用戶體驗有不利影響的操作或者訪問設備數據。為了使用受保護的功能,你必須包含一個或者多個<uses-permission>標簽在你的app manifest中。</span> </p>
<p>
<br />
</p>
<p>
<em><strong><span style="font-size:18px;color:#000000;">Android 6.0中權限分為兩種,普通權限和危險權限(即運行時權限,下面統稱運行時權限)。</span></strong></em> </p>
<p>
<strong><span style="font-size:18px;color:#000000;"><br />
</span></strong> </p>
<h4>
<span style="font-size:18px;">4.1普通權限<br />
</span> </h4>
如果你的應用manifest中只申明了普通權限(也就是說,這些權限對于用戶隱私和設備操作不會造成太多危險),系統會自動授予這些權限。
<h4>
<span style="font-size:18px;">4.2運行時權限<br />
</span> </h4>
如果你的應用manifest中聲明了運行時權限(也就是說,這些權限可能會影響用戶隱私和設備的普通操作),系統會明確的讓用戶決定是否授予這些權限。系統請求用戶授予這些權限的方式是由當前應用運行的系統版本來決定的。
<h5>
<span style="font-size:18px;">4.2.1 Android6.0及以上的系統</span> </h5>
<p>
<span style="font-size:18px;">如果你的設備運行的是Android6.0(API level
23)及以上的系統,并且你的應用的targetSdkVersion也是23或者更高,那么應用向用戶請求這些權限是實時的。這意味著用戶可以隨時取消 這些運行時權限的授權。所以應用在每次需要用到這些運行時權限的時候都需要去檢查是否還有這些權限的授權。具體請求方式后面會講到。</span> </p>
<h5>
<span style="font-size:18px;">4.2.2 Android 5.1及以下的系統</span><br />
</h5>
<p>
<span style="font-size:18px;">如果你的設備運行在Android5.1(API level 22)及以下的系統中,或者你的app的targetSdkVersion是22或者更低。系統會請求用戶在apk安裝的時候授予這些權限。</span> </p>
<p>
<span style="font-size:18px;">如果你的應用更新的時候添加了一個權限,系統會在用戶更新應用的時候請求用戶授予這個權限,<span style="font-size:18px;color:#000000;"><strong><em><span style="font-size:18px;">一旦用戶安裝了這個應用,唯一可以取消授權的方式就是卸載掉這個應用。</span></em></strong><strong><em><span style="font-size:18px;">注意這句話的意思,想一下如果app的targetSdkVersion是22或者以下,但是運行在Android6.0及以上的設備中會有什么問題?后面會分析這個問題。</span></em></strong></span></span> </p>
<p>
<span style="font-size:18px;"><br />
</span> </p>
常常來說一個授權失敗會拋出SecurityException,然而這并不是在 所有情況下都會發生。比如,發送一個廣播去檢查授權(SendBroadcast(Intent)),數據會被發送給所有接收者,但是當這個方法的請求返 回的時候,你不會收到任何一個因為授權失敗拋出的異常,其實在大多數情況下,授權失敗只會打印系統日志。
任何應用也可以定義和執行他們自己的權限。
<h4>
<span style="font-size:18px;">4.3自動權限調整</span> </h4>
<p>
<span style="font-size:18px;">簡單的說,如果你的app targetSdkVersion是3,而你當前運行的系統版本是4,那么在android version 4 中新添加的權限會自動添加到你的app中。</span> </p>
<p>
<span style="font-size:18px;">比如</span><span style="text-decoration:none;color:#000000;"><strong><em><span style="text-decoration:none;font-size:18px;"><a href="/misc/goto?guid=4959548338458555507">WRITE_EXTERNAL_STORAGE<span style="text-decoration:none;font-size:18px;">權限是在api 4的時候添加的,而你的應用的targetSdkVersion是3,那么這個權限會自動添加到你的應用中。而且在官方商店上這個權限也會列出來(<span style="text-decoration:none;font-size:18px;">盡管可能你并不需要這個權限</span>)。</span></a></span></em></strong></span> </p>
<p>
<span style="text-decoration:none;color:#000000;"><strong><em><span style="color:#000000;text-decoration:none;font-size:18px;"><a href="/misc/goto?guid=4959548338458555507"><span style="text-decoration:none;font-size:18px;color:#000000;">所以建議經常更新你的targetSdkVersion到最新版本。</span></a></span></em></strong></span> </p>
<p>
<br />
</p>
<p>
<span style="color:#000000;"><strong><em><span style="font-size:18px;">下面來回答上面的那個問題,如果app的targetSdkVersion是22或者以下,但是運行在android 6.0或以上版本的手機中,會發生什么?</span></em></strong></span> </p>
<p>
<br />
</p>
<p>
<span style="font-size:18px;color:#000000;">安裝過程中,會一起請求用戶授予所有
權限,如果用戶拒絕,將不能安裝這個app,只有用戶全部同意這些授權,才能安裝這個應用,但是問題來了,安裝好了這個應用之后,android6.0以 上的系統中,用戶是可以去設置中取消授權的,而且是隨時都可以取消,所以很多運行時權限可能也得不到,目前官方的做法是,如果用戶取消該項授權,那么依賴 該項授權的方法的返回值為null,所以你的app可能會報空指針異常。以后是否會針對22以下的app做改變還不得而知,畢竟crash是很難讓人接受 的,但是crash是由用戶造成的,用戶應該也可以理解。</span> </p>
<h3>
<strong><span style="color:#000000;"><span style="text-decoration:none;">五.普通權限和運行時權限</span></span></strong> </h3>
<p>
<br />
</p>
<p>
<span style="color:#000000;"><strong><em><span style="font-size:18px;">系統權限會被傳遞給兩種不同的保護級別,我們所知道這兩種最重要的保護級別就是普通權限和運行時權限。</span></em></strong></span> </p>
<p>
<span style="color:#000000;"><strong><em><span style="font-size:18px;"><br />
</span></em></strong></span> </p>
<h4>
<span style="font-size:18px;color:#000000;">5.1普通權限</span> </h4>
<p>
<span style="font-size:16px;">普通權限的覆蓋區域是在你的app需要訪問沙盒以外的數據和資源的時候,但是對用戶隱私和其他app的操作只有很少的影響,比如開啟手電筒的權限。這個時候,系統會自動授權這些普通權限。</span> </p>
<h4>
<span style="font-size:16px;"><br />
</span>5.2運行時權限 </h4>
運行時權限的覆蓋區域是你的app想要的數據和資源涉及用戶的隱私信息,或者是可能潛在的影響用戶的存儲數據或者其他app的操作。比如,請求獲取用戶聯系人信息的權限。如果一個app申明了運行時權限,用戶必須明確的授權這些權限給app。
<h4>
<span style="font-size:18px;">5.3權限組</span> </h4>
<h4>
<em><strong>所有的運行時權限都屬于對應的權限組,如果你的app運行在android6.0及以上系統,下面的規則都適用:</strong></em> </h4>
<h5>
<span style="font-size:16px;">5.3.1</span> </h5>
<p>
<span style="font-size:16px;">如果一個app在manifest中請求了一個運行時權限,而且app還沒有得到這個運行時權限所在的權限組中的任何一個運行時權限授權,那么系統會彈出一個對話框,描述app想要訪問的運行時權限的權限組,這個對話框不會描述這個權限組中某一個特定的權限。</span> </p>
<p>
<span style="font-size:16px;">比如,你的app想要請求READ_CONTACT權限,對話框只會描述app想要請求設備的聯系人,如果用戶授權通過,系統會授予app所請求的該項權限。</span> </p>
<h5>
<span style="font-size:16px;">5.3.2</span> </h5>
<p>
<span style="font-size:16px;">如果一個app在manifest中請求一個運行時權限,并且這個app已經在相同的權限組中有了另一個運行時權限的授權,那么系統不會彈出對話框,而是會立即授予app該項運行時權限的授權。</span> </p>
<p>
<span style="font-size:16px;">比如,一個app之前請求過一個READ_CONTACT的權限并且被授權通過,之后又請求一個WRITE_CONTACT(在同一個權限組)權限,那么系統會自動授予該權限。</span> </p>
<p>
<br />
</p>
<p>
<strong><em>其實所有權限(普通權限、運行時權限、用戶自定義權限)都屬于特定的權限組,但是只有運行時權限的權限組才會影響用戶體驗。</em></strong> </p>
<p>
<br />
</p>
<h5>
<span style="font-size:16px;">5.3.3運行時權限和權限組列表</span> </h5>
<table class="ke-zeroborder">
<tbody>
<tr>
<th>
Permission Group
</th>
<th>
Permissions
</th>
</tr>
<tr>
<td>
<strong><em><a href="/misc/goto?guid=4959649282530521942"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">CALENDAR</span></a></em></strong> </td>
<td>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649282613010475"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">READ_CALENDAR</span></a></em></strong> </p>
</li>
</ul>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649282699688792"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">WRITE_CALENDAR</span></a></em></strong> </p>
</li>
</ul>
</td>
</tr>
<tr>
<td>
<strong><em><a href="/misc/goto?guid=4959649282785053990"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">CAMERA</span></a></em></strong> </td>
<td>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649282863647584"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">CAMERA</span></a></em></strong> </p>
</li>
</ul>
</td>
</tr>
<tr>
<td>
<strong><em><a href="/misc/goto?guid=4959649282951012393"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">CONTACTS</span></a></em></strong> </td>
<td>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649283032651904"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">READ_CONTACTS</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649283120549831"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">WRITE_CONTACTS</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649283194944335"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">GET_ACCOUNTS</span></a></em></strong> </p>
</li>
</ul>
</td>
</tr>
<tr>
<td>
<strong><em><a href="/misc/goto?guid=4959649283274762832"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">LOCATION</span></a></em></strong> </td>
<td>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959548338618551688"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">ACCESS_FINE_LOCATION</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959548338535822597"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">ACCESS_COARSE_LOCATION</span></a></em></strong> </p>
</li>
</ul>
</td>
</tr>
<tr>
<td>
<strong><em><a href="/misc/goto?guid=4959649283426427669"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">MICROPHONE</span></a></em></strong> </td>
<td>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649283513036254"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">RECORD_AUDIO</span></a></em></strong> </p>
</li>
</ul>
</td>
</tr>
<tr>
<td>
<strong><em><a href="/misc/goto?guid=4959649283598349390"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">PHONE</span></a></em></strong> </td>
<td>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649283678185879"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">READ_PHONE_STATE</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649283753365969"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">CALL_PHONE</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649283837620435"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">READ_CALL_LOG</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649283933903287"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">WRITE_CALL_LOG</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649284011225898"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">ADD_VOICEMAIL</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649284096343127"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">USE_SIP</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649284181686413"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">PROCESS_OUTGOING_CALLS</span></a></em></strong> </p>
</li>
</ul>
</td>
</tr>
<tr>
<td>
<strong><em><a href="/misc/goto?guid=4959649284266125952"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">SENSORS</span></a></em></strong> </td>
<td>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649284353274182"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">BODY_SENSORS</span></a></em></strong> </p>
</li>
</ul>
</td>
</tr>
<tr>
<td>
<strong><em><a href="/misc/goto?guid=4959649284438665493"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">SMS</span></a></em></strong> </td>
<td>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649284519957308"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">SEND_SMS</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649284606039175"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">RECEIVE_SMS</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649284681149977"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">READ_SMS</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649284763076169"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">RECEIVE_WAP_PUSH</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649284846980287"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">RECEIVE_MMS</span></a></em></strong> </p>
</li>
</ul>
</td>
</tr>
<tr>
<td>
<strong><em><a href="/misc/goto?guid=4959649284932231730"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">STORAGE</span></a></em><em><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;"> </span></em></strong> </td>
<td>
<ul>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959649285019455116"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">READ_EXTERNAL_STORAGE</span></a></em></strong> </p>
</li>
<li>
<p>
<strong><em><a href="/misc/goto?guid=4959548338458555507"><span style="color:#000000;font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">WRITE_EXTERNAL_STORAGE</span></a></em></strong> </p>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>
<br />
</p>
<p>
<span style="font-size:16px;">有兩個權限比較特殊,分別是<span style="font-size:16px;color:#000000;"><strong><em><a href="/misc/goto?guid=4959649285116419894"><span style="font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">SYSTEM_ALERT_WINDOW</span></a></em></strong><strong><em><span style="font-size:16px;font-family:微軟雅黑,Microsoft YaHei;"> 和 </span></em></strong><strong><em><a href="/misc/goto?guid=4959649285201916105"><span style="font-size:16px;font-family:微軟雅黑,Microsoft YaHei;">WRITE_SETTINGS</span></a></em></strong></span></span> </p>
<p>
<span style="font-size:16px;">都屬于比較敏感的權限,很多時候都永不到,如果需要這個權限,應該首先聲明,然后發送Intent去請求用戶授權,然后系統會顯示詳細的管理界面。</span> </p>
<p>
<br />
</p>
<h5>
<span style="font-size:20px;color:#953734;"><em><strong>5.3.4運行時權限的申請</strong></em></span> </h5>
<p>
<span style="font-size:18px;">第一.判斷</span> </p>
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
第二.如果是android6.0以上的系統,則檢查是否獲取授權
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);
如果返回值為PackageManager.PERMISSION_GRANTED,則可以繼續之后的操作,如果返回值為PERMISSION_DENIED,則代表沒有授權該權限。
第三.shouldShowRequestPermissionRationale()可以得到是否需要彈出一個解釋申請該權限的提示給用戶,如果為true,則可以彈。
第四.請求該權限
示例如下:
// Here, thisActivity is the current activity if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {// Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) { // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an // app-defined int constant. The callback method gets the // result of the request. }
} else { 執行獲取權限后的操作 }</pre>
第五.請求權限之后,在onRequestPermissionsResult()返回值中可以得到用戶是否授權,如果授權,就可以操作該運行時權限對應的方法
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {// permission was granted, yay! Do the // contacts-related task you need to do. } else { // permission denied, boo! Disable the // functionality that depends on this permission. } return; } // other 'case' lines to check for other // permissions this app might request }
}</pre>
運行時權限的特點是,實時性,用戶可以隨時取消授權,所以每次調用運行時權限的方法都需要判斷或者請求一次運行時權限。
在執行運行時權限申請的同時想一下是否真的有必要,想一下使用Intent的方式啟動其他應用是否可以達到需求,比如ACTION_IMAGE_CAPTURE,是直接申明CAMERA的權限自己做一個照相機還是發送ACTION_IMAGE_CAPTURE請求讓別的應用處理并在onActivityResult()返回值更方便
如果設備運行在5.1或者以下的設備,或者targetSdkVersion在22或以下,系統會在安裝app的時候讓用戶授權權限。再說一遍,系統只會提示用戶app需要的權限組,而不會提示某一個特定的權限。
<h3> <strong><span style="text-decoration:none;color:#000000;">六.自定義權限</span></strong> </h3> <p> <br /> </p> <p> <span style="font-size:16px;">為了執行自定義權限,你必須在你的manifest中聲明一個或多個<permission>標簽。</span> </p> <p> <span style="font-size:16px;">比如:</span> </p> <p> </p>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.me.app.myapp" > <permission android: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>屬性是必須的,告訴系統當app申請該權限的時候,要怎樣通知用戶。
<permissionGroup>屬性是可選的,可以幫助系統顯示自定義屬性屬于哪個權限組,當通知用戶彈出框的時候,當然你可以選擇某一個自定義權限屬于已知的權限組,也可以屬于某一個自定義權限組,建議屬于已知的權限組。
<android:label>相當于權限組的提示,要簡短
<android:description>是某一個特定權限的描述,規則是兩句話,第一句描述,第二句警告用戶如果授權會發生什么后果。
比如,CALL_PHONE權限
<string name="permlab_callPhone">directly call phone numbers</string> <string name="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>之后,你會在setting—>Application中看到該自定義權限。
</div> 來自:http://my.oschina.net/u/990728/blog/546319