Avviare un servizio in primo piano

Per avviare un servizio in primo piano dalla tua app, devi seguire due passaggi. Innanzitutto, devi avviare il servizio chiamando context.startForegroundService(). Poi, il servizio deve chiamare ServiceCompat.startForeground() per promuovere se stesso a servizio in primo piano.

Prerequisiti

A seconda del livello API di destinazione della tua app, esistono alcune limitazioni relative al momento in cui un'app può avviare un servizio in primo piano.

Avviare un servizio

Per avviare un servizio in primo piano, devi prima avviarlo come un servizio normale (non in primo piano):

Kotlin

val intent = Intent(...) // Build the intent for the service
context.startForegroundService(intent)

Java

Context context = getApplicationContext();
Intent intent = new Intent(...); // Build the intent for the service
context.startForegroundService(intent);

Punti chiave sul codice

  • Lo snippet di codice avvia un servizio. Tuttavia, il servizio non è ancora in esecuzione in primo piano. All'interno del servizio stesso, devi chiamare ServiceCompat.startForeground() per promuovere il servizio a servizio in primo piano.

Promuovere un servizio in primo piano

Una volta che un servizio è in esecuzione, devi chiamare ServiceCompat.startForeground() per richiedere che il servizio venga eseguito in primo piano. In genere, questo metodo viene chiamato nel metodo onStartCommand() del servizio.

ServiceCompat.startForeground() accetta i seguenti parametri:

I tipi di servizi in primo piano che passi a startForeground() tipi dichiarati nel file manifest, a seconda del caso d'uso specifico. Poi, se devi aggiungere altri tipi di servizi, puoi chiamare di nuovo startForeground().

Supponiamo, ad esempio, che un'app di fitness esegua un servizio di monitoraggio della corsa che ha sempre bisogno di informazioni location, ma potrebbe o meno riprodurre contenuti multimediali. Dovrai dichiarare sia location sia mediaPlayback nel file manifest. Se un utente inizia una corsa e vuole solo monitorare la sua posizione, la tua app deve chiamare startForeground() e passare solo l'autorizzazione ACCESS_FINE_LOCATION. Poi, se l'utente vuole iniziare a riprodurre l'audio, chiama di nuovo startForeground() e passa la combinazione bit a bit di tutti i tipi di servizi in primo piano (in questo caso, ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK).

L'esempio seguente mostra il codice che un servizio di videocamera utilizzerebbe per promuoversi a servizio in primo piano:

Kotlin

class MyCameraService: Service() {

  private fun startForeground() {
    // Before starting the service as foreground check that the app has the
    // appropriate runtime permissions. In this case, verify that the user has
    // granted the CAMERA permission.
    val cameraPermission =
            PermissionChecker.checkSelfPermission(this, Manifest.permission.CAMERA)
    if (cameraPermission != PermissionChecker.PERMISSION_GRANTED) {
        // Without camera permissions the service cannot run in the foreground
        // Consider informing user or updating your app UI if visible.
        stopSelf()
        return
    }

    try {
        val notification = NotificationCompat.Builder(this, "CHANNEL_ID")
            // Create the notification to display while the service is running
            .build()
        ServiceCompat.startForeground(
            /* service = */ this,
            /* id = */ 100, // Cannot be 0
            /* notification = */ notification,
            /* foregroundServiceType = */
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
            } else {
                0
            },
        )
    } catch (e: Exception) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
                && e is ForegroundServiceStartNotAllowedException) {
            // App not in a valid state to start foreground service
            // (e.g. started from bg)
        }
        // ...
    }
  }
}

Java

public class MyCameraService extends Service {

    private void startForeground() {
        // Before starting the service as foreground check that the app has the
        // appropriate runtime permissions. In this case, verify that the user
        // has granted the CAMERA permission.
        int cameraPermission =
            ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (cameraPermission == PackageManager.PERMISSION_DENIED) {
            // Without camera permissions the service cannot run in the
            // foreground. Consider informing user or updating your app UI if
            // visible.
            stopSelf();
            return;
        }

        try {
            Notification notification =
                new NotificationCompat.Builder(this, "CHANNEL_ID")
                    // Create the notification to display while the service
                    // is running
                    .build();
            int type = 0;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                type = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
            }
            ServiceCompat.startForeground(
                    /* service = */ this,
                    /* id = */ 100, // Cannot be 0
                    /* notification = */ notification,
                    /* foregroundServiceType = */ type
            );
        } catch (Exception e) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
                    e instanceof ForegroundServiceStartNotAllowedException
            ) {
                // App not in a valid state to start foreground service
                // (e.g started from bg)
            }
            // ...
        }
    }

    //...
}

Punti chiave sul codice

  • L'app ha già dichiarato nel file manifest di aver bisogno dell'autorizzazione CAMERA. Tuttavia, l'app deve anche verificare in fase di runtime che l'utente abbia concesso questa autorizzazione. Se l'app non dispone effettivamente delle autorizzazioni corrette, deve informare l'utente del problema.
  • Diversi tipi di servizi in primo piano sono stati introdotti con versioni diverse della piattaforma Android. Questo codice verifica la versione di Android in esecuzione e richiede le autorizzazioni appropriate.
  • Il codice verifica la presenza di ForegroundServiceStartNotAllowedException nel caso in cui stia tentando di avviare un servizio in primo piano in una situazione non consentita (ad esempio, se sta tentando di promuovere il servizio in primo piano mentre l'app è in background).