Per avviare un servizio in primo piano dalla tua app, devi eseguire due passaggi. Innanzitutto, devi avviare il servizio chiamando
context.startForegroundService()
. Quindi, fai in modo che il
servizio chiami ServiceCompat.startForeground()
per promuoversi
in un servizio in primo piano.
Prerequisiti
A seconda del livello API a cui è destinata l'app, esistono alcune limitazioni relative al momento in cui un'app può avviare un servizio in primo piano.
Le app che hanno come target Android 12 (livello API 31) o versioni successive non possono avviare un servizio in primo piano mentre l'app è in background, con alcune eccezioni specifiche. Per ulteriori informazioni e per conoscere le eccezioni a questa regola, consulta Limitazioni all'avvio di un servizio in primo piano in background.
Le app che hanno come target Android 14 (livello API 34) o versioni successive devono richiedere le autorizzazioni appropriate per il tipo di servizio in primo piano. Quando l'app tenta di promuovere un servizio in primo piano, il sistema verifica la presenza delle autorizzazioni appropriate e genera
SecurityException
se l'app non ne ha. Ad esempio, se provi ad avviare un servizio in primo piano di tipolocation
, il sistema verifica che la tua app disponga già dell'autorizzazioneACCESS_COARSE_LOCATION
oACCESS_FINE_LOCATION
. 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
Per avviare un servizio in primo piano, devi prima avviarlo come servizio ordinario (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 del 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 un servizio in primo piano.
Promuovere un servizio in primo piano
Una volta eseguito un servizio, devi chiamare
ServiceCompat.startForeground()
per richiedere che il servizio
venga eseguito in primo piano. Normalmente, questo metodo viene chiamato nel metodo
onStartCommand()
del servizio.
ServiceCompat.startForeground()
accetta i seguenti parametri:
- Il servizio.
- Un numero intero positivo che identifica in modo univoco la notifica del servizio nella barra di stato.
- L'oggetto
Notification
stesso. - Il tipo o i tipi di servizio in primo piano che identificano il lavoro svolto dal servizio
I tipi di servizi in primo piano che trasmetti a startForeground()
tipi dichiarati nel manifest, a seconda del caso d'uso specifico. Se in seguito dovessi aggiungere altri tipi di servizi, puoi chiamare
di nuovo il numero startForeground()
.
Ad esempio, supponiamo che un'app di fitness esegua un servizio di monitoraggio della corsa che ha sempre bisogno di informazioni location
, ma potrebbe o meno aver bisogno di riprodurre contenuti multimediali. Devi
dichiarare sia location
sia mediaPlayback
nel manifest. Se un
utente inizia 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 iniziare a riprodurre l'audio, chiama di nuovo startForeground()
e
trasmetti 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 fotocamera 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 del codice
- L'app ha già dichiarato nel manifest di aver bisogno dell'autorizzazione
CAMERA
. Tuttavia, l'app deve anche eseguire un controllo in fase di runtime per assicurarsi che l'utente abbia concesso l'autorizzazione. Se l'app non dispone effettivamente delle autorizzazioni corrette, dovrebbe informare l'utente del problema. - Sono stati introdotti diversi tipi di servizio in primo piano con versioni diverse della piattaforma Android. Questo codice controlla 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).