Xamarin 中的許可權Permissions In Xamarin.Android

概觀Overview

Android 應用程式會在自己的沙箱中執行,且基於安全性考慮,無法存取裝置上的特定系統資源或硬體。Android applications run in their own sandbox and for security reasons do not have access to certain system resources or hardware on the device. 使用者必須先明確授與應用程式的許可權,才能使用這些資源。The user must explicitly grant permission to the app before it may use these resources. 例如,應用程式無法存取裝置上的 GPS,而不需要使用者的明確許可權。For example, an application cannot access the GPS on a device without explicit permission from the user. 如果應用程式嘗試在沒有許可權的情況下存取受保護的資源,則 Android 會擲回 Java.Lang.SecurityExceptionAndroid will throw a Java.Lang.SecurityException if an app tries to access a protected resource without permission.

應用程式開發人員會在androidmanifest.xml中宣告許可權。Permissions are declared in the AndroidManifest.xml by the application developer when the app is developed. Android 有兩個不同的工作流程,可取得使用者對這些許可權的同意:Android has two different workflows for obtaining the user's consent for those permissions:

  • 針對以 Android 5.1 (API 層級22)或更低版本為目標的應用程式,在安裝應用程式時,就會發生許可權要求。For apps that targeted Android 5.1 (API level 22) or lower, the permission request occurred when the app was installed. 如果使用者未授與許可權,則不會安裝應用程式。If the user did not grant the permissions, then the app would not be installed. 安裝應用程式之後,除非卸載應用程式,否則沒有任何方法可以撤銷許可權。Once the app is installed, there is no way to revoke the permissions except by uninstalling the app.
  • 從 Android 6.0 (API 層級23)開始,使用者對許可權擁有更多控制權;只要應用程式安裝在裝置上,他們就可以授與或撤銷許可權。Starting in Android 6.0 (API level 23), users were given more control over permissions; they can grant or revoke permissions as long as the app is installed on the device. 此螢幕擷取畫面顯示 Google Contacts 應用程式的許可權設定。This screenshot shows the permission settings for the Google Contacts app. 它會列出各種許可權,並允許使用者啟用或停用許可權:It lists the various permissions and allows the user to enable or disable permissions:

範例許可權畫面

Android 應用程式必須在執行時間檢查,以查看他們是否有權存取受保護的資源。Android apps must check at run-time to see if they have permission to access a protected resource. 如果應用程式沒有許可權,則必須使用 Android SDK 提供的新 Api 提出要求,以供使用者授與許可權。If the app does not have permission, then it must make requests using the new APIs provided by the Android SDK for the user to grant the permissions. 許可權分成兩個類別:Permissions are divided into two categories:

  • 一般許可權– 這些許可權會對使用者的安全性或隱私權造成較小的安全性風險。Normal Permissions – These are permissions which pose little security risk to the user's security or privacy. Android 6.0 會在安裝時自動授與一般許可權。Android 6.0 will automatically grant normal permissions at the time of installation. 如需一般許可權的完整清單,請參閱 Android 檔。Please consult the Android documentation for a complete list of normal permissions.
  • 危險的許可權– 相對於一般許可權,危險的許可權是保護使用者安全性或隱私權的許可權。Dangerous Permissions – In contrast to normal permissions, dangerous permissions are those that protect the user's security or privacy. 使用者必須明確授與這些許可權。These must be explicitly granted by the user. 傳送或接收 SMS 訊息是需要危險許可權的動作範例。Sending or receiving an SMS message is an example of an action requiring a dangerous permission.

重要

許可權所屬的類別目錄可能會隨著時間而變更。The category that a permission belongs to may change over time. 已分類為「一般」許可權的許可權可能會在未來的 API 層級提升為危險許可權。It is possible that a permission which was categorized as a "normal" permission may be elevated in future API levels to a dangerous permission.

危險的許可權會進一步細分為許可權群組Dangerous permissions are further sub-divided into permission groups. 許可權群組會保留邏輯上相關的許可權。A permission group will hold permissions that are logically related. 當使用者將許可權授與許可權群組的其中一個成員時,Android 會自動將許可權授與該群組的所有成員。When the user grants permission to one member of a permission group, Android automatically grants permission to all members of that group. 例如, STORAGE許可權群組會同時保存 WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE 許可權。For example, the STORAGE permission group holds both the WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE permissions. 如果使用者授與 READ_EXTERNAL_STORAGE的許可權,則會同時自動授與 WRITE_EXTERNAL_STORAGE 許可權。If the user grants permission to READ_EXTERNAL_STORAGE, then the WRITE_EXTERNAL_STORAGE permission is automatically granted at the same time.

在要求一個或多個許可權之前,最好先提供理由,說明為什麼應用程式需要許可權,然後再要求許可權。Before requesting one or more permissions, it is a best practice to provide a rationale as to why the app requires the permission before requesting the permission. 一旦使用者瞭解其基本原理,應用程式就可以向使用者要求許可權。Once the user understands the rationale, the app can request permission from the user. 藉由瞭解其基本概念,如果使用者想要授與許可權並瞭解影響(如果沒有的話),則可以做出明智的決定。By understanding the rationale, the user can make an informed decision if they wish to grant the permission and understand the repercussions if they do not.

檢查和要求許可權的整個工作流程稱為「_執行時間」許可權_檢查,並可在下圖中摘要說明:The whole workflow of checking and requesting permissions is known as a run-time permissions check, and can be summarized in the following diagram:

執行時間許可權檢查流程圖Run-time permission check flow chart

Android 支援程式庫反向移植一些新的 Api,以取得舊版 Android 的許可權。The Android Support Library backports some of the new APIs for permissions to older versions of Android. 這些 backport Api 會自動檢查裝置上的 Android 版本,因此不需要每次都執行 API 層級檢查。These backported APIs will automatically check the version of Android on the device so it is not necessary to perform an API level check each time.

本檔將討論如何將許可權新增至 Xamarin Android 應用程式,以及以 Android 6.0 (API 層級23)或更高版本為目標的應用程式應該如何執行執行時間許可權檢查。This document will discuss how to add permissions to a Xamarin.Android application and how apps that target Android 6.0 (API level 23) or higher should perform a run-time permission check.

注意

硬體的許可權可能會影響應用程式 Google Play 的篩選方式。It is possible that permissions for hardware may affect how the app is filtered by Google Play. 例如,如果應用程式需要相機的許可權,則 Google Play 不會在未安裝相機的裝置上顯示 Google Play 商店中的應用程式。For example, if the app requires permission for the camera, then Google Play will not show the app in the Google Play Store on a device that does not have a camera installed.

需求Requirements

強烈建議使用 Xamarin Android 專案,包括支援相容的 NuGet 套件。It is strongly recommended that Xamarin.Android projects include the Xamarin.Android.Support.Compat NuGet package. 此套件會將許可權特定的 Api 將到舊版的 Android,提供一個通用介面,而不需要持續檢查應用程式執行所在的 Android 版本。This package will backport permission specific APIs to older versions of Android, providing one common interface without the need to constantly check the version of Android that the app is running on.

要求系統許可權Requesting System Permissions

使用 Android 許可權的第一個步驟是在 Android 資訊清單檔案中宣告許可權。The first step in working with Android permissions is to declare the permissions in the Android manifest file. 無論應用程式瞄準的 API 層級為何,都必須執行此動作。This must be done regardless of the API level that the app is targetting.

以 Android 6.0 或更高版本為目標的應用程式無法假設,因為使用者在過去某個時間點授與許可權,所以該許可權將會在下一次生效。Apps that target Android 6.0 or higher cannot assume that because the user granted permission at some point in the past, that the permission will be valid the next time. 以 Android 6.0 為目標的應用程式必須一律執行執行時間許可權檢查。An app that targets Android 6.0 must always perform a runtime permission check. 以 Android 5.1 或更低版本為目標的應用程式不需要執行執行時間許可權檢查。Apps that target Android 5.1 or lower do not need to perform a run-time permission check.

注意

應用程式應該只要求其所需的許可權。Applications should only request the permissions that they require.

在資訊清單中宣告許可權Declaring Permissions in the Manifest

許可權會使用 uses-permission 元素加入至androidmanifest.xmlPermissions are added to the AndroidManifest.xml with the uses-permission element. 例如,如果應用程式要找出裝置的位置,它需要良好和課程的位置許可權。For example, if an application is to locate the position of the device, it requires fine and course location permissions. 下列兩個元素會新增至資訊清單:The following two elements are added to the manifest:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

您可以使用內建于 Visual Studio 的工具支援來宣告許可權:It is possible to declare the permissions using the tool support built into Visual Studio:

  1. 按兩下 方案總管中的 屬性,然後選取屬性視窗中的 Android 資訊清單 索引標籤:Double-click Properties in the Solution Explorer and select the Android Manifest tab in the Properties window:

    在 [Android 資訊清單] 索引標籤中 必要許可權Required permissions in the Android Manifest tab

  2. 如果應用程式還沒有 Androidmanifest.xml,請按一下 [找不到 androidmanifest.xml]。按一下以新增一個,如下所示:If the application does not already have an AndroidManifest.xml, click No AndroidManifest.xml found. Click to add one as shown below:

    沒有 Androidmanifest.xml 的 xml 訊息No AndroidManifest.xml message

  3. 從 [必要許可權] 清單中選取您的應用程式所需的任何許可權,並儲存:Select any permissions your application needs from the Required permissions list and save:

    已選取 範例相機許可權Example CAMERA permissions selected

Xamarin 會在組建階段自動將部分許可權新增至 Debug 組建。Xamarin.Android will automatically add some permissions at build time to Debug builds. 這可讓您更輕鬆地對應用程式進行偵錯工具。This will make debugging the application easier. 特別的是,INTERNETREAD_EXTERNAL_STORAGE兩個值得注意的許可權。In particular, two notable permissions are INTERNET and READ_EXTERNAL_STORAGE. 這些自動設定的許可權將不會在 [必要許可權] 清單中啟用。These automatically-set permissions will not appear to be enabled in the Required permissions list. 不過,發行組建只會使用在 [必要許可權] 清單中明確設定的許可權。Release builds, however, use only the permissions that are explicitly set in the Required permissions list.

若為以 Android 5.1 (API 層級22)或更低版本為目標的應用程式,則不需要執行其他動作。For apps that target Android 5.1(API level 22) or lower, there is nothing more that needs to be done. 將在 Android 6.0 (API 23 層級23)或更高版本上執行的應用程式,應該繼續進行下一節,以瞭解如何執行執行時間許可權檢查。Apps that will run on Android 6.0 (API 23 level 23) or higher should proceed on to the next section on how to perform run time permission checks.

Android 6.0 中的執行時間許可權檢查Runtime Permission Checks in Android 6.0

ContextCompat.CheckSelfPermission 方法(可用於 Android 支援程式庫)是用來檢查是否已授與特定的許可權。The ContextCompat.CheckSelfPermission method (available with the Android Support Library) is used to check if a specific permission has been granted. 這個方法會傳回具有兩個值之一的Android.Content.PM.Permission列舉:This method will return a Android.Content.PM.Permission enum which has one of two values:

  • Permission.Granted – 已授與指定的許可權。Permission.Granted – The specified permission has been granted.
  • Permission.Denied – 未授與指定的許可權。Permission.Denied – The specified permission has not been granted.

此程式碼片段是如何檢查活動中的攝影機許可權的範例:This code snippet is an example of how to check for the Camera permission in an Activity:

if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) == (int)Permission.Granted) 
{
    // We have permission, go ahead and use the camera.
} 
else 
{
    // Camera permission is not granted. If necessary display rationale & request.
}

最佳做法是將應用程式的必要許可權通知使用者,以做出明智的決策來授與許可權。It is a best practice to inform the user as to why a permission is necessary for an application so that an informed decision can be made to grant the permission. 其中一個範例是將相片和異地標記拍照的應用程式。An example of this would be an app that takes photos and geo-tags them. 使用者可以清楚瞭解相機許可權,但可能不清楚為什麼應用程式也需要裝置的位置。It is clear to the user that the camera permission is necessary, but it might not be clear why the app also needs the location of the device. 基本原理應該會顯示一則訊息,協助使用者瞭解為什麼需要 location 許可權,以及需要攝影機許可權。The rationale should display a message to help the user understand why the location permission is desirable and that the camera permission is required.

ActivityCompat.ShouldShowRequestPermissionRationale 方法是用來判斷是否應該向使用者顯示基本原理。The ActivityCompat.ShouldShowRequestPermissionRationale method is used to determine if the rationale should be shown to the user. 如果應該顯示指定許可權的基本原理,這個方法將會傳回 trueThis method will return true if the rationale for a given permission should be displayed. 此螢幕擷取畫面顯示應用程式所顯示的 Snackbar 範例,說明應用程式為何需要知道裝置的位置:This screenshot shows an example of a Snackbar displayed by an application that explains why the app needs to know the location of the device:

位置的基本原理

如果使用者授與許可權,則應該呼叫 ActivityCompat.RequestPermissions(Activity activity, string[] permissions, int requestCode) 方法。If the user grants the permission, the ActivityCompat.RequestPermissions(Activity activity, string[] permissions, int requestCode) method should be called. 這個方法需要下列參數:This method requires the following parameters:

  • 活動– 這是要求許可權的活動,而且會由 Android 的結果通知。activity – This is the activity that is requesting the permissions and is to be informed by Android of the results.
  • 許可權– 所要求的許可權清單。permissions – A list of the permissions that are being requested.
  • requestCode – 用來比對 RequestPermissions 呼叫之許可權要求結果的整數值。requestCode – An integer value that is used to match the results of the permission request to a RequestPermissions call. 這個值應大於零。This value should be greater than zero.

此程式碼片段是所討論兩種方法的範例。This code snippet is an example of the two methods that were discussed. 首先,會進行檢查,以判斷是否應該顯示許可權的理由。First, a check is made to determine if the permission rationale should be shown. 如果要顯示基本原理,則會顯示 Snackbar,其中包含基本原理。If the rationale is to be shown, then a Snackbar is displayed with the rationale. 如果使用者在 Snackbar 中按一下 [確定] ,則應用程式會要求許可權。If the user clicks OK in the Snackbar, then the app will request the permissions. 如果使用者不接受基本原理,則應用程式不應該繼續要求許可權。If the user does not accept the rationale, then the app should not proceed to request permissions. 如果沒有顯示 [基本],則活動會要求許可權:If the rationale is not shown, then the Activity will request the permission:

if (ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.AccessFineLocation)) 
{
    // Provide an additional rationale to the user if the permission was not granted
    // and the user would benefit from additional context for the use of the permission.
    // For example if the user has previously denied the permission.
    Log.Info(TAG, "Displaying camera permission rationale to provide additional context.");

    var requiredPermissions = new String[] { Manifest.Permission.AccessFineLocation };
    Snackbar.Make(layout, 
                   Resource.String.permission_location_rationale,
                   Snackbar.LengthIndefinite)
            .SetAction(Resource.String.ok, 
                       new Action<View>(delegate(View obj) {
                           ActivityCompat.RequestPermissions(this, requiredPermissions, REQUEST_LOCATION);
                       }    
            )
    ).Show();
}
else 
{
    ActivityCompat.RequestPermissions(this, new String[] { Manifest.Permission.Camera }, REQUEST_LOCATION);
}

即使使用者已授與許可權,也可以呼叫 RequestPermissionRequestPermission can be called even if the user has already granted permission. 後續的呼叫並不是必要的,但可讓使用者有機會確認(或撤銷)許可權。Subsequent calls are not necessary, but they provide the user with the opportunity to confirm (or revoke) the permission. 呼叫 RequestPermission 時,系統會將控制權移交給作業系統,這會顯示可接受許可權的 UI:When RequestPermission is called, control is handed off to the operating system, which will display a UI for accepting the permissions:

許可權對話方塊

使用者完成之後,Android 會透過回呼方法(OnRequestPermissionResult)將結果傳回給活動。After the user is finished, Android will return the results to the Activity via a callback method, OnRequestPermissionResult. 這個方法是介面 ActivityCompat.IOnRequestPermissionsResultCallback 的一部分,必須由活動執行。This method is a part of the interface ActivityCompat.IOnRequestPermissionsResultCallback which must be implemented by the Activity. 此介面具有單一方法,OnRequestPermissionsResult,其將由 Android 叫用以通知活動使用者的選擇。This interface has a single method, OnRequestPermissionsResult, which will be invoked by Android to inform the Activity of the user's choices. 如果使用者已授與許可權,則應用程式可以繼續使用受保護的資源。If the user has granted the permission, then the app can go ahead and use the protected resource. 如何執行 OnRequestPermissionResult 的範例如下所示:An example of how to implement OnRequestPermissionResult is shown below:

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    if (requestCode == REQUEST_LOCATION) 
    {
        // Received permission result for camera permission.
        Log.Info(TAG, "Received response for Location permission request.");

        // Check if the only required permission has been granted
        if ((grantResults.Length == 1) && (grantResults[0] == Permission.Granted)) {
            // Location permission has been granted, okay to retrieve the location of the device.
            Log.Info(TAG, "Location permission has now been granted.");
            Snackbar.Make(layout, Resource.String.permission_available_camera, Snackbar.LengthShort).Show();            
        } 
        else 
        {
            Log.Info(TAG, "Location permission was NOT granted.");
            Snackbar.Make(layout, Resource.String.permissions_not_granted, Snackbar.LengthShort).Show();
        }
    } 
    else 
    {
        base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

摘要Summary

本指南討論如何在 Android 裝置中新增和檢查許可權。This guide discussed how to add and check for permissions in an Android device. 舊版 Android 應用程式(API 層級 < 23)和新的 Android 應用程式(API 層級 > 22)之間的許可權使用方式上的差異。The differences in how permissions work between old Android apps (API level < 23) and new Android apps (API level > 22). 它討論了如何在 Android 6.0 中執行執行時間許可權檢查。It discussed how to perform run-time permission checks in Android 6.0.