最初仅请求在前台访问位置信息
当应用中的功能需要位置信息访问权限时,请等到用户与该功能互动时再发出权限请求。本工作流遵循在上下文中请求运行时权限的最佳实践,如介绍如何请求应用权限的指南中所述。
图 1 举例说明了如何执行此过程。该应用包含一项“分享位置信息”功能,需要前台位置信息访问权限。不过,在用户选择分享位置信息按钮之前,应用不会请求位置权限。
图 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_COARSE_LOCATION。即使您只能访问大致位置信息,也可以满足大多数用例的要求。图 2 显示了您的应用以 Android 12 为目标平台且仅请求 ACCESS_COARSE_LOCATION 时显示的面向用户的对话框。
当您的应用同时请求 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 时,系统权限对话框将为用户提供以下选项:
确切位置:允许您的应用获取确切位置信息。
大致位置:允许您的应用仅获取大致位置信息。
图 3 显示该对话框包含两个可帮助用户进行选择的视觉提示选项。用户确定位置信息精确度后,可以点按三个按钮中的一个来选择权限授予的时长。
在 Android 12 和更高版本中,用户可以前往系统设置,以设置任何应用的首选位置信息精确度,而不管该应用的目标 SDK 版本是什么。即使您的应用安装在搭载 Android 11 或更低版本的设备上,用户随后又将该设备升级到 Android 12 或更高版本,也是如此。
注意:如果用户从权限对话框或在系统设置中将应用的位置信息使用权从确切位置降级到大致位置,系统会重启应用的进程。因此,遵循有关请求运行时权限的最佳实践特别重要。
图 2. 当您的应用仅请求 ACCESS_COARSE_LOCATION 时显示的系统权限对话框。
图 3. 当您的应用在单个运行时请求中同时请求 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 时显示的系统权限对话框。
用户的选择会影响权限授予
下表显示了系统根据用户在运行时权限对话框中选择的选项向您的应用授予的权限:
确切位置
大致位置
仅在使用该应用时允许
ACCESS_FINE_LOCATION 和
ACCESS_COARSE_LOCATION
ACCESS_COARSE_LOCATION
仅限这一次
ACCESS_FINE_LOCATION 和
ACCESS_COARSE_LOCATION
ACCESS_COARSE_LOCATION
拒绝
无位置权限
无位置权限
如需确定系统已向您的应用授予的权限,请查看权限请求的返回值。您可以在类似于下面的代码中使用 Jetpack 库,也可以使用平台库,在这种情况下,您自行管理权限请求代码。
Kotlin
@RequiresApi(Build.VERSION_CODES.N)
fun requestPermissions() {
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:
// https://developer.android.com/training/permissions/requesting#request-permission
locationPermissionRequest.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
}LocationPermissionsActivity.kt
Java
private void requestPermissions() {
ActivityResultLauncher
registerForActivityResult(new ActivityResultContracts
.RequestMultiplePermissions(), result -> {
Boolean fineLocationGranted = null;
Boolean coarseLocationGranted = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
fineLocationGranted = result.getOrDefault(
Manifest.permission.ACCESS_FINE_LOCATION, false);
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
});
}LocationPermissionsActivityJava.java
请求升级到确切位置
您可以要求用户将应用的访问权限从大致位置升级到确切位置。但是,在让用户将应用的使用权升级到确切位置信息之前,请考虑应用的用例是否确实需要这一级别的精确度。如果您的应用需要通过蓝牙或 Wi-Fi 将某个设备与附近的设备配对,请考虑使用配套设备配对或蓝牙权限,而不是请求 ACCESS_FINE_LOCATION 权限。
如需请求用户将应用的位置信息使用权从大致位置信息升级到确切位置信息,请执行以下操作:
如有必要,请说明您的应用为何需要获取权限。
再次同时请求 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 权限。由于用户已允许系统向您的应用授予大致位置信息使用权,因此这次系统对话框有所不同,如图 4 和图 5 所示:
图 4. 用户之前选择了大致位置和仅在使用该应用时允许(在图 3 的对话框中)。
图 5. 用户之前选择了大致位置和仅限这一次(在图 3 的对话框中)。
最初仅请求在前台访问位置信息
即使应用中有多项功能需要位置信息访问权限,可能其中也只有部分功能需要后台位置信息访问权限。因此,建议应用对位置权限执行递增请求,先请求前台位置信息访问权限,再请求后台位置信息访问权限。执行递增请求可以为用户提供更大的控制权和透明度,因为他们可以更好地了解应用中的哪些功能需要后台位置信息访问权限。
注意:如果应用以 Android 11(API 级别 30)或更高版本为目标平台,系统会强制执行此最佳实践。如果您同时请求在前台访问位置信息的权限和在后台访问位置信息的权限,系统会忽略该请求,且不会向您的应用授予其中的任一权限。图 6 显示了旨在处理递增请求的应用示例。“显示当前位置”和“推荐附近的地点”这两项功能都需要前台位置信息访问权限。不过,只有“推荐附近的地点”功能需要后台位置信息访问权限。
图 6. 这两项功能都需要位置信息访问权限,但只有“推荐附近的地点”功能需要后台位置信息访问权限。
执行递增请求的过程如下所示:
首先,应用应该引导用户留意到需要前台位置信息访问权限的功能,例如图 1 中的“分享位置信息”功能或图 2 中的“显示当前位置”功能。
在应用有权访问前台位置信息之前,建议您停止让用户访问需要后台位置信息访问权限的功能。
稍后,等到用户探索需要后台位置信息访问权限的功能时,您可以再请求在后台访问位置信息的权限。
其他资源
如需详细了解 Android 中的位置权限,请查看以下资料:
Codelab
隐私保护最佳实践
视频
如何查找可能在后台使用位置信息的情况
示例
示例应用演示了如何使用位置信息权限。