尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Android 13+ 后台定位权限适配:从 ACCESS_BACKGROUND_LOCATION 到前台服务 3 步实现
Android 13 后台定位权限适配从 ACCESS_BACKGROUND_LOCATION 到前台服务 3 步实现随着 Android 系统版本的迭代后台定位权限的管理变得越来越严格。从 Android 10 引入 ACCESS_BACKGROUND_LOCATION 权限到 Android 13 进一步细化权限申请流程开发者需要不断调整适配策略。本文将深入探讨如何在 Android 13 系统中实现合规且高效的后台定位功能并提供一套完整的代码实现方案。1. 权限声明与分级申请逻辑在 Android 10 及以上版本中定位权限被明确分为前台和后台两种类型。这种分级机制要求开发者在 Manifest 文件中正确声明权限并在运行时根据实际需求进行动态申请。1.1 Manifest 权限声明首先在 AndroidManifest.xml 中声明必要的权限!-- 基础网络权限 -- uses-permission android:nameandroid.permission.INTERNET / !-- 粗略定位权限 -- uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION / !-- 精确GPS定位权限 -- uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION / !-- Android 10 后台定位权限 -- uses-permission android:nameandroid.permission.ACCESS_BACKGROUND_LOCATION /对于 Android 10 及以上版本还需要添加前台服务权限uses-permission android:nameandroid.permission.FOREGROUND_SERVICE /1.2 运行时权限申请策略Android 13 引入了更细粒度的权限控制我们需要根据不同版本采取不同的申请策略private fun requestLocationPermissions() { val permissions mutableListOfString() // 基础定位权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ! PackageManager.PERMISSION_GRANTED) { permissions.add(Manifest.permission.ACCESS_FINE_LOCATION) } // Android 10 后台定位权限 if (Build.VERSION.SDK_INT Build.VERSION_CODES.Q ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) ! PackageManager.PERMISSION_GRANTED) { permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION) } if (permissions.isNotEmpty()) { ActivityCompat.requestPermissions(this, permissions.toTypedArray(), LOCATION_PERMISSION_REQUEST_CODE) } else { // 权限已授予开始定位 startLocationUpdates() } }提示Android 13 引入了新的运行时权限对话框系统会自动区分前台和后台定位权限的申请。开发者无需额外处理这种区分。1.3 权限申请结果处理在 onRequestPermissionsResult 中处理用户的选择override fun onRequestPermissionsResult( requestCode: Int, permissions: Arrayout String, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode LOCATION_PERMISSION_REQUEST_CODE) { val allGranted grantResults.all { it PackageManager.PERMISSION_GRANTED } if (allGranted) { startLocationUpdates() } else { // 处理权限被拒绝的情况 if (permissions.contains(Manifest.permission.ACCESS_BACKGROUND_LOCATION) Build.VERSION.SDK_INT Build.VERSION_CODES.Q) { // 后台权限被拒绝降级为前台定位 startForegroundLocationUpdates() } else { showPermissionDeniedDialog() } } } }2. 前台服务 (Foreground Service) 的创建与配置从 Android 8.0 (Oreo) 开始后台服务受到严格限制。要实现持续定位功能必须使用前台服务并显示持续通知。2.1 创建定位服务类class LocationForegroundService : Service() { private lateinit var locationClient: FusedLocationProviderClient private lateinit var locationCallback: LocationCallback override fun onCreate() { super.onCreate() locationClient LocationServices.getFusedLocationProviderClient(this) locationCallback object : LocationCallback() { override fun onLocationResult(result: LocationResult) { result.locations.lastOrNull()?.let { location - // 处理位置更新 handleNewLocation(location) } } } } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { startForeground(NOTIFICATION_ID, createNotification()) startLocationUpdates() return START_STICKY } private fun startLocationUpdates() { val locationRequest LocationRequest.create().apply { interval 10000 // 10秒更新间隔 fastestInterval 5000 // 最快5秒更新 priority LocationRequest.PRIORITY_HIGH_ACCURACY } try { locationClient.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) } catch (e: SecurityException) { // 处理权限异常 } } private fun createNotification(): Notification { val channelId if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) { createNotificationChannel() } else { } return NotificationCompat.Builder(this, channelId) .setContentTitle(位置服务运行中) .setContentText(正在后台获取位置信息) .setSmallIcon(R.drawable.ic_location_notification) .setPriority(NotificationCompat.PRIORITY_LOW) .build() } RequiresApi(Build.VERSION_CODES.O) private fun createNotificationChannel(): String { val channelId location_service_channel val channelName 位置服务 val channel NotificationChannel( channelId, channelName, NotificationManager.IMPORTANCE_LOW ).apply { description 用于持续获取位置信息的后台服务 } val manager getSystemService(NOTIFICATION_SERVICE) as NotificationManager manager.createNotificationChannel(channel) return channelId } override fun onBind(intent: Intent?): IBinder? null override fun onDestroy() { super.onDestroy() locationClient.removeLocationUpdates(locationCallback) } }2.2 启动和停止前台服务在 Activity 或 ViewModel 中控制服务的启停// 启动服务 val serviceIntent Intent(context, LocationForegroundService::class.java) if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) { startForegroundService(serviceIntent) } else { startService(serviceIntent) } // 停止服务 val stopIntent Intent(context, LocationForegroundService::class.java) stopService(stopIntent)2.3 通知配置最佳实践Android 13 对通知权限做了进一步限制需要特别注意在 AndroidManifest.xml 中添加通知权限声明uses-permission android:nameandroid.permission.POST_NOTIFICATIONS /在 Android 13 设备上运行时请求通知权限if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) { val notificationPermission Manifest.permission.POST_NOTIFICATIONS if (ContextCompat.checkSelfPermission(this, notificationPermission) ! PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(notificationPermission), NOTIFICATION_PERMISSION_REQUEST_CODE) } }确保通知内容清晰说明定位目的.setContentText(正在获取位置信息以提供运动轨迹记录服务)3. 电量优化 (Battery Optimization) 的豁免申请即使实现了前台服务Android 的电量优化机制仍可能限制后台定位。我们需要处理这些限制以确保定位功能的可靠性。3.1 检查电池优化状态fun isIgnoringBatteryOptimizations(context: Context): Boolean { val packageName context.packageName val powerManager context.getSystemService(POWER_SERVICE) as PowerManager return powerManager.isIgnoringBatteryOptimizations(packageName) }3.2 请求忽略电池优化fun requestIgnoreBatteryOptimizations(activity: Activity) { val intent Intent().apply { action Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS data Uri.parse(package:${activity.packageName}) } try { activity.startActivity(intent) } catch (e: ActivityNotFoundException) { // 处理异常 } }注意Google Play 对滥用电池优化豁免的应用有严格限制。确保只在确实需要持续后台定位的功能中使用此功能并在应用描述中明确说明原因。3.3 自适应定位策略为了平衡定位精度和电量消耗建议根据使用场景动态调整定位策略场景类型更新间隔精度要求适用API运动轨迹记录5-10秒高精度PRIORITY_HIGH_ACCURACY位置共享30-60秒中等精度PRIORITY_BALANCED_POWER_ACCURACY地理围栏按需触发低精度PRIORITY_LOW_POWERfun getLocationRequestBasedOnScenario(scenario: LocationScenario): LocationRequest { return LocationRequest.create().apply { when (scenario) { LocationScenario.FITNESS_TRACKING - { interval 5000 fastestInterval 2000 priority LocationRequest.PRIORITY_HIGH_ACCURACY } LocationScenario.LOCATION_SHARING - { interval 30000 fastestInterval 15000 priority LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY } LocationScenario.GEOFENCING - { interval 60000 fastestInterval 30000 priority LocationRequest.PRIORITY_LOW_POWER } } } }4. 兼容性处理与测试策略不同 Android 版本对后台定位的限制各不相同我们需要建立全面的兼容性处理方案。4.1 版本差异处理表Android 版本后台定位限制必须的适配措施 8.0无特别限制基本权限申请8.0-9.0后台执行限制使用前台服务10-12后台位置访问需特别权限添加 ACCESS_BACKGROUND_LOCATION13细粒度权限控制处理新的权限对话框4.2 测试要点为确保功能在各种环境下正常工作建议测试以下场景权限组合测试仅授予前台定位权限授予前后台定位权限拒绝所有定位权限系统设置测试开启/关闭系统定位服务开启/关闭电池优化开启/关闭应用的后台限制实际使用场景测试应用在前台运行时的定位应用在后台运行时的定位设备重启后的自动恢复4.3 调试技巧在开发过程中可以使用以下 ADB 命令模拟不同条件# 模拟授予定位权限 adb shell pm grant package_name android.permission.ACCESS_FINE_LOCATION adb shell pm grant package_name android.permission.ACCESS_BACKGROUND_LOCATION # 模拟撤销权限 adb shell pm revoke package_name android.permission.ACCESS_FINE_LOCATION # 启用/禁用电池优化 adb shell dumpsys deviceidle whitelist package_name adb shell dumpsys deviceidle whitelist -package_name实现一个健壮的后台定位功能需要全面考虑权限管理、服务生命周期和电量优化等多个方面。通过本文介绍的三步策略开发者可以构建出符合最新 Android 规范的位置感知应用。在实际项目中建议结合用户反馈不断优化定位策略在功能需求和设备资源消耗之间找到最佳平衡点。
RELATED

相关推荐

Unity WebGL音频播放优化:HTML5 Audio替代方案实战

Unity WebGL音频播放优化:HTML5 Audio替代方案实战

1. 项目概述:当Unity WebGL音频遇上现实如果你和我一样,在Unity里做WebGL项目,并且对音频播放有那么一点点要求——比如需要精准控制播放进度、实现无缝循环、或者只是单纯地不想听到那烦人的“啪嗒”一声的循环爆音——那你很可能已经和Unit…

📅 2026/9/29 8:32:45
Unity Android游戏CPU占用率100%优化实战:从定位到解决

Unity Android游戏CPU占用率100%优化实战:从定位到解决

1. 项目概述:当你的Unity游戏在手机上“发烧”了最近在项目群里,好几个开发者朋友都在吐槽同一个问题:自己做的Unity游戏,在Android手机上跑起来之后,手机烫得能煎鸡蛋,用性能监测工具一看,好家…

📅 2026/11/7 22:36:45
虚幻引擎5 Nanite完整启用与优化指南:从原理到实战

虚幻引擎5 Nanite完整启用与优化指南:从原理到实战

1. 项目概述:为什么我们需要关注Nanite?如果你最近在捣鼓虚幻引擎5,尤其是想把手头的项目画质和性能再往上拔一拔,那“Nanite”这个词你肯定绕不过去。它不是什么新出的插件,而是UE5最核心的“黑科技”之一&#xff0c…

📅 2026/11/12 2:10:08
MORE NEWS

更多资讯

📰

汝州电工证办理条件2026河南最新政策全攻略

汝州电工证办理条件2026河南最新政策全攻略 你是不是还在为不知道去哪报名、怕被中介坑而发愁?2026年河南最新政策对电工证办理条件有了明确要求,本文将从汝州电工证办理条件出发,帮你理清流程、避开陷阱,稳稳拿到电工证。…

📰

合肥建筑电工证年审怎么考,真实经历告诉你别被中介坑

合肥建筑电工证年审怎么考,真实经历告诉你别被中介坑 你是不是也跟很多商丘的建筑工人一样,听说要年审合肥建筑电工证,心里直打鼓?不知道去哪报名,怕被中介骗钱?别急,我给你讲讲我身边老李的真实经历,他就是去年刚完成合肥建筑电工证年审的,现在在工…

📰

船检局电工证全国通用吗?别被中介坑了,听我给你说清楚

船检局电工证全国通用吗?别被中介坑了,听我给你说清楚 你是不是也和我一样,刚听说要考个 船检局电工证 ,就心里一紧:这证到底能不能全国用?去哪报名?会不会被中介骗?别急,今天我就用自己在河南信阳水利工程项目上的经历,给你讲讲这个证的来龙去脉…

📰

黔江电工证考试怎么考?郑州报考避坑指南全解析

黔江电工证考试怎么考?郑州报考避坑指南全解析 你是不是也正被“急需特种作业证才能上岗找工作”这个问题搞得焦头烂额?别急,今天咱们就来聊聊 黔江电工证考试 怎么考,报考前有哪些避坑指南,特别是从 郑州报考避坑指南…

📰

电工证 桂城有效期多久网上查询

电工证 桂城有效期多久网上查询 学历不高怕报不上名?电工证 桂城报名门槛其实没你想象的高,网上查询也能搞定,关键是别踩坑! 电工证 桂城有效期多久网上查询 Q1:电工证 桂城有效期是多久?如何网上查询? 电工证 桂城的有效期通常是 6年…

📰

重庆电工证免考试2026河南最新政策来了,别再被中介骗了

重庆电工证免考试2026河南最新政策来了,别再被中介骗了 你是不是也在犹豫,重庆电工证能不能免考试?去哪报名最靠谱?别急,我来给你说清楚,2026年河南最新政策已经出来了,很多人因为信息不对称被中介坑,其实正规渠道报名真的没那么难。…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬