TargetSDK=34(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)对定位类型前台服务的权限要求更严格:
- 需持有
FOREGROUND_SERVICE_LOCATION权限(已添加) - 需持有
ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION权限(已添加) - 核心问题:应用未处于「有权访问前台定位权限」的合格状态
关键原因
Android 14中,即使Manifest声明了定位权限,启动定位类型前台服务前,必须确保用户已授予前台定位权限(Android 12+后定位权限分为前台/后台,此处需前台权限)。你的StartupService在应用启动时直接调用startForeground,此时用户可能未授权,或应用启动场景不符合前台服务启动规则。
另外,IntentService已被标记为Deprecated,建议后续替换为JobIntentService或WorkManager,但这不是当前崩溃的直接原因。
具体修复步骤
前置权限请求:在启动
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)) }调整前台服务类型:如果
StartupService不需要定位功能,移除Manifest中服务的android:foregroundServiceType="location"属性;若确实需要定位,确保权限前置逻辑正确。适配Android 14前台服务启动规则:Android 14限制前台服务仅能在用户主动交互场景(如点击按钮)下启动,若应用是启动时自动触发服务,可考虑将初始化逻辑移到Activity中,或使用
WorkManager执行后台初始化任务。验证权限声明完整性:检查Manifest中定位权限是否被
tools:node="remove"等属性意外移除,确保Android 12+的权限配置正确。
内容的提问来源于stack exchange,提问作者petestmart

