请求位置权限

为了保护用户隐私,使用位置服务的应用必须请求位置权限。

请求位置权限时,请遵循与任何其他 运行时权限 相同的最佳实践。在位置权限方面,一个重要的区别是系统包含多个与位置相关的权限。您请求哪些权限以及如何请求权限取决于应用用例的位置要求。

此页面描述了不同类型的位置要求,并提供了有关在每种情况下如何请求位置权限的指导。

位置访问类型

每个权限都具有以下特征的组合

前台位置

如果您的应用包含仅共享或接收位置信息一次或在限定时间内的功能,则该功能需要前台位置访问权限。以下是一些示例

  • 在导航应用中,一项功能允许用户获取逐向导航。
  • 在消息应用中,一项功能允许用户与其他用户共享其当前位置。

如果应用的功能在以下情况之一中访问设备的当前位置,则系统会认为您的应用正在使用前台位置

  • 属于您的应用的活动可见。
  • 您的应用正在运行前台服务。当前台服务正在运行时,系统会通过显示持久通知来提高用户意识。当应用置于后台时(例如,当用户按下设备上的主页按钮或关闭设备的显示屏时),您的应用会保留访问权限。

    此外,建议您声明 前台服务类型location,如以下代码片段所示。在 Android 10(API 级别 29)及更高版本上,您必须声明此前台服务类型。

    <!-- Recommended for Android 9 (API level 28) and lower. -->
    <!-- Required for Android 10 (API level 29) and higher. -->
    <service
        android:name="MyNavigationService"
        android:foregroundServiceType="location" ... >
        <!-- Any inner elements would go here. -->
    </service>

当您的应用请求 ACCESS_COARSE_LOCATION 权限或 ACCESS_FINE_LOCATION 权限时,您会声明对前台位置的需求,如以下代码片段所示

<manifest ... >
  <!-- Always include this permission -->
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

  <!-- Include only if your app benefits from precise location access. -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

后台位置

如果应用中的功能持续与其他用户共享位置或使用 地理围栏 API,则该应用需要后台位置访问权限。以下是一些示例

  • 在家庭位置共享应用中,一项功能允许用户持续与家人共享位置。
  • 在物联网应用中,一项功能允许用户配置其家庭设备,以便在用户离开家时关闭,并在用户返回家时重新打开。

如果应用在 前台位置 部分中未描述的任何情况下访问设备的当前位置,则系统会认为您的应用正在使用后台位置。后台位置精度与 前台位置精度 相同,这取决于您的应用声明的位置权限。

在 Android 10(API 级别 29)及更高版本上,您必须在应用的清单中声明 ACCESS_BACKGROUND_LOCATION 权限才能 在运行时请求后台位置访问权限。在早期版本的 Android 上,当您的应用收到前台位置访问权限时,它也会自动收到后台位置访问权限。

<manifest ... >
  <!-- Required only when requesting background location access on
       Android 10 (API level 29) and higher. -->
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</manifest>

精度

Android 支持以下级别的位置精度

近似
提供设备位置估计。如果此位置估计来自 LocationManagerServiceFusedLocationProvider,则此估计的精度在约 3 平方公里(约 1.2 平方英里)以内。当您声明 ACCESS_COARSE_LOCATION 权限但未声明 ACCESS_FINE_LOCATION 权限时,您的应用可以接收此精度级别的位置。
精确

提供尽可能准确的设备位置估算。如果位置估算来自LocationManagerServiceFusedLocationProvider,则此估算通常在约 50 米(160 英尺)以内,有时精确到几米(10 英尺)或更精确。当您声明ACCESS_FINE_LOCATION权限时,您的应用可以接收此精度的定位。

如果用户授予了近似位置权限,则无论您的应用声明了哪些位置权限,您的应用都只能访问近似位置。

当用户仅授予近似位置访问权限时,您的应用仍应能够正常工作。如果应用中的某个功能绝对需要使用ACCESS_FINE_LOCATION权限访问精确位置,您可以提示用户允许您的应用访问精确位置

在运行时请求位置访问权限

当应用中的某个功能需要位置访问权限时,请等到用户与该功能交互后再发出权限请求。此工作流程遵循在上下文中请求运行时权限的最佳实践,如解释如何请求应用权限的指南中所述。

图 1 显示了如何执行此过程的示例。该应用包含一个“分享位置”功能,该功能需要前台位置访问权限。但是,应用只有在用户选择“分享位置”按钮后才会请求位置权限。

After the user selects the Share Location button, the
    system's location permission dialog appears
图 1. 需要前台位置访问权限的位置共享功能。如果用户选择“仅在使用应用期间允许”,则启用此功能。

用户可以仅授予近似位置

在 Android 12(API 级别 31)或更高版本上,即使您的应用请求ACCESS_FINE_LOCATION运行时权限,用户也可以请求您的应用仅检索近似位置信息。

要处理此潜在的用户行为,请不要单独请求ACCESS_FINE_LOCATION权限。而应在单个运行时请求中同时请求ACCESS_FINE_LOCATION权限和ACCESS_COARSE_LOCATION权限。如果您尝试仅请求ACCESS_FINE_LOCATION,则系统会在某些 Android 12 版本上忽略此请求。如果您的应用以 Android 12 或更高版本为目标,则系统会在Logcat中记录以下错误消息

ACCESS_FINE_LOCATION must be requested with ACCESS_COARSE_LOCATION.

当您的应用同时请求ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION时,系统权限对话框会为用户提供以下选项

  • 精确:允许您的应用获取精确位置信息。
  • 近似:允许您的应用仅获取近似位置信息。

图 3显示对话框包含这两个选项的视觉提示,以帮助用户进行选择。用户确定位置精度后,点击三个按钮之一以选择权限授予的持续时间。

在 Android 12 及更高版本上,用户可以导航到系统设置以设置任何应用的首选位置精度,而不管该应用的目标 SDK 版本如何。即使您的应用安装在运行 Android 11 或更低版本的设备上,然后用户将设备升级到 Android 12 或更高版本,情况也是如此。

The dialog refers only to approximate location and
         contains 3 buttons, one above the other
图 2. 当您的应用仅请求ACCESS_COARSE_LOCATION时出现的系统权限对话框。
The dialog has 2 sets of options, one above the other
图 3. 当您的应用在单个运行时请求中同时请求ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION时出现的系统权限对话框。

用户选择会影响权限授予

下表显示了系统根据用户在权限运行时对话框中选择的选项授予应用的权限

精确

近似
在使用应用期间 ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
ACCESS_COARSE_LOCATION
仅此一次 ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
ACCESS_COARSE_LOCATION
拒绝 无位置权限 无位置权限

要确定系统已授予应用哪些权限,请检查权限请求的返回值。您可以在类似于以下内容的代码中使用 Jetpack 库,或者使用平台库,在这些库中,您可以自己管理权限请求代码

Kotlin

val locationPermissionRequest = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        when {
            permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
                // Precise location access granted.
            }
            permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
                // Only approximate location access granted.
            } else -> {
                // No location access granted.
            }
        }
    }

// ...

// Before you perform the actual permission request, check whether your app
// already has the permissions, and whether your app needs to show a permission
// rationale dialog. For more details, see Request permissions.
locationPermissionRequest.launch(arrayOf(
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION))

Java

ActivityResultLauncher<String[]> locationPermissionRequest =
    registerForActivityResult(new ActivityResultContracts
        .RequestMultiplePermissions(), result -> {
            Boolean fineLocationGranted = result.getOrDefault(
                    Manifest.permission.ACCESS_FINE_LOCATION, false);
            Boolean coarseLocationGranted = result.getOrDefault(
                    Manifest.permission.ACCESS_COARSE_LOCATION,false);
            if (fineLocationGranted != null && fineLocationGranted) {
                // Precise location access granted.
            } else if (coarseLocationGranted != null && coarseLocationGranted) {
                // Only approximate location access granted.
            } else {
                // No location access granted.
            }
        }
    );

// ...

// Before you perform the actual permission request, check whether your app
// already has the permissions, and whether your app needs to show a permission
// rationale dialog. For more details, see Request permissions.
locationPermissionRequest.launch(new String[] {
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION
});

请求升级到精确位置

您可以提示用户将应用的访问权限从近似位置升级到精确位置。但是,在提示用户将应用的访问权限升级到精确位置之前,请考虑您的应用用例是否绝对需要这种精度。如果您的应用需要通过蓝牙或 Wi-Fi 将设备与附近的设备配对,请考虑使用伴侣设备配对蓝牙权限,而不是请求ACCESS_FINE_LOCATION权限。

要请求用户将应用的位置访问权限从近似升级到精确,请执行以下操作

  1. 如有必要,解释您的应用为何需要此权限
  2. 再次同时请求ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION权限。由于用户已允许系统向您的应用授予近似位置,因此这次系统对话框有所不同,如图 4 和图 5 所示
The dialog contains the options 'Change to precise
         location', 'Only this time', and 'Deny'.
图 4. 用户之前选择了“近似”和“在使用应用期间”(在图 3 的对话框中)。
The dialog contains the options 'Only this time' and
         'Deny'.
图 5. 用户之前选择了“近似”和“仅此一次”(在图 3 的对话框中)。

最初仅请求前台位置

即使应用中的多个功能需要位置访问权限,也可能只有其中一些功能需要后台位置访问权限。因此,建议您的应用对位置权限执行增量请求,先请求前台位置访问权限,然后再请求后台位置访问权限。通过执行增量请求,您可以为用户提供更多控制权和透明度,因为他们可以更好地了解应用中的哪些功能需要后台位置访问权限。

图 6 显示了一个旨在处理增量请求的应用示例。 “显示当前位置”和“推荐附近地点”这两个功能都需要前台位置访问权限。但是,只有“推荐附近地点”功能需要后台位置访问权限。

The button that enables foreground location access is
    positioned half a screen length away from the button that enables background
    location
图 6. 两个功能都需要位置访问权限,但只有“推荐附近功能”功能需要后台位置访问权限。

执行增量请求的过程如下

  1. 首先,您的应用应引导用户使用需要前台位置访问权限的功能,例如图 1 中的“分享位置”功能或图 2 中的“显示当前位置”功能。

    建议您在应用获得前台位置访问权限之前,禁用用户对需要后台位置访问权限的功能的访问。

  2. 稍后,当用户探索需要后台位置访问权限的功能时,您可以请求后台位置访问权限。

如有必要,请求后台位置

图 7. 设置页面包含一个名为“始终允许”的选项,该选项授予后台位置访问权限。

权限对话框内容取决于目标 SDK 版本

当应用中的某个功能在运行 Android 10(API 级别 29)的设备上请求后台位置时,系统权限对话框会包含一个名为“始终允许”的选项。如果用户选择此选项,则应用中的该功能将获得后台位置访问权限。

但是,在 Android 11(API 级别 30)及更高版本上,系统对话框不包含“始终允许”选项。相反,用户必须在设置页面上启用后台位置,如图 7 所示。

您可以通过在请求后台位置权限时遵循最佳实践来帮助用户导航到此设置页面。授予权限的过程取决于应用的目标 SDK 版本。

应用以 Android 11 或更高版本为目标

如果尚未向您的应用授予ACCESS_BACKGROUND_LOCATION权限,并且shouldShowRequestPermissionRationale()返回true,请向用户显示一个教育性 UI,其中包含以下内容

  • 清楚地解释应用的功能为何需要访问后台位置。
  • 授予后台位置的设置选项的用户可见标签(例如,图 7 中的“始终允许”)。您可以调用getBackgroundPermissionOptionLabel()以获取此标签。此方法的返回值已本地化为用户设备的语言首选项。
  • 用户拒绝权限的选项。如果用户拒绝后台位置访问权限,则他们应该能够继续使用您的应用。
Users can tap the system notification to change location
  settings for an app
图 8. 提醒用户他们已向应用授予后台位置访问权限的通知。

应用以 Android 10 或更低版本为目标

当应用中的某个功能请求后台位置访问权限时,用户会看到一个系统对话框。此对话框包含一个选项,用于导航到设置页面上应用的位置权限选项。

只要您的应用已遵循请求位置权限的最佳实践,您就不需要进行任何更改来支持此行为。

用户可以影响后台位置精度

如果用户请求大致位置,则用户在位置权限对话框中的选择也适用于后台位置。换句话说,如果用户授予您的应用ACCESS_BACKGROUND_LOCATION权限,但在前台仅授予大致位置访问权限,则您的应用在后台也仅具有大致位置访问权限。

后台位置授权提醒

在 Android 10 及更高版本上,当应用中的某个功能在用户授予后台位置访问权限后首次在后台访问设备位置时,系统会安排发送通知给用户。此通知提醒用户,他们已允许您的应用始终访问设备位置。图 8 显示了一个示例通知。

检查应用 SDK 依赖项中的位置要求

检查您的应用是否使用了任何依赖于位置权限的 SDK,尤其是ACCESS_FINE_LOCATION权限。请参阅这篇关于了解 SDK 依赖项的行为的 Medium 文章。

其他资源

有关 Android 中位置权限的更多信息,请查看以下资料

Codelabs

视频

示例