Search code examples
androidkotlinandroid-manifestandroid-permissionsforeground-service

Starting TGS with type location ... TargetSDK=34 - Android 14 Crash on Startup


I updated to Android 14 last night. Once I attempted to install our app (from Play Store) on my device I started getting a crash upon opening the app

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)

I've tried adding some of the newly required permissions into my manifest. When everything was tested on the beta it worked fine (as far as I know).

I've also tried the solutions shown in this question: Foreground Service crashing on Android 14, which seems very similar.

Here are my files. I tried to include what I thought was necessary. Let me know if there are pieces that help provide more context.

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>

Startup Service

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
    }
    ...

Solution

  • here is the complete demo how to do it when dealing with location with boot compatible forground service if you don't wan't to start service after the device restart then you could exclude code for

    ACCESS_BACKGROUND_LOCATION

    from the demo app

    https://github.com/JigarRangani/ForGroundLocation