正确处理位置权限
了解前台位置和精确位置
正确处理位置权限 是 CoddyKit 上的免费 Android Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 4 节课。
权限不是可选项
位置权限是 Android 最敏感的权限之一。仅在清单中声明还不够——在新版本 Android 上,您必须在运行时请求用户授权,并妥善处理每一种结果。
本课将介绍权限级别、如何在 Compose 中请求权限、如何处理拒绝,以及新的精确与大致位置和后台位置规则。
三种位置权限
Android 将位置权限分为多个级别:
ACCESS_COARSE_LOCATION—— 大致位置(约精确到街区)。ACCESS_FINE_LOCATION—— 精确位置(GPS 级别)。ACCESS_BACKGROUND_LOCATION—— 应用不在前台时访问位置。
只请求实际需要的权限。后台位置访问会在 Play 商店触发额外审核。
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- only if truly needed: -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />在 Compose 中请求权限
Activity Result API 会为您提供用于显示权限对话框的启动器。在 Compose 中,将 rememberLauncherForActivityResult 与 RequestMultiplePermissions 合约结合使用。
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { result ->
val fine = result[Manifest.permission.ACCESS_FINE_LOCATION] == true
val coarse = result[Manifest.permission.ACCESS_COARSE_LOCATION] == true
// react to the user's choice
}发起请求
调用 launch() 并传入权限数组即可触发对话框——通常应在用户点击按钮后触发,而不是在界面加载时自动触发。
Button(onClick = {
launcher.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
}) {
Text("Enable location")
}检查权限是否已授予
如果权限已经授予,请不要再次请求。在发起请求前,使用 ContextCompat.checkSelfPermission 进行检查。
import androidx.core.content.ContextCompat
import android.content.pm.PackageManager
fun hasFineLocation(context: Context): Boolean {
return ContextCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}精确位置与大致位置
从 Android 12(API 31)开始,即使您请求的是精确位置,用户也可以授予大致位置权限。因此,您必须同时请求精确和大致位置权限,并接受用户可能将授权降级为大致位置。
请尽可能设计出在大致位置下也能正常工作的功能。
// Request both — the system shows a Precise/Approximate toggle
launcher.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
// If only COARSE comes back granted, you got approximate location.显示权限说明
如果用户拒绝过一次,Android 允许您检查 shouldShowRequestPermissionRationale。当它为 true 时,请在再次请求前,友好地说明您为什么需要位置信息。
import androidx.core.app.ActivityCompat
val shouldExplain = ActivityCompat.shouldShowRequestPermissionRationale(
activity,
Manifest.permission.ACCESS_FINE_LOCATION
)
if (shouldExplain) {
// show a dialog: "We use your location to find nearby stores"
}处理永久拒绝
如果用户选择不再询问(或拒绝两次),系统将不再显示对话框。您唯一能做的是将用户引导至应用设置,让他们手动启用权限。
import android.content.Intent
import android.provider.Settings
import android.net.Uri
fun openAppSettings(context: Context) {
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", context.packageName, null)
)
context.startActivity(intent)
}使用 Accompanist Permissions
accompanist-permissions 库将上述流程封装成适合 Compose 使用的状态。rememberMultiplePermissionsState 会跟踪权限授予状态,并提供 launchMultiplePermissionRequest() 调用。
import com.google.accompanist.permissions.rememberMultiplePermissionsState
val permissions = rememberMultiplePermissionsState(
listOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
if (permissions.allPermissionsGranted) {
// show the map / read location
} else {
Button(onClick = { permissions.launchMultiplePermissionRequest() }) {
Text("Grant location")
}
}后台位置规则
后台位置需要采用两步流程:先授予前台位置权限(精确/大致),然后单独请求 ACCESS_BACKGROUND_LOCATION,该请求会在 Android 11 及更高版本上打开系统设置。Google Play 商店要求您提供明确的使用理由和隐私政策。
只有当您的应用确实需要在关闭状态下获取位置时才请求该权限,例如地理围栏、健身追踪等。
// Step 1: request foreground first and confirm it's granted.
// Step 2: only then request background:
launcher.launch(
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
)
// On Android 11+ this sends the user to settings to pick "Allow all the time".受权限控制的地图
将这些部分串联起来:根据权限状态控制地图的显示。只有获得权限后才显示地图,否则显示请求权限的提示。这是标准且尊重用户的实现模式。
@Composable
fun LocationGate(permissions: MultiplePermissionsState) {
when {
permissions.allPermissionsGranted -> MapScreen()
else -> Column {
Text("We need location to show nearby places.")
Button(onClick = { permissions.launchMultiplePermissionRequest() }) {
Text("Allow location")
}
}
}
}快速检查
从 Android 12 开始,用户可以选择大致位置,而不是精确位置。这对您的权限请求意味着什么?
回顾
现在您已经了解如何负责任地请求位置权限:
- 在清单中声明大致/精确位置权限(只有在必要时才声明后台位置权限)。
- 使用 Activity Result API 或
accompanist-permissions在运行时请求权限。 - 同时请求精确和大致位置权限,以支持精确/大致位置切换。
- 显示请求理由,并将永久拒绝权限的用户引导至应用设置。
- 将后台位置作为单独且有充分理由的两步流程处理。
至此,地图与位置服务部分就完成了——您可以显示地图、定位用户、放置标记,并以正确的方式请求权限。
常见问题解答
「正确处理位置权限」课时是免费的吗?
是的 — 「正确处理位置权限」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 4 节课。
「正确处理位置权限」这节课中我会学到什么?
了解前台位置和精确位置 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Android Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「正确处理位置权限」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Android Academy 课中编写并运行代码吗?
能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。