page.title=權限 page.tags=previewresources, androidm page.keywords=權限, 執行階段, 預覽 page.image={@docRoot}preview/features/images/permissions_check.png @jd:body

快速檢視

本文件內容

  1. 總覽
  2. 編寫執行階段權限的程式碼
  3. 測試執行階段權限
  4. 建議做法

M 開發人員預覽版導入新的應用程式權限模型,簡化使用者安裝和升級應用程式的程序。 如果 M 預覽版上執行的應用程式支援新的權限模型,使用者安裝或升級應用程式時,不需要授與任何權限。應用程式會在需要時才要求權限,而且系統會對使用者顯示要求權限的對話方塊。

如果應用程式支援新的權限模型,它仍能在在執行舊版 Android 的裝置上安裝並執行 (在那些裝置上使用舊的權限模型)。

總覽

使用 M 開發人員預覽版,平台導入新的應用程式權限模型。 以下是這個新模型的主要元件摘要:

此權限模型改變應用程式要求權限的功能行為。 以下是您應遵循以調整此模型的開發做法摘要:

注意:如果應用程式是以 M 開發人員預覽版為目標,「務必要」 使用新的權限模型。

自 M 開發人員預覽版推出起,並非所有 Google 應用程式都完全實作新的權限模型。 Google 正透過 M 開發人員預覽版逐漸更新這些應用程式,以適當保留權限切換設定。

注意:如果您的應用程式有自己的 API 介面,務必要先確定呼叫端具備存取該資料的必要權限後,再 Proxy 權限。

系統應用程式和簽名權限

一般來說,當使用者安裝應用程式時,系統只會將 {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL PROTECTION_NORMAL} 授與應用程式。不過,在某些情況下,系統會授與應用程式更多權限:

在這兩種情況下,使用者仍能隨時撤銷權限,只要前往系統的 [設定] 畫面,然後選擇 [應用程式] > app_name > [權限]。應用程式應持續在執行階段檢查是否具備權限,並在必要時予以要求。

往後和回溯相容性

如果應用程式不是以 M 開發人員預覽版為目標,即使在 M 預覽版裝置上,應用程式也會持續使用舊的權限模型。 當使用者安裝應用程式時,系統會要求使用者授與應用程式的宣示說明中列出的所有權現。

注意:在執行 M 開發人員預覽版的裝置上,使用者能從應用程式的設定畫面關閉任何應用程式 (包括舊版應用程式) 的權限。 如果使用者關閉舊版應用程式的權限,系統會自動停用適當功能。 當應用程式嘗試執行需要那項權限的操作時,該操作不一定會造成例外狀況。 而可能傳回空的資料集,通知發生錯誤,或展示未預期的行為。 例如,如果您不具備查詢行事曆的權限,方法會傳回空的資料集。

如果您在並非執行 M 預覽版的裝置上使用新的權限模型來安裝應用程式,系統會將它和任何其他應用程式一視同仁:系統會在安裝期間要求使用者授與所有宣告的權限。

注意:對於預覽版,您必須將 SDK 最低版本設定為 M 預覽版 SDK,才能以預覽版 SDK 編譯。 這表示在開發人員預覽版期間,您將無法在舊版平台上測試這類應用程式。

權限與意圖比較

在許多情況下,您可以為應用程式在兩種方法當中擇一來執行工作。 您可以讓應用程式要求權限以自行執行操作。 或者,您可以讓應用程式使用意圖,讓其他應用程式來執行工作。

例如,假設您的應用程式需要能夠使用裝置相機拍攝相片。 您的應用程式能要求 android.permission.CAMERA 權限,讓應用程式直接存取相機。 接著,應用程式會使用相機 API 來控制相機並拍攝相片。 這種方法可讓您的應用程式對攝影處理程序有完整控制權,並讓您將相機 UI 納入應用程式。

不過,如果您不需要這類控制權,您可以只使用 {@link android.provider.MediaStore#ACTION_IMAGE_CAPTURE ACTION_IMAGE_CAPTURE} 意圖來要求影像。 當您啟動意圖時,會提示使用者選擇相機應用程式 (如果還沒有預設的相機應用程式),然後該應用程式會拍攝相片。 相機應用程式會將相片傳回應用程式的 {@link android.app.Activity#onActivityResult onActivityResult()} 方法。

同樣地,如果您需要撥打電話、存取使用者的聯絡人等等,您都可以建立適當的意圖來執行,或是要求權限,然後直接存取適當的物件。 每種方法各有利弊。

如果您使用權限:

如果您使用意圖:

編寫執行階段權限的程式碼

如果您的應用程式是以新的 M 開發人員預覽版為目標,請務必使用新的權限模型。 這表示除了在宣示說明中宣告所需的權限之外,您也必須在執行階段檢查是否具備權限,並在您不具備時要求權限。

啟用新的權限模型

如要啟用新的 M 開發人員預覽版權限模型,可將應用程式的 targetSdkVersion 屬性設定為 "MNC",並將 compileSdkVersion 設定為 "android-MNC"。這樣做可啟用所有新權限功能。

對於預覽版,您必須將 minSdkVersion 設定為 "MNC",才能以預覽版 SDK 編譯。

指定只限 M 預覽版使用的權限

您可以在宣示說明中使用新的 <uses-permission-sdk-m> 元素,指出只有在 M 預覽版上才需要某權限。 如果您以這種方式宣告權限,每當在舊版裝置上安裝應用程式時,系統都不會提示使用者或將權限授與應用程式。藉由使用 <uses-permission-sdk-m> 元素,當使用者安裝更新時,您不需要強制他們授與權限,就可以將新的權限新增至更新的應用程式版本。

如果應用程式在使用 M 開發人員預覽版的裝置上執行, <uses-permission-sdk-m> 的運作方式會和 <uses-permission> 相同。 當他們安裝應用程式時,系統不會提示使用者授與任何權限,而應用程式會在需要時才要求權限。

提示授與權限

如果您的應用程式使用新的 M 開發人員預覽版權限模型,在執行 M 預覽版的裝置上初次啟動應用程式時,不會要求使用者授與所有權限。 您的應用程式會在需要時才要求權限。 應用程式要求權限時,系統會對使用者顯示對話方塊。

如果您的應用程式在 SDK 22 以下版本的裝置上執行,應用程式會使用舊的權限模型。 當使用者安裝應用程式時,會提示他們授與應用程式在其宣示說明中要求的所有權限,但標示為 <uses-permission-sdk-m> 的那些權限除外。

檢查應用程式執行所在的平台

只有執行 M 開發人員預覽版的裝置上才支援此權限模型。 呼叫這些方法之前,應用程式應該檢查 {@link android.os.Build.VERSION#CODENAME Build.VERSION.CODENAME} 的值,驗證它執行所在的平台。 如果裝置是執行 M 開發人員預覽版, {@link android.os.Build.VERSION#CODENAME CODENAME} 是 "MNC"

檢查應用程式是否具備所需權限

當使用者嘗試執行需要權限的操作時,應用程式會檢查它目前是否具備可執行此操作的權限。 如要這麼做,應用程式可呼叫 Context.checkSelfPermission(permission_name)。由於使用者可以隨時撤銷應用程式的權限,即使應用程式知道使用者已授與該權限,還是應該執行此檢查。 例如,如果使用者想要使用應用程式拍攝相片,應用程式會呼叫 Context.checkSelfPermission(Manifest.permission.CAMERA)

表 1.權限和權限群組。

權限群組 權限
android.permission-group.CALENDAR
  • android.permission.READ_CALENDAR
  • android.permission.WRITE_CALENDAR
android.permission-group.CAMERA
  • android.permission.CAMERA
android.permission-group.CONTACTS
  • android.permission.READ_CONTACTS
  • android.permission.WRITE_CONTACTS
  • android.permission.READ_PROFILE
  • android.permission.WRITE_PROFILE
android.permission-group.LOCATION
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
android.permission-group.MICROPHONE
  • android.permission.RECORD_AUDIO
android.permission-group.PHONE
  • android.permission.READ_PHONE_STATE
  • android.permission.CALL_PHONE
  • android.permission.READ_CALL_LOG
  • android.permission.WRITE_CALL_LOG
  • com.android.voicemail.permission.ADD_VOICEMAIL
  • android.permission.USE_SIP
  • android.permission.PROCESS_OUTGOING_CALLS
android.permission-group.SENSORS
  • android.permission.BODY_SENSORS
  • android.permission.USE_FINGERPRINT
android.permission-group.SMS
  • android.permission.SEND_SMS
  • android.permission.RECEIVE_SMS
  • android.permission.READ_SMS
  • android.permission.RECEIVE_WAP_PUSH
  • android.permission.RECEIVE_MMS
  • android.permission.READ_CELL_BROADCASTS

必要時要求權限

如果應用程式還沒有所需的權限,應用程式會呼叫 Activity.requestPermissions(String[], int) 方法以要求適當的權限。 應用程式會傳遞它所需的權限,還有整數「要求代碼」。 這種方法以非同步方式運作:它會立即傳回,並在使用者回應對話方塊後,系統會以該結果呼叫應用程式的回呼方法,傳遞應用程式傳遞給 requestPermissions() 的相同「要求代碼」。

下列程式碼會檢查應用程式是否具備讀取使用者聯絡人的權限,並在必要時要求權限。

if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
    requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
            MY_PERMISSIONS_REQUEST_READ_CONTACTS);

    // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
    // app-defined int constant

    return;
}

處理權限要求回應

當應用程式要求權限時,系統會對使用者呈現對話方塊。 當使用者回應時,系統會呼叫 Activity.onRequestPermissionsResult(int, String[], int[]) 並將使用者回應傳遞給它。 您的應用程式需要覆寫該方法。將您傳遞給 requestPermissions() 的相同要求代碼傳遞給回呼。 例如,如果應用程式要求 READ_CONTACTS 存取權,可能會有下列回呼方法:

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! do the
                // calendar task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'switch' lines to check for other
        // permissions this app might request
    }
}

如果使用者授與權限,系統就會將應用程式宣示說明所列出該功能區域的所有權限給予應用程式。 如果使用者拒絕要求,您應該執行適當動作。 例如,您可能會停用依存於此權限的任何選單動作。

系統要求使用者授與權限時,使用者可選擇告知系統不要再次要求該權限。 在上述情況下,當應用程式使用 requestPermissions() 要求該權限時,系統會立即拒絕要求。 在這種情況下,如果使用者再次明確拒絕您的要求,系統會以相同的方式呼叫您的 onRequestPermissionsResult()。 基於這個理由,您的應用程式不能假設已與使用者發生任何直接互動。

測試執行階段權限

如果您的應用程式是以新的 M 開發人員預覽版為目標,您必須測試它是否能適當處理權限。 您不能假設應用程式在執行時具備任何特定權限。 應用程式初次啟動時,很可能不具備任何權限,且使用者可隨時撤銷或還原權限。

您應該測試應用程式,確保它在所有權限情況下都能正常運作。 使用 M 預覽版 SDK,我們現在提供 Android 偵錯橋 (adb) 命令,不管需要嘗試哪種權限設定都能讓您測試。

新的 adb 命令和選項

M 預覽版 SDK 平台工具提供的數個命令可讓您測試應用程式如何處理權限。

連同權限一併安裝

您可以使用 adb install 命令的新 -g 選項,安裝應用程式並授與其宣示說明中列出的所有權限:

$ adb install -g <path_to_apk>

授與和撤銷權限

您可以使用新的 ADB 套件管理員 (pm) 命令,對安裝的應用程式授與和撤銷權限。此功能在自動化測試時非常實用。

如要授與權限,可使用套件管理員的 grant 命令:

$ adb pm grant <package_name> <permission_name>

例如,如要將可錄製音訊的權限授與 com.example.myapp 套件,請使用此命令:

$ adb pm grant com.example.myapp android.permission.RECORD_AUDIO

如要撤銷權限,可使用套件管理員的 revoke 命令:

$ adb pm revoke <package_name> <permission_name>

最佳做法

新的權限模型讓使用者有更順暢的體驗,並能輕鬆安裝應用程式且對應用程式執行的工作感到自在。 建議使用下列最佳做法以充分利用新的模型。

只要求您所需的權限

每次要求權限時,您都是在強迫使用者做出決定。 如果使用者拒絕要求,就會減少您應用程式的功能。 您應該儘可能減少提出這些要求的次數。

例如,您的應用程式可經常使用意圖來取得所需功能,而不是要求權限。 如果您的應用程式需要使用手機的相機拍攝相片,應用程式可以使用 {@link android.provider.MediaStore#ACTION_IMAGE_CAPTURE MediaStore.ACTION_IMAGE_CAPTURE} 意圖。 當您的應用程式執行意圖時,系統會提示使用者選擇已安裝的相機應用程式來拍攝相片。

別讓使用者無法承受

如果您讓使用者一次面對太多權限要求,可能會讓使用者無法承受而結束您的應用程式。您應該改為在需要時才要求權限。

在某些情況下,您的應用程式可能必須具備一或多個權限。在那種情況下,在應用程式啟動時立即要求所有權限是合理的舉措。 例如,如果您建立攝影應用程式,該應用程式會需要存取裝置相機。 使用者初次啟動應用程式時,看到要求使用相機的權限不會被嚇到。 但如果相同的應用程式具有與使用者聯絡人分享相片的功能,您可能「不」應該在初次啟動時要求該權限。 可以等到使用者嘗試使用「分享」功能時,再要求該權限。

如果您的應用程式提供教學課程,在教學課程結束時要求應用程式的基本權限是合理的舉措。

說明需要權限的原因

當您呼叫 requestPermissions() 時,系統顯示的權限對話方塊會說明您的應用程式想要的權限,但不會說明原因。 在某些情況下,使用者可能會感到不解。 在呼叫 requestPermissions() 前對使用者說明應用程式想要權限的原因是不錯的想法。

例如,攝影應用程式可能想要使用定位服務,以便將相片加上地理標籤。 一般使用者可能不明白相片可以包含定位資訊,而不明白為何攝影應用程式會想要知道位置。 在這種情況下,在呼叫 requestPermissions()「之前」,將此功能的相關資訊告訴使用者會是不錯的想法。

您可以將這些要求與應用程式教學課程結合來完成此作業。教學課程可依序顯示應用程式的各項功能,並可以同時說明需要哪些權限。 例如,攝影應用程式的教學課程可以示範「與聯絡人分享相片」功能,接著告訴使用者需要提供權限,應用程式才能看到使用者的聯絡人。 接著,應用程式可以呼叫 requestPermissions(),要求使用者提供該存取權。 當然,並非每位使用者都會依照教學課程執行動作,所以您仍需要在應用程式的正常操作期間檢查和要求權限。