Android 6.0的Permission權限設計

作者 | 2016-05-15

Android 6.0(API Level 23)開始,應用程式的權限有新的機制,API 23開始,權限分為兩大類型,一般權限(Normal Permission)與危險權限(Dangerous Permission)。

Android 6.0的Permission權限

Android 6.0(API Level 23)開始,應用程式的權限有新的機制,在API 23之前(Android 4.x、5.x)應用程式在安裝時會要求所有會使用到的權限,如INTERNET網路連線、READ_CONTACT讀取聯絡人資料或是WRITE_EXTERNAL_STORAGE寫入外部儲存裝置(如SD Card)等,在API 23開始,權限分為兩大類型,一般權限(Normal Permission)與危險權限(Dangerous Permission)。

當應用程式在開發時,其「targetSdkVersion」目標開發版本設定為23或以上時,且在Android 6.0以上的手機環境執行時,對於權限相關的運作方式說明如下。

一般權限與危險權限

這兩種權限同樣都要在AndroidManifest.xml中使用<uses-permission>宣告,不同的是,危險權限除此之外,在執行應用程式時,如果程式碼中存取了危險權限,還會出現請求權限的對話框,要求使用者允許存取資料,下圖是存取危險權限之一的拍照權限出現的對話框:

A4506

危險權限依照功能分為以下幾個組別:

序號群組項目說明
1CALENDAR日曆READ_CALENDAR讀取日曆
WRITE_CALENDAR寫入日曆
2CAMERACAMERA相機拍照功能
3CONTACTS聯絡人READ_CONTACTS讀取聯絡人
WRITE_CONTACTS寫入聯絡人
GET_ACCOUNTS取得手機帳號
4LOCATION位置ACCESS_FINE_LOCATION取得精確位置
ACCESS_COARSE_LOCATION取得大約位置
5MICROPHONE麥克風RECORD_AUDIO錄製聲音
6PHONE電話READ_PHONE_STATE讀取通話狀態
CALL_PHONE撥出電話
READ_CALL_LOG讀取通話記錄
WRITE_CALL_LOG寫入通話記錄
ADD_VOICEMAIL新增語音留言
USE_SIP使用SIP網路電話
PROCESS_OUTGOING_CALLS存取撥出電話
7SENSORS感應器BODY_SENSORS讀取體感資料
8SMS簡訊SEND_SMS傳送簡訊
RECEIVE_SMS接收簡訊
READ_SMS讀取簡訊
RECEIVE_WAP_PUSH接收WAP推播訊息
RECEIVE_MMS接收多媒體簡訊
9STORAGE儲存READ_EXTERNAL_STORAGE讀取外部儲存
WRITE_EXTERNAL_STORAGE寫入外部儲存

危險權限若在執行過程獲得使用者授權其中一種權限後,便自動取得該群組內的所有權限,例如使用者允許第3組中的READ_CONTACTS後,應用程式也一併取得CONTACTS群組內的WRITE_CONTACTS權限。

這些權限值全都定義在android.Manifest.permission中,使用時可以在類別中以import語法導入:

在類別內以下列方式取得權限值(以字串定義):

或是直接import static,如下:

即可在類別中直接使用permission內定義的所有權限常數,如下圖:

A4508

執行中要求權限

權限檢查是Android 6.0(API 23)後才有的,請確認「app模組」的build.gradle內宣告的complieSdkVersion為23以上,且targetSdkVersion亦為23以上,如下:

程式中使用由「Support v4」類別庫所提供的「ActivityCompat」類別,import語法如下:

首先,在程式中若想存取屬於危險權限的資源之前,需先檢查是否已經取得使用者的授權,檢查權限語法:

  • 已擁有權限-PERMISSION_GRANTED

代表應用程式目前已獲得使用者允許使用該權限。

  • 無權限-PERMISSION_DENIED

應用程式目前無該權限。

接下來應設計程式判斷回傳的狀態值,並設計擁有與無權限的程式碼,程式片段如下:

向使用者請求權限

ActivityCompat類別亦提供向使用者請求權限的類別方法「requestPermissions」,方法的規格如下:

第一個參數傳入Context物件,第二個字串陣列則是欲要求的權限,第三個int是本次請求的辨識編號,當使用者決定後返回onRequestPermissionsResult方法時的辨認號碼,因此,應在類別中定義符合其功能的常數名稱,以提高程式可讀性,例如請求外部儲存時,常數名稱為「REQUEST_EXTERNEL_PERMISSION」。程式碼範例如下:

第二行傳入一個字串陣列,因本例使用import static故不需要如「android.Manifest.permission.WRITE_EXTERNAL_STORAGE」這麼長的常數,直接使用即可。第三行則需要在類別中先定義int常數,值可以是0或1等不與其他權限相關重複的直即可。

提示:在Android Studio中使用常數時,其實不需要先去定義,直接在程式碼中鍵入常數全大寫的名稱後,按下「Alt+Enter」,會立即偵測到常數需求,再選擇「Create constant field ‘常數名稱’」後,再選擇資料型態與值即可,如下圖:

A4510

最後,檢查儲存外部設備權限與向使用者請求權限的片段程式碼如下:

無權限時,執行完ActivityCompat.requestPermissions方法後,出現如下圖的權限對話框:

A4512

需要注意是程式碼在出現對話框之後,會執行if…else後續程式碼,待使用者按下對話框中的任一選擇鈕後,將自動執行這個Activity內的「onRequestPermissionsResult」方法,這是非同步(Asynchronized)的處理模式。

當使用者允許或拒絕權限

使用者在任何權限請求對話中可按下「允許」或「拒絕」按鈕,當按下按鈕時會自動執行onRequestPermissionsResult,請覆寫該方法,如下:

在此方法內可使用switch…case處理一個以上的權限請求回覆,參數requestCode可以辨識不同的權限回覆,第三個參數是使用者的回覆結果,片段程式碼如下:

 

相關文章:

2 thoughts on “Android 6.0的Permission權限設計

  1. MINA

    您好,請問writeFild()一直出現紅字是為什麼呢?

    回覆
    1. Hank Tom 文章作者

      這個方法是要自己設計,把寫入檔案的程式碼設計在裏面。

      回覆

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *