You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Target SDK34定位前台服务启动崩溃问题求助

问题描述

我使用类型为location的前台服务获取位置信息,设置每2分钟执行一次,服务周期性启停,要求在前后台均持续运行。已在清单中配置以下权限:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

但当应用处于后台且GPS定位关闭时,启动下一次前台服务位置更新时出现崩溃,异常信息如下:

Fatal Exception: java.lang.RuntimeException
Unable to create service com.lystloc.utils.services.tracking.LocationUpdateService: java.lang.SecurityException: Starting FGS with type location callerApp=ProcessRecord{c137f46 23529:com.lystloc/u0a332} targetSDK=34 requires permissions: all of the permissions allOf=true [android.permission.FOREGROUND_SERVICE_LOCATION] any of the permissions allOf=false [android.permission.ACCESS_COARSE_LOCATION, android.permission.ACCESS_FINE_LOCATION] and the app must be in the eligible state/exemptions to access the foreground only permission
解决方案

核心问题

这是Android 14(TargetSDK 34)对位置型前台服务(FGS)的严格权限限制导致的:

  • 即使清单声明了位置权限,当GPS关闭时,系统会判定应用无获取位置的必要,此时后台启动位置型FGS会直接触发SecurityException
  • 后台状态下,启动位置型FGS不仅需要持有动态位置权限,还需要系统认为应用处于「有资格获取前台位置」的状态,GPS关闭直接打破了这个条件

具体修复步骤

  1. 启动服务前做双重校验
    在触发LocationUpdateService启动逻辑前,必须检查两个关键条件:

    • 动态位置权限是否授予:确认ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION已被用户授予(清单声明≠已授权)
    • 设备定位是否开启:通过LocationManager判断GPS或网络定位是否可用
      任一条件不满足时,不要启动服务,可弹窗提示用户开启定位,或延后下一次任务执行。
  2. 适配Android 14的FGS启动规则
    Android 14对后台启动位置型FGS的豁免条件有明确要求,即使你持有ACCESS_BACKGROUND_LOCATION权限,当GPS关闭时系统也会拒绝启动服务,所以必须确保定位可用后再执行启动操作。

  3. 修改启动逻辑示例
    替换原有的服务启动代码,加入前置校验:

    // 获取LocationManager实例
    val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
    
    // 检查动态位置权限
    val hasValidLocationPerm = ContextCompat.checkSelfPermission(
        this,
        Manifest.permission.ACCESS_FINE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED ||
            ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
    
    // 检查定位是否开启(GPS或网络定位均可)
    val isLocationEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
            locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
    
    if (hasValidLocationPerm && isLocationEnabled) {
        // 满足条件,启动前台服务
        val intent = Intent(this, LocationUpdateService::class.java)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(intent)
        } else {
            startService(intent)
        }
    } else {
        // 处理异常情况:发送通知引导用户开启定位
        val notificationIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
        val pendingIntent = PendingIntent.getActivity(
            this,
            0,
            notificationIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        val notification = NotificationCompat.Builder(this, "location_channel")
            .setContentTitle("定位服务已关闭")
            .setContentText("请开启定位以继续获取位置信息")
            .setSmallIcon(R.drawable.ic_location)
            .setContentIntent(pendingIntent)
            .build()
        NotificationManagerCompat.from(this).notify(1, notification)
    }
    
  4. 添加异常捕获
    即使做了前置校验,仍可能存在极端场景导致启动失败,建议包裹try-catch避免崩溃:

    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(intent)
        } else {
            startService(intent)
        }
    } catch (e: SecurityException) {
        Log.e("LocationService", "启动前台服务失败: ${e.message}")
        // 可加入降级逻辑,比如延后10分钟再尝试
    }
    

内容的提问来源于stack exchange,提问作者bala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 00:40:56