Servizi in primo piano

I servizi in primo piano eseguono operazioni visibili all'utente.

I servizi in primo piano mostrano una notifica nella barra di stato per informare gli utenti che la tua app sta eseguendo un'attività in primo piano e consuma risorse di sistema.

Ecco alcuni esempi di app che utilizzano i servizi in primo piano:

  • Un'app di lettore musicale che riproduce musica in un servizio in primo piano. La notifica potrebbe mostrare il brano attualmente in riproduzione.
  • Un'app per il fitness che registra l'esecuzione di un utente in un servizio in primo piano, dopo aver ricevuto l'autorizzazione dall'utente. La notifica potrebbe mostrare la distanza percorsa dall'utente durante la sessione di fitness corrente.

Utilizza un servizio in primo piano solo quando la tua app deve eseguire un'attività che sia evidente dall'utente, anche quando non interagisce direttamente con l'app. Se l'azione è di importanza sufficientemente scarsa da voler utilizzare una notifica con priorità minima, crea invece un'attività in background.

Questo documento descrive l'autorizzazione richiesta per l'utilizzo dei servizi in primo piano e come avviare un servizio in primo piano e rimuoverlo dallo sfondo. Descrive inoltre come associare determinati casi d'uso ai tipi di servizi in primo piano e le limitazioni dell'accesso che vengono applicate quando si avvia un servizio in primo piano da un'app in esecuzione in background.

L'utente può ignorare la notifica per impostazione predefinita

A partire da Android 13 (livello API 33), gli utenti possono ignorare la notifica associata a un servizio in primo piano per impostazione predefinita. Per farlo, gli utenti eseguono un gesto di scorrimento sulla notifica. In genere, la notifica non viene ignorata, a meno che il servizio in primo piano non venga interrotto o rimosso da quest'ultimo.

Se vuoi che la notifica non possa essere ignorata dall'utente, trasmetti true al metodo setOngoing() quando crei la notifica utilizzando Notification.Builder.

Servizi che mostrano immediatamente una notifica

Se un servizio in primo piano ha almeno una delle seguenti caratteristiche, il sistema mostra la notifica associata subito dopo l'avvio del servizio, anche sui dispositivi con Android 12 o versioni successive:

Su Android 13 (livello API 33) o versioni successive, se l'utente nega l'autorizzazione alle notifiche, vedrà comunque gli avvisi relativi ai servizi in primo piano in Task Manager, ma non nel riquadro a scomparsa delle notifiche.

Dichiara i servizi in primo piano nel tuo file manifest

Nel file manifest dell'app, dichiara ciascuno dei servizi in primo piano dell'app con un elemento <service>. Per ogni servizio, utilizza un attributo android:foregroundServiceType per dichiarare il tipo di lavoro svolto dal servizio.

Ad esempio, se la tua app crea un servizio in primo piano per riprodurre musica, potresti dichiarare il servizio nel seguente modo:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
  <application ...>

    <service
        android:name=".MyMediaPlaybackService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="false">
    </service>
  </application>
</manifest>

Se al servizio si applicano più tipi, separali con l'operatore |. Ad esempio, un servizio che utilizza la fotocamera e il microfono dichiarerebbe in questo modo:

android:foregroundServiceType="camera|microphone"

Richiedi le autorizzazioni per i servizi in primo piano

Le app destinate ad Android 9 (livello API 28) o versioni successive e che utilizzano servizi in primo piano devono richiedere FOREGROUND_SERVICE nel file manifest dell'app, come mostrato nel seguente snippet di codice. Si tratta di un'autorizzazione normale, pertanto il sistema la concede automaticamente all'app richiedente.

Inoltre, se l'app ha come target il livello API 34 o superiore, deve richiedere il tipo di autorizzazione appropriato per il tipo di lavoro che il servizio in primo piano svolgerà. Ogni tipo di servizio in primo piano ha un tipo di autorizzazione corrispondente. Ad esempio, se un'app avvia un servizio in primo piano che utilizza la fotocamera, devi richiedere le autorizzazioni FOREGROUND_SERVICE e FOREGROUND_SERVICE_CAMERA. Queste sono tutte autorizzazioni normali, quindi il sistema le concede automaticamente se sono elencate nel manifest.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>

    <application ...>
        ...
    </application>
</manifest>

Prerequisiti per i servizi in primo piano

A partire da Android 14 (livello API 34), quando avvii un servizio in primo piano, il sistema controlla se sono presenti prerequisiti specifici in base al tipo di servizio. Ad esempio, se provi ad avviare un servizio in primo piano di tipo location, il sistema controlla per assicurarsi che la tua app abbia già l'autorizzazione ACCESS_COARSE_LOCATION o ACCESS_FINE_LOCATION. In caso contrario, il sistema visualizza SecurityException.

Per questo motivo, devi confermare che i prerequisiti richiesti siano soddisfatti prima di avviare un servizio in primo piano. La documentazione relativa al tipo di servizio in primo piano elenca i prerequisiti richiesti per ogni tipo di servizio in primo piano.

Avviare un servizio in primo piano

Prima di richiedere al sistema di eseguire un servizio come servizio in primo piano, avvia il servizio stesso:

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);

All'interno del servizio, di solito in onStartCommand(), puoi richiedere che il servizio venga eseguito in primo piano. Per farlo, chiama il numero ServiceCompat.startForeground() (disponibile su Androidx-core 1.12 e versioni successive). Questo metodo prevede i seguenti parametri:

  • Il servizio
  • Un numero intero positivo che identifica in modo univoco la notifica nella barra di stato
  • L'oggetto Notification stesso
  • I tipi di servizi in primo piano che identificano il lavoro svolto dal servizio

Questi tipi potrebbero essere un sottoinsieme dei tipi dichiarati nel file manifest, a seconda del caso d'uso specifico. Quindi, se devi aggiungere altri tipi di servizi, puoi chiamare di nuovo startForeground().

Ad esempio, supponiamo che un'app per l'attività fisica esegua un servizio di tracker della corsa che ha sempre bisogno di informazioni su location, ma potrebbe o meno dover riprodurre contenuti multimediali. Nel file manifest devi dichiarare sia location sia mediaPlayback. Se un utente avvia un'esecuzione e vuole semplicemente che la propria posizione venga monitorata, la tua app dovrebbe chiamare startForeground() e trasmettere solo l'autorizzazione ACCESS_FINE_LOCATION. Quindi, se l'utente vuole iniziare a riprodurre l'audio, richiama di nuovo startForeground() e trasmetti la combinazione a bit di tutti i tipi di servizi in primo piano (in questo caso, ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK).

Ecco un esempio che avvia un servizio in primo piano della fotocamera:

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

    //...
}

Rimuovere un servizio dal primo piano

Per rimuovere il servizio dal primo piano, chiama stopForeground(). Questo metodo utilizza un valore booleano che indica se rimuovere anche la notifica nella barra di stato. Tieni presente che il servizio continua a essere eseguito.

Se interrompi il servizio mentre viene eseguito in primo piano, la relativa notifica viene rimossa.

Gestire l'interruzione avviata dall'utente delle app che eseguono servizi in primo piano

Nella parte inferiore del riquadro a scomparsa delle notifiche è presente un pulsante che indica il
    numero di app attualmente in esecuzione in background. Quando premi questo pulsante, viene visualizzata una finestra di dialogo che elenca i nomi delle diverse app. Il pulsante Interrompi si trova a destra di ogni app
Figura 1. Flusso di lavoro di Task Manager sui dispositivi con Android 13 o versioni successive.

A partire da Android 13 (livello API 33), gli utenti possono completare un flusso di lavoro dal riquadro a scomparsa delle notifiche per interrompere un'app con servizi in primo piano in esecuzione, indipendentemente dalla versione dell'SDK target dell'app. Questa autorizzazione, denominata Task Manager, mostra un elenco di app che attualmente eseguono un servizio in primo piano.

Questo elenco è denominato App attive. Accanto a ogni app c'è un pulsante Interrompi. La Figura 1 mostra il flusso di lavoro di Tasks Manager su un dispositivo che esegue Android 13.

Quando l'utente preme il pulsante Interrompi accanto alla tua app in Task Manager, si verificano le seguenti azioni:

  • Il sistema rimuove l'app dalla memoria. Di conseguenza, l'intera app si interrompe, non solo il servizio in primo piano in esecuzione.
  • Il sistema rimuove lo stack di attività dell'app.
  • La riproduzione dei contenuti multimediali si interrompe.
  • La notifica associata al servizio in primo piano viene rimossa.
  • L'app rimane nella cronologia.
  • I job pianificati vengono eseguiti all'orario pianificato.
  • Le sveglie suonano nell'orario o nella finestra temporale programmata.

Per verificare che l'app si comporti come previsto durante e dopo che un utente l'ha interrotta, esegui questo comando ADB in una finestra del terminale:

adb shell cmd activity stop-app PACKAGE_NAME

Esenzioni

Il sistema offre diversi livelli di esenzioni per alcuni tipi di app, descritti nelle sezioni seguenti.

Le esenzioni si intendono per app, non per processo. Se il sistema esclude un processo in un'app, sono esenti anche tutti gli altri processi in quell'app.

Esenzioni dalla visualizzazione in Task Manager

Le seguenti app possono eseguire un servizio in primo piano e non essere visualizzate in Task Manager:

Esenzioni dovute all'interruzione dell'accesso da parte degli utenti

Quando i seguenti tipi di app eseguono un servizio in primo piano, vengono visualizzati in Task Manager, ma accanto al nome dell'app non è presente il pulsante Interrompi che l'utente può toccare:

Usa API create ad hoc anziché servizi in primo piano

Per molti casi d'uso, esistono API Jetpack o della piattaforma che è possibile usare per svolgere operazioni per le quali altrimenti si potrebbe usare un servizio in primo piano. Se esiste un'API adatta creata per scopi specifici, dovresti quasi sempre usarla anziché un servizio in primo piano. Le API dedicate spesso forniscono funzionalità aggiuntive specifiche per i casi d'uso che altrimenti dovresti creare in autonomia. Ad esempio, l' API Bubbles gestisce la logica UI complessa per le app di messaggistica che devono implementare funzionalità di bolle di chat.

La documentazione per i tipi di servizi in primo piano elenca buone alternative da utilizzare al posto dei servizi in primo piano.

Limitazioni relative all'avvio di un servizio in primo piano in background

Le app destinate ad Android 12 o versioni successive non possono avviare servizi in primo piano mentre l'app è in esecuzione in background, ad eccezione di alcuni casi speciali. Se un'app tenta di avviare un servizio in primo piano mentre l'app viene eseguita in background e il servizio in primo piano non soddisfa uno dei casi eccezionali, il sistema genera un ForegroundServiceStartNotAllowedException.

Inoltre, se un'app vuole avviare un servizio in primo piano che richiede autorizzazioni durante l'uso (ad esempio, autorizzazioni di sensori del corpo, fotocamera, microfono o posizione), non può creare il servizio mentre è in background, anche se rientra in una delle esenzioni dalle limitazioni relative all'avvio in background. Il motivo è spiegato nella sezione Limitazioni relative all'avvio di servizi in primo piano che richiedono autorizzazioni mentre sono in uso.

Esenzioni dalle limitazioni relative all'avvio in background

Nelle seguenti situazioni, la tua app può avviare servizi in primo piano anche quando l'app è in esecuzione in background:

Limitazioni relative all'avvio di servizi in primo piano che richiedono autorizzazioni durante l'uso

Su Android 14 (livello API 34) o versioni successive, devi tenere presente alcune situazioni speciali se avvii un servizio in primo piano che richiede autorizzazioni durante l'uso.

Se la tua app ha come target Android 14 o versioni successive, il sistema operativo controlla quando crei un servizio in primo piano per verificare che l'app disponga di tutte le autorizzazioni appropriate per il tipo di servizio in questione. Ad esempio, quando crei un servizio in primo piano di tipo microfono, il sistema operativo verifica che la tua app attualmente disponga dell'autorizzazione RECORD_AUDIO. Se non disponi di questa autorizzazione, il sistema genera un SecurityException.

Per quanto riguarda le autorizzazioni durante l'uso, è possibile che si verifichino problemi. Se la tua app dispone di un'autorizzazione durante l'uso, può averla soltanto mentre è in primo piano. Ciò significa che se la tua app è in background e tenta di creare un servizio in primo piano di tipo fotocamera, posizione o microfono, il sistema rileva che attualmente l'app non dispone delle autorizzazioni richieste e genera un SecurityException.

In modo simile, se la tua app è in background e crea un servizio per la salute che richiede l'autorizzazione BODY_SENSORS_BACKGROUND, al momento l'app non dispone di questa autorizzazione e il sistema genera un'eccezione. Questo non si applica se si tratta di un servizio sanitario che richiede autorizzazioni diverse, ad esempio ACTIVITY_RECOGNITION. La chiamata a PermissionChecker.checkSelfPermission() non impedisce questo problema. Se la tua app ha un'autorizzazione durante l'uso e chiama checkSelfPermission() per verificare se dispone di tale autorizzazione, il metodo restituisce PERMISSION_GRANTED anche se l'app è in background. Quando il metodo restituisce PERMISSION_GRANTED, significa che l'app ha questa autorizzazione mentre l'app è in uso."

Per questo motivo, se il servizio in primo piano ha bisogno di un'autorizzazione durante l'utilizzo, devi chiamare Context.startForegroundService() o Context.bindService() mentre la tua app ha un'attività visibile, a meno che il servizio non rientri in una delle esenzioni definite.

Esenzioni dalle limitazioni relative alle autorizzazioni durante l'uso

In alcune situazioni, anche se un servizio in primo piano viene avviato mentre l'app viene eseguita in background, può comunque accedere alle informazioni su posizione, fotocamera e microfono mentre l'app è in esecuzione in primo piano ("durante l'uso").

In queste stesse situazioni, se il servizio dichiara un tipo di servizio in primo piano di location ed viene avviato da un'app che dispone dell'autorizzazione ACCESS_BACKGROUND_LOCATION, il servizio può accedere alle informazioni sulla posizione in qualsiasi momento, anche quando l'app viene eseguita in background.

Il seguente elenco contiene le seguenti situazioni:

  • Un componente di sistema avvia il servizio.
  • Il servizio inizia interagendo con i widget dell'app.
  • Il servizio inizia interagendo con una notifica.
  • Il servizio viene avviato come un PendingIntent inviato da un'app diversa e visibile.
  • Il servizio viene avviato da un'app che è un controller dei criteri dei dispositivi in esecuzione in modalità proprietario del dispositivo.
  • Il servizio viene avviato da un'app che fornisce l'VoiceInteractionService.
  • Il servizio viene avviato da un'app che dispone dell'autorizzazione con privilegi START_ACTIVITIES_FROM_BACKGROUND.
Determina quali servizi sono interessati nella tua app

Quando testi la tua app, avvia i relativi servizi in primo piano. Se un servizio avviato ha limitato l'accesso alla posizione, al microfono e alla fotocamera, in Logcat viene visualizzato il seguente messaggio:

Foreground service started from background can not have \
location/camera/microphone access: service SERVICE_NAME