Lancer un service de premier plan

Le lancement d'un service de premier plan à partir de votre application s'effectue 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 se promouvoir en service de premier plan.

Prérequis

Selon le niveau d'API ciblé par votre application, le lancement d'un service de premier plan peut être soumis à certaines restrictions.

  • Les applications ciblant Android 12 (niveau d'API 31) ou version ultérieure ne sont pas autorisées à démarrer un service de premier plan lorsqu'elles s'exécutent en arrière-plan, à quelques exceptions près. Pour en savoir plus et connaître les exceptions à cette règle, consultez Restrictions concernant le démarrage d'un service de premier plan en arrière-plan.

  • Les applications ciblant 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 si elle dispose des autorisations appropriées et génère une erreur SecurityException si ce n'est pas le cas. 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 les types de services de premier plan répertorie les prérequis 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 (non de 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 n'est pas encore exécuté au premier plan. Dans le service lui-même, vous devez appeler ServiceCompat.startForeground() pour le promouvoir en service de premier plan.

Promouvoir 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. En règle générale, 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() 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 à nouveau startForeground().

Supposons, par exemple, qu'une application de fitness exécute un service de suivi de course à pied qui a toujours besoin d'informations de location, mais qui peut ou non avoir besoin de lire des contenus multimédias. Vous devez déclarer location et mediaPlayback dans le fichier manifeste. Si un utilisateur commence une course et souhaite uniquement 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 du contenu audio, appelez à nouveau startForeground() et transmettez la combinaison au niveau du bit 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 se promouvoir en 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 recherche ForegroundServiceStartNotAllowedException au cas où il tente 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 alors que l'application s'exécute en arrière-plan).