Lancer un service de premier plan

Le lancement d'un service de premier plan à partir de votre application se fait en deux étapes. Tout d'abord, vous devez démarrer le service en appelant context.startForegroundService(). Ensuite, demandez au service d'appeler ServiceCompat.startForeground() pour s'auto-promouvoir en service de premier plan.

Prérequis

Selon le niveau d'API ciblé par votre application, certaines restrictions s'appliquent au moment où une application peut lancer un service de premier plan.

  • Les applications qui ciblent Android 12 (niveau d'API 31) ou une version ultérieure ne sont pas autorisées à démarrer un service de premier plan lorsque l'application est en arrière-plan, sauf dans quelques cas spécifiques. Pour en savoir plus et connaître les exceptions à cette règle, consultez la section Restrictions concernant le démarrage d'un service de premier plan en arrière-plan.

  • Les applications qui ciblent Android 14 (niveau d'API 34) ou version ultérieure doivent demander les autorisations appropriées pour le type de service de premier plan. Lorsque l'application tente de promouvoir un service au premier plan, le système vérifie les autorisations appropriées et génère une exception SecurityException si l'application en manque. Par exemple, si vous essayez de lancer un service de premier plan de type location, le système vérifie que votre application dispose déjà de l'autorisation ACCESS_COARSE_LOCATION ou ACCESS_FINE_LOCATION. La documentation sur le type de service de premier plan liste les conditions préalables requises pour chaque type de service de premier plan.

Lancer un service

Pour lancer un service de premier plan, vous devez d'abord le lancer en tant que service ordinaire (hors premier plan) :

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

Points clés concernant le code

  • L'extrait de code lance un service. Toutefois, le service ne s'exécute pas encore au premier plan. Dans le service lui-même, vous devez appeler ServiceCompat.startForeground() pour promouvoir le service en service de premier plan.

Mettre un service au premier plan

Une fois qu'un service est en cours d'exécution, vous devez appeler ServiceCompat.startForeground() pour demander que le service s'exécute au premier plan. Normalement, vous appelez cette méthode dans la méthode onStartCommand() du service.

ServiceCompat.startForeground() utilise les paramètres suivants:

Les types de services de premier plan que vous transmettez à startForeground() sont les types déclarés dans le fichier manifeste, en fonction du cas d'utilisation spécifique. Ensuite, si vous devez ajouter d'autres types de services, vous pouvez appeler startForeground() à nouveau.

Par exemple, supposons qu'une application de fitness exécute un service de suivi de la course à pied qui a toujours besoin d'informations location, mais qui peut ou non avoir besoin de lire des contenus multimédias. Vous devez déclarer à la fois location et mediaPlayback dans le fichier manifeste. Si un utilisateur commence à courir et souhaite simplement que sa position soit suivie, votre application doit appeler startForeground() et ne transmettre que l'autorisation ACCESS_FINE_LOCATION. Ensuite, si l'utilisateur souhaite commencer à lire de l'audio, appelez à nouveau startForeground() et transmettez la combinaison par bits de tous les types de services de premier plan (dans ce cas, ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK).

L'exemple suivant montre le code qu'un service d'appareil photo utiliserait pour s'auto-promouvoir en tant que service de premier plan:

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

    //...
}

Points clés concernant le code

  • L'application a déjà déclaré dans le fichier manifeste qu'elle a besoin de l'autorisation CAMERA. Toutefois, l'application doit également vérifier au moment de l'exécution que l'utilisateur a accordé cette autorisation. Si l'application ne dispose pas des autorisations appropriées, elle doit informer l'utilisateur du problème.
  • Différents types de services de premier plan ont été introduits avec différentes versions de la plate-forme Android. Ce code vérifie la version d'Android sur laquelle il s'exécute et demande les autorisations appropriées.
  • Le code vérifie ForegroundServiceStartNotAllowedException au cas où il tenterait de démarrer un service de premier plan dans une situation non autorisée (par exemple, s'il tente de promouvoir le service au premier plan lorsque l'application est en arrière-plan).