从 Android Q 测试版 1 开始,此项变更具有以下特性:
图 1. 请求用户同意让应用访问位置信息的对话框
Android Q 可让用户更好地控制应用何时能够访问设备位置信息。当在 Android Q 上运行的应用请求位置信息访问权限时,用户会看到如图 1 所示的对话框。此对话框可让用户将位置信息访问权限授予到两个不同的范围:在使用中(仅限前台)或始终(前台和后台)。
为了让用户更好地控制应用对位置信息的访问权限,Android Q 引入了新的位置权限 ACCESS_BACKGROUND_LOCATION。与现有的 ACCESS_FINE_LOCATION和 ACCESS_COARSE_LOCATION 权限不同,新权限仅会影响应用在后台运行时对位置信息的访问权。除非应用的某个 Activity 可见或应用正在运行前台服务,否则应用将被视为在后台运行。
在后台请求访问位置信息
如果您的应用以 Android Q 为目标平台,并且在后台运行时需要访问用户的位置信息,则您必须在应用的清单文件中声明新权限:
如果您的应用在 Android Q 上运行但目标平台是 Android 9(API 级别 28)或更低版本,则以下行为适用:
注意:虽然您的应用可以请求并获得 ACCESS_BACKGROUND_LOCATION 权限,但用户可以通过选择让该应用只能在前台访问位置信息来撤消此权限。
请求后台位置信息访问权限
注意:此部分适用于在 Android Q 上运行的所有应用,无论它们的目标平台是哪个版本。
如果应用的用例需要在后台运行时访问位置信息,请务必考虑您需要此权限的范围:
延续用户发起的操作
注意:如果您的应用在后台运行时不需要访问位置信息,则最佳做法是以 Android Q 为目标平台,并且不请求新的后台位置权限。这样一来,应用仅在使用中时收到位置信息更新。
如果用户只允许您的应用在前台访问位置信息,那么即使用户按下设备上的主屏幕按钮或关闭设备的显示屏,用户可能仍会启动要求该应用访问其位置信息的工作流。
要在此特定用例中保留对用户位置信息的访问权,请启动您已在应用清单中声明具有前台服务类型 "location"的前台服务:
android:name="MyNavigationService" android:foregroundServiceType="location" ... > ...
在启动前台服务之前,请确保您的应用仍可访问用户的位置信息:
val permissionAccessCoarseLocationApproved = ActivityCompat
.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
if (permissionAccessCoarseLocationApproved) {
// App has permission to access location in the foreground. Start your
// foreground service that has a foreground service type of "location".
} else {
// Make a request for foreground-only location access.
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION),
your-permission-request-code
)
}
定期查看用户的位置信息
您的应用可能有一个需要始终都能访问用户位置信息的用例。此类用例包括地理围栏以及与亲朋好友分享位置信息。
如果这些条件适用于您的应用,只要用户授予该应用对其位置信息的始终访问权,您就可以继续请求位置信息更新而无需任何更改:
android:name="MyFamilyLocationSharingService" ... > ...
虽然您的应用可以请求在后台访问位置信息,但用户也可以选择使应用只能在前台访问位置信息,或者完全撤消访问权。因此,每当您的应用启动服务时,都要查看用户是否仍允许该应用在后台访问位置信息。
如果用户已要求您的应用只能在前台访问位置信息,则最佳做法是让该应用显示一个自定义对话框,提醒用户如果该应用不能始终访问其位置信息便无法正常运行。用户确认此对话框后,您可以请求后台位置信息访问权,此时会出现如图 2 所示的系统对话框:
图 2. 请求用户同意让应用始终访问位置信息的对话框
以下代码段中显示了此权限检查逻辑的示例:
val permissionAccessCoarseLocationApproved = ActivityCompat
.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
if (permissionAccessCoarseLocationApproved) {
val backgroundLocationPermissionApproved = ActivityCompat
.checkSelfPermission(this, permission.ACCESS_BACKGROUND_LOCATION) ==
PackageManager.PERMISSION_GRANTED
if (backgroundLocationPermissionApproved) {
// App can access location both in the foreground and in the background.
// Start your service that doesn't have a foreground service type
// defined.
} else {
// App can only access location in the foreground. Display a dialog
// warning the user that your app must have all-the-time access to
// location in order to function properly. Then, request background
// location.
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
your-permission-request-code
)
}
} else {
// App doesn't have access to the user's location at all. Make full request
// for permission.
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION),
your-permission-request-code
)
}
遵循位置信息最佳做法
通过按照本指南中显示的方法来检查和请求位置权限,您的应用可以成功跟踪其有关用户位置信息的访问权限等级。
要详细了解如何确保用户数据安全,请参阅权限最佳做法指南。
仅请求您所需的权限
仅在需要时请求权限。例如:
在未授予权限时支持优雅降级
为了保持良好的用户体验,请在设计应用时确保它可以优雅地处理以下情况: