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

TargetSDK=34(Android 14)启动时因定位前台服务权限崩溃

Android 14应用启动崩溃问题排查

问题现象

设备升级至Android 14后,从Play商店安装应用启动时崩溃,崩溃日志如下:

FATAL EXCEPTION: main
Process: com.myapp.appname, PID: 1518
java.lang.RuntimeException: Unable to create service com.myapp.StartupService: 
java.lang.SecurityException: Starting FGS with type location callerApp=ProcessRecord{95e97ef 
1518:com.myapp.appname/u0a370} 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 at 
android.app.ActivityThread.handleCreateService(ActivityThread.java:4664)

已在Manifest中添加相关权限,Beta测试阶段正常,尝试过类似方案仍未解决。

相关文件内容

Manifest文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.myapp"
    android:versionCode="1"
    android:versionName="1.0">

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

    <application
        android:name=".BaseApplication"
        android:allowBackup="false"
        android:fullBackupContent="false"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:resizeableActivity="false"
        android:theme="@style/appTheme"
        android:requestLegacyExternalStorage="true">
        <activity
            ...

        <!-- Service used when app is initializing on start up -->
        <service android:name="com.myapp.StartupService"
            android:foregroundServiceType="location"
            android:exported="false"
            >
        </service>
            ...
        <service
            android:name="com.myapp.chat.push.FcmListenerService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
            ...
    </application>
</manifest>

StartupService代码

class StartupService : IntentService {
    constructor() : super("StartupService") {}
    constructor(name: String?) : super(name) {}

    private val STARTUP_NOTIFICATION_ID = 42
    private fun createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        val name: CharSequence = getString(R.string.notification_channel_name_misc)
        val description = getString(R.string.notification_channel_description_misc)
        val importance = NotificationManager.IMPORTANCE_LOW
        val channel = NotificationChannel(
            AppConstants.NOTIFICATION_CHANNEL_MISCELLANEOUS,
            name,
            importance
        )
        channel.description = description
        channel.setSound(null, null)
        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this
        val notificationManager = getSystemService(
            NotificationManager::class.java
        )
        notificationManager.createNotificationChannel(channel)
    }

    @Deprecated("Deprecated in Java")
    override fun onCreate() {
        super.onCreate()
        createNotificationChannel()
        val builder = NotificationCompat.Builder(
            applicationContext,
            AppConstants.NOTIFICATION_CHANNEL_MISCELLANEOUS
        )
            .setContentTitle(getString(R.string.notification_startup_title))
            .setContentText(getString(R.string.notification_startup_text))
            .setSmallIcon(R.drawable.ic_notification_small)
            .setPriority(NotificationCompat.PRIORITY_LOW)
        startForeground(STARTUP_NOTIFICATION_ID, builder.build()) // THIS LINE IS THROWING THE ERROR
    }
    ...

问题分析与修复方案

从崩溃日志可知,Android 14(targetSDK=34)对定位类型前台服务的权限要求更严格:

  1. 需持有FOREGROUND_SERVICE_LOCATION权限(已添加)
  2. 需持有ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION权限(已添加)
  3. 核心问题:应用未处于「有权访问前台定位权限」的合格状态

关键原因

Android 14中,即使Manifest声明了定位权限,启动定位类型前台服务前,必须确保用户已授予前台定位权限(Android 12+后定位权限分为前台/后台,此处需前台权限)。你的StartupService在应用启动时直接调用startForeground,此时用户可能未授权,或应用启动场景不符合前台服务启动规则。

另外,IntentService已被标记为Deprecated,建议后续替换为JobIntentService或WorkManager,但这不是当前崩溃的直接原因。

具体修复步骤

  1. 前置权限请求:在启动StartupService前,先检查并请求定位权限,确认授权后再启动服务:

    // 在启动Service的入口处(如Activity的onCreate)检查权限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // 发起权限请求,在回调中确认授权后启动Service
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
            if (granted) {
                startService(Intent(this, StartupService::class.java))
            } else {
                // 处理权限拒绝逻辑,如引导用户到设置页开启权限
            }
        }.launch(Manifest.permission.ACCESS_FINE_LOCATION)
    } else {
        // 权限已授予,直接启动Service
        startService(Intent(this, StartupService::class.java))
    }
    
  2. 调整前台服务类型:如果StartupService不需要定位功能,移除Manifest中服务的android:foregroundServiceType="location"属性;若确实需要定位,确保权限前置逻辑正确。

  3. 适配Android 14前台服务启动规则:Android 14限制前台服务仅能在用户主动交互场景(如点击按钮)下启动,若应用是启动时自动触发服务,可考虑将初始化逻辑移到Activity中,或使用WorkManager执行后台初始化任务。

  4. 验证权限声明完整性:检查Manifest中定位权限是否被tools:node="remove"等属性意外移除,确保Android 12+的权限配置正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 13:27:05