Android Runtime Permissions
主題: |
Android Runtime Permissions |
文章簡介: |
簡單的Android Runtime Permissions相關程式範例 |
作者: |
柯杏洳 |
版本/產出日期: |
V1.0/2016.12.07 |
1. 前言
• 本文章用來提供Android開發人員在開發應用程式時,初步了解Android Runtime Permissions的相關程式。
2. 開始前準備
請先自行準備一台Android 6.0以上的手機或模擬器,開好一個Android專案,本文章範例建立於以下版本的環境:
• JDK 8
• Android Studio 2.2.2
3. 關於Runtime Permissions
對於開發者來說,原本Android的 App如果需要權限,只需在App的Manifest檔案定義就好,而對於使用者來說,就是在Google Play按下安裝時,會看到應用程式要求存取的權限(然後為了安裝也只能同意),但是從6.0 (API level 23)開始,Android允許使用者可以在App安裝之後再去開啟或關閉app所獲取的一些權限(Dangerous Permissions,詳見第二個參考連結,這裡權限的開啟跟關閉是針對權限group),也可以說是從這個版本開始,這些權限需要使用者明確的同意才可以提供給App,於是開發時如果要支援6.0以上的手機,就需要加上一些程式碼做權限檢查跟request相關的處理(如果忘了寫程式處理,執行的時候就會有例外,開發者就會記得要加了XD)。
4. 手機上查看方式
這裡以我手邊手機Nexus 5(搭Android 6.0.1)為例,首先打開「設定」的App,點擊「應用程式」選單
↓ |
||
a. 點擊右上角齒輪圖示(往下) |
→ |
可以檢視該應用程式現在取得了哪些權限,點擊權限區塊 |
↓ |
↓ |
|
點擊「應用程式權限」 |
可以變更這應用程式權限的授權狀況 |
|
↓ |
||
在這裡可以查看各個權限已授權多少應用程式、共有多少應用程式request這些權限,再點擊權限項目進去 |
||
↓ |
||
可以變更每個應用程式授權的狀況 |
5. 程式範例
如果正在開發的App使用到一些Dangerous權限(詳見第二個參考連結,常見的例子是要存取聯絡人資料、儲存空間、相機、電話等),除了一樣要在Manifest檔案定義之外,需要加入檢查、request跟request結果處理的部分。
在此以電話為例,我要使用Intent來做打電話的動作,利用Intent.ACTION_CALL這個Action,讓我的App能直接打電話,這需要使用到"android.permission.CALL_PHONE"的權限。(如果是用Intent.ACTION_DIAL叫別的App做打電話的動作,我們的App就不需要用到該權限)
(%1) 在Manifest加入權限宣告
<uses-permission android:name="android.permission.CALL_PHONE" />
(1) 檢查權限是否已獲取
呼叫ContextCompat.checkSelfPermission(),傳入Context與權限字串常數(詳見第三個參考連結)檢查回傳值是否為PERMISSION_GRANTED。
(2) request權限
呼叫ActivityCompat.requestPermissions(),傳入Activity、權限字串陣列(可以一次要求多個權限)與RequestCode(跟startForActivityResult所用的RequestCode作用一樣,可以用來區分這是哪個request)
第一次執行request會出現下圖的對話框
如果按了拒絕,再執行request,會出現如下圖的對話框(多了不要再詢問的CheckBox),如果使用者勾選了不要再詢問,接下來再執行request將不會再顯示對話框(除非使用者有去應用程式設定變更授權狀態)。
如果一次request多個權限,則畫面會像下面兩張圖,左下角多了「目前是第幾個要詢問的權限 / 總共要詢問的權限數量」的字樣(左圖和右圖分別是第一次跟第二次以後出現的樣式,同樣只差在多了不要再詢問CheckBox)。
(3) 處理request權限的結果
為了要知道request的結果,我們得覆寫onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)。(不論使用者按下「允許」、「拒絕」或已不再顯示對話框,結果都將透過onRequestPermissionsResult回來)
(4) 確認是否需要跟使用者解釋需要權限的原因(Optional)
呼叫ActivityCompat.shouldShowRequestPermissionRationale(),傳入Activity與權限字串常數。
官方說法是使用者可能就是不清楚為什麼要用到權限才按下拒絕,有時可能需要幫助使用者了解這個App為什麼需要用到這(些)權限,因此這個方法主要是使用者第一次看到對話框,按下「拒絕」之後,且未勾選不再詢問之前都會回傳true,因為,如果使用者再次按下拒絕且勾選不要再詢問,就沒必要再作解釋。
不過,在實際案例中,如果接下來的操作真的需要這個權限,只要request回來的結果是沒有授權,App都得讓使用者知道這樣功能無法運作,所以我自己覺得沒有一定要呼叫這個方法。
6. 補充
(1) Fragment的權限request
如果是(已經被attach到某個Activity上的)Fragment想要自己request權限並處理request結果,差別在於request的時候,要直接呼叫Fragment本身的requestPermissions(),傳入權限字串陣列與RequestCode,並在Fragment的類別裡覆寫onRequestPermissionsResult()。
• 特別需要注意的是,這裡Fragment的request結果其實會先經過Activity再到Fragment(詳情可以去Android Acitivity裡onRequestPermissionsResult的程式),所以該Activity如果有覆寫onRequestPermissionsResult(),必須執行父類別的方法就可以讓Fragment的onRequestPermissionsResult()收到結果囉!
(2) 導去應用程式設定
萬一使用者真的勾選了不再詢問,且拒絕授權給App,此時呼叫request就不會再跟使用者有互動了,也許可以試著引導使用者去App設定打開權限,目前Android沒有開放直接開啟App權限設定頁的方式,找到的替代方案就是開啟該App的資訊頁(詳見最後一個參考連結)。
(3) Android Studio裡的(IntelliJ)小幫手
現在Android Studio會提示需要在Manifest加權限宣告
按下Quick fix快捷鍵(在MAC目前是alt+Enter)會顯示建議動作
選了動作會自動在Manifest補上宣告
<uses-permission android:name="android.permission.CALL_PHONE" />
也會提示需要呼叫checkSelfPermission檢查是否有權限
按下快捷鍵會顯示建議動作
選了動作會自動幫忙補上基本的判斷邏輯
以上是針對Runtime Permissions的簡單說明,如果有興趣可以看看官網詳細解釋與網路上各種大神的說明。
本文章的範例專案放在此連結:https://github.com/smallblack9/RuntimePermissionsSample
7. 參考來源
• Working with System Permissions | Android Developers https://developer.android.com/training/permissions/index.html
• Normal and Dangerous Permissions (主要有列出Dangerous的權限與其對應的group)
https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
• Manifest.permission (內有權限常數的定義)
https://developer.android.com/reference/android/Manifest.permission.html
• 取通話紀錄的參考程式(stackoverflow)
http://stackoverflow.com/questions/19493360/get-last-call-duration-in-android
• 開啟App設定頁面參考作法
http://stackoverflow.com/questions/32822101/how-to-programmatically-open-the-permission-screen-for-a-specific-app-on-android