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 sta utilizzando 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 la corsa di un utente in un servizio in primo piano, dopo aver ricevuto l'autorizzazione dall'utente. La notifica potrebbe mostrare la distanza che l'utente ha percorso durante la sessione di fitness in corso.
Utilizza un servizio in primo piano solo quando la tua app deve eseguire un'attività visibile all'utente, anche quando non interagisce direttamente con l'app. Se l'azione è di importanza sufficientemente bassa 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 dal background. Inoltre, descrive come associare determinati casi d'uso ai tipi di servizi in primo piano e le limitazioni di accesso che si applicano quando avvii 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. A questo scopo, gli utenti eseguono un gesto di scorrimento sulla notifica. Tradizionalmente, la notifica non viene chiusa a meno che il servizio in primo piano non venga interrotto o rimosso dall'attività in primo piano.
Se vuoi che la notifica non sia ignorabile dall'utente, passa true
al metodo setOngoing()
quando crei la notifica utilizzando Notification.Builder
.
Servizi che mostrano immediatamente una notifica
Se un servizio in primo piano presenta almeno una delle seguenti caratteristiche, il sistema mostra la notifica associata immediatamente dopo l'avvio del servizio, anche sui dispositivi con Android 12 o versioni successive:
- Il servizio è associato a una notifica che include pulsanti di azione.
- Il servizio ha un
foregroundServiceType
dimediaPlayback
,mediaProjection
ophoneCall
. - Il servizio fornisce un caso d'uso relativo a chiamate, navigazione o riproduzione di contenuti multimediali, come definito nell'attributo categoria della notifica.
- Il servizio ha disattivato la modifica del comportamento passando
FOREGROUND_SERVICE_IMMEDIATE
insetForegroundServiceBehavior()
durante la configurazione della notifica.
Su Android 13 (livello API 33) o versioni successive, se l'utente nega l'autorizzazione di notifica, visualizza comunque le notifiche relative ai servizi in primo piano nel Task Manager, ma non le vede nella barra delle notifiche.
Dichiara i servizi in primo piano nel file manifest
Nel file manifest della tua app, dichiara ogni servizio in primo piano 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 che riproduce 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 tuo servizio si applicano più tipi, separali con l'operatore |
. Ad esempio, un servizio che utilizza la fotocamera e il microfono lo dichiarerebbe come segue:
android:foregroundServiceType="camera|microphone"
Richiedi le autorizzazioni per i servizi in primo piano
Le app che hanno come target Android 9 (livello API 28) o versioni successive e utilizzano i servizi in primo piano devono richiedere FOREGROUND_SERVICE
nel file manifest dell'app, come mostrato nel seguente snippet di codice. Si tratta di una normale permissione, pertanto il sistema la concede automaticamente all'app che la richiede.
Inoltre, se l'app ha come target il livello API 34 o versioni successive, deve richiedere il tipo di autorizzazione appropriato per il tipo di attività che verrà svolta dal servizio in primo piano. 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 sia le autorizzazioni FOREGROUND_SERVICE
sia FOREGROUND_SERVICE_CAMERA
. Si tratta di autorizzazioni normali, pertanto il sistema le concede automaticamente se sono elencate nel file 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 la presenza di prerequisiti specifici in base al tipo di servizio. Ad esempio, se provi a avviare un servizio in primo piano di tipo location
, il sistema verifica che la tua app disponga già dell'autorizzazione ACCESS_COARSE_LOCATION
o ACCESS_FINE_LOCATION
. In caso contrario, il sistema genera un errore SecurityException
.
Per questo motivo, devi verificare 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, in genere in onStartCommand()
, puoi richiedere che venga eseguito in primo piano. Per farlo, chiama
ServiceCompat.startForeground()
(disponibile in androidx-core 1.12 e versioni successive). Questo metodo accetta 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. Se devi aggiungere altri tipi di servizi, puoi chiamare di nuovo startForeground()
.
Ad esempio, supponiamo che un'app per il fitness esegua un servizio di monitoraggio della corsa che richiede sempre informazioni location
, ma potrebbe o meno dover riprodurre contenuti multimediali. Devi dichiarare sia location
che mediaPlayback
nel file manifest. Se un
utente avvia una corsa e vuole solo che la sua posizione venga monitorata, la tua app deve chiamare
startForeground()
e passare solo l'autorizzazione ACCESS_FINE_LOCATION
. Poi, se l'utente vuole avviare la riproduzione audio, chiama di nuovo startForeground()
e passa la combinazione bitwise 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 accetta un valore booleano che indica se rimuovere anche la notifica della barra di stato. Tieni presente che il servizio continua a funzionare.
Se interrompi il servizio mentre è in esecuzione in primo piano, la relativa notifica viene rimossa.
Gestire l'interruzione delle app che eseguono servizi in primo piano avviata dall'utente
A partire da Android 13 (livello API 33), gli utenti possono completare un flusso di lavoro dal riquadro delle notifiche per interrompere un'app con servizi in primo piano in esecuzione, indipendentemente dalla versione dell'SDK target dell'app. Questa funzionalità, chiamata Task Manager, mostra un elenco di app che attualmente eseguono un servizio in primo piano.
Questo elenco è denominato App attive. Accanto a ogni app è presente un pulsante Interrompi. La Figura 1 mostra il flusso di lavoro di Task Manager su un dispositivo con 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 arresta, non solo il servizio in primo piano in esecuzione.
- Il sistema rimuove la pila di attività precedenti dell'app.
- La riproduzione di contenuti multimediali viene interrotta.
- La notifica associata al servizio in primo piano viene rimossa.
- L'app rimane nella cronologia.
- I job pianificati vengono eseguiti all'ora programmata.
- Le sveglie suonano all'ora o nell'intervallo di tempo programmato.
Per verificare che l'app si comporti come previsto durante e dopo l'interruzione da parte dell'utente, esegui il seguente comando ADB in una finestra del terminale:
adb shell cmd activity stop-app PACKAGE_NAME
Esenzioni
Il sistema prevede diversi livelli di esenzione per determinati tipi di app, descritti nelle sezioni seguenti.
Le esenzioni si applicano per app, non per processo. Se il sistema esenta un processo in un'app, lo sono anche tutti gli altri processi dell'app.
Esenzioni dalla visualizzazione in Task Manager
Le seguenti app possono eseguire un servizio in primo piano e non comparire affatto in Task Manager:
- App a livello di sistema
- App di sicurezza, ovvero app con il ruolo
ROLE_EMERGENCY
- Dispositivi in modalità demo
Esenzioni dall'interruzione da parte degli utenti
Quando i seguenti tipi di app eseguono un servizio in primo piano, vengono visualizzati in Task Manager, ma non è presente il pulsante Interrompi accanto al nome dell'app che l'utente può toccare:
- App per il proprietario del dispositivo
- App del proprietario del profilo
- App permanenti
- App con il ruolo
ROLE_DIALER
Utilizza API create appositamente anziché servizi in primo piano
Per molti casi d'uso, esistono API di piattaforma o Jetpack che puoi utilizzare per svolgere attività per le quali potresti altrimenti utilizzare un servizio in primo piano. Se esiste un'API appositamente progettata, dovresti quasi sempre utilizzarla anziché un servizio in primo piano. Le API create appositamente spesso forniscono funzionalità aggiuntive specifiche per i casi d'uso che altrimenti dovresti creare autonomamente. Ad esempio, l' API Bubbles gestisce la logica complessa dell'interfaccia utente per le app di messaggistica che devono implementare le funzionalità delle bolle di chat.
La documentazione relativa ai tipi di servizi in primo piano elenca ottime alternative da utilizzare al posto dei servizi in primo piano.
Restrizioni relative all'avvio di un servizio in primo piano dal background
Le app che hanno come target 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 è in esecuzione 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'utilizzo (ad esempio autorizzazioni per il sensore di movimento, la fotocamera, il microfono o la posizione), non può crearlo mentre è in background, anche se rientra in una delle esenzioni dalle limitazioni di avvio in background. Il motivo è spiegato nella sezione Limitazioni all'avvio di servizi in primo piano che richiedono autorizzazioni durante l'utilizzo.
Esenzioni dalle limitazioni relative all'avvio in background
Nelle seguenti situazioni, la tua app può avviare servizi in primo piano anche mentre è in esecuzione in background:
- L'app passa da uno stato visibile all'utente, ad esempio un'attività.
- L'app può avviare un'attività in background, tranne nel caso in cui l'app abbia un'attività nello stack secondario di un'attività esistente.
La tua app riceve un messaggio con priorità elevata utilizzando Firebase Cloud Messaging.
L'utente esegue un'azione su un elemento dell'interfaccia utente relativo alla tua app. Ad esempio, potrebbe interagire con una bolla, una notifica, un widget o un'attività.
La tua app richiama una sveglia esatta per completare un'azione richiesta dall'utente.
La tua app è il metodo di input corrente del dispositivo.
La tua app riceve un evento correlato al geofencing o alla transizione di riconoscimento attività.
Dopo il riavvio del dispositivo e la ricezione dell'azione di intent
ACTION_BOOT_COMPLETED
,ACTION_LOCKED_BOOT_COMPLETED
oACTION_MY_PACKAGE_REPLACED
in un broadcast receiver.La tua app riceve l'azione di intent
ACTION_TIMEZONE_CHANGED
,ACTION_TIME_CHANGED
oACTION_LOCALE_CHANGED
in un broadcast receiver.La tua app riceve l'evento
ACTION_TRANSACTION_DETECTED
daNfcService
.App con determinati ruoli o autorizzazioni di sistema, ad esempio proprietari del dispositivo e proprietari del profilo.
La tua app utilizza Companion Device Manager e dichiara l'autorizzazione
REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
o l'autorizzazioneREQUEST_COMPANION_RUN_IN_BACKGROUND
. Se possibile, utilizzaREQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
.L'utente disattiva le ottimizzazioni della batteria per la tua app.
La tua app dispone dell'autorizzazione
SYSTEM_ALERT_WINDOW
. Nota: se la tua app ha come target Android 15 o versioni successive, deve disporre dell'autorizzazioneSYSTEM_ALERT_WINDOW
e al momento deve avere una finestra in overlay visibile.
Limitazioni per l'avvio di servizi in primo piano che richiedono autorizzazioni durante l'utilizzo
Su Android 14 (livello API 34) o versioni successive, devi tenere conto di situazioni speciali se avvii un servizio in primo piano che richiede autorizzazioni durante l'utilizzo.
Se la tua app ha come target Android 14 o versioni successive, il sistema operativo verifica quando crei un servizio in primo piano per assicurarsi che l'app disponga di tutte le autorizzazioni appropriate per quel tipo di servizio. Ad esempio, quando crei un servizio in primo piano di tipo microfono, il sistema operativo verifica che la tua app disponga attualmente dell'autorizzazione RECORD_AUDIO
. Se non disponi di questa autorizzazione, il sistema genera un messaggio di errore SecurityException
.
Per le autorizzazioni durante l'utilizzo, questo causa un potenziale problema. Se la tua app dispone di un'autorizzazione di accesso durante l'uso, questa autorizzazione è disponibile solo quando l'app è 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 l'app non dispone attualmente delle autorizzazioni richieste e genera un SecurityException
.
Analogamente, se la tua app è in background e crea un servizio per la salute che richiede l'autorizzazione BODY_SENSORS
, l'app non la possiede al momento e il sistema genera un'eccezione.
(Questo non si applica se si tratta di un servizio sanitario che richiede autorizzazioni diverse, come ACTIVITY_RECOGNITION
.) La chiamata a PermissionChecker.checkSelfPermission()
non impedisce questo problema. Se la tua app dispone di un'autorizzazione di utilizzo e chiama checkSelfPermission()
per verificare se dispone di questa autorizzazione, il metodo restituisce PERMISSION_GRANTED
anche se l'app è in background. Quando il metodo restituisce PERMISSION_GRANTED
, significa che "la tua app dispone di questa autorizzazione durante l'uso".
Per questo motivo, se il servizio in primo piano ha bisogno di un'autorizzazione durante l'uso, 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 in uso
In alcuni casi, 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 viene eseguita in primo piano ("durante l'uso").
Nelle stesse situazioni, se il servizio dichiara un tipo di servizio in primo piano di location
e viene avviato da un'app che dispone dell'autorizzazione ACCESS_BACKGROUND_LOCATION
, questo servizio può accedere alle informazioni sulla posizione in qualsiasi momento, anche quando l'app viene eseguita in background.
Il seguente elenco contiene queste situazioni:
- Un componente di sistema avvia il servizio.
- Il servizio inizia interagendo con i widget delle app.
- Il servizio inizia interagendo con una notifica.
- Il servizio inizia come
PendingIntent
inviato da un'altra app 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 il
VoiceInteractionService
. - Il servizio viene avviato da un'app che dispone dell'autorizzazione privilegiata
START_ACTIVITIES_FROM_BACKGROUND
.
Determina quali servizi sono interessati nella tua app
Quando testi l'app, avvia i servizi in primo piano. Se un servizio avviato ha accesso limitato a posizione, microfono e fotocamera, in Logcat viene visualizzato il seguente messaggio:
Foreground service started from background can not have \ location/camera/microphone access: service SERVICE_NAME