Services de premier plan

Les services de premier plan effectuent des opérations visibles par l'utilisateur.

Les services de premier plan affichent une notification dans la barre d'état pour indiquer aux utilisateurs que votre application effectue une tâche au premier plan et consomme des ressources système.

Voici quelques exemples d'applications qui utilisent des services de premier plan:

  • Application de lecteur musical qui lit de la musique dans un service de premier plan. La notification peut afficher le titre en cours de lecture.
  • Une application de fitness qui enregistre la course d'un utilisateur dans un service de premier plan, après avoir reçu l'autorisation de l'utilisateur. La notification peut afficher la distance parcourue par l'utilisateur pendant la session de fitness en cours.

N'utilisez un service de premier plan que lorsque votre application doit effectuer une tâche visible par l'utilisateur, même lorsqu'il n'interagit pas directement avec l'application. Si l'action est suffisamment peu importante pour que vous souhaitiez utiliser une notification de priorité minimale, créez plutôt une tâche en arrière-plan.

Ce document décrit l'autorisation requise pour utiliser les services de premier plan, et explique comment démarrer un service de premier plan et le supprimer de l'arrière-plan. Il décrit également comment associer certains cas d'utilisation à des types de services de premier plan et les restrictions d'accès qui s'appliquent lorsque vous démarrez un service de premier plan à partir d'une application exécutée en arrière-plan.

L'utilisateur peut ignorer la notification par défaut

À partir d'Android 13 (niveau d'API 33), les utilisateurs peuvent ignorer la notification associée à un service de premier plan par défaut. Pour ce faire, les utilisateurs effectuent un geste de balayage sur la notification. Traditionnellement, la notification n'est pas ignorée, sauf si le service de premier plan est arrêté ou supprimé du premier plan.

Si vous ne souhaitez pas que l'utilisateur puisse ignorer la notification, transmettez true à la méthode setOngoing() lorsque vous créez votre notification à l'aide de Notification.Builder.

Services qui affichent une notification immédiatement

Si un service de premier plan présente au moins l'une des caractéristiques suivantes, le système affiche la notification associée immédiatement après le démarrage du service, même sur les appareils exécutant Android 12 ou version ultérieure:

Sous Android 13 (niveau d'API 33) ou version ultérieure, si l'utilisateur refuse l'autorisation de notification, il voit toujours les notifications liées aux services de premier plan dans le gestionnaire de tâches, mais pas dans le panneau des notifications.

Déclarer des services de premier plan dans votre fichier manifeste

Dans le fichier manifeste de votre application, déclarez chacun de ses services de premier plan avec un élément <service>. Pour chaque service, utilisez un attribut android:foregroundServiceType pour déclarer le type de travail effectué par le service.

Par exemple, si votre application crée un service de premier plan qui diffuse de la musique, vous pouvez déclarer le service comme suit:

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

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

Si plusieurs types s'appliquent à votre service, séparez-les avec l'opérateur |. Par exemple, un service qui utilise la caméra et le micro le déclare comme suit:

android:foregroundServiceType="camera|microphone"

Demander les autorisations pour le service de premier plan

Les applications qui ciblent Android 9 (niveau d'API 28) ou une version ultérieure et qui utilisent des services de premier plan doivent demander FOREGROUND_SERVICE dans le fichier manifeste de l'application, comme indiqué dans l'extrait de code suivant. Il s'agit d'une autorisation normale. Le système l'accorde donc automatiquement à l'application à l'origine de la demande.

De plus, si l'application cible le niveau d'API 34 ou supérieur, elle doit demander le type d'autorisation approprié pour le type de travail que le service de premier plan effectuera. Chaque type de service de premier plan est associé à un type d'autorisation. Par exemple, si une application lance un service de premier plan qui utilise l'appareil photo, vous devez demander les autorisations FOREGROUND_SERVICE et FOREGROUND_SERVICE_CAMERA. Il s'agit toutes d'autorisations normales. Le système les accorde donc automatiquement si elles sont listées dans le fichier manifeste.

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

Prérequis pour les services de premier plan

À partir d'Android 14 (niveau d'API 34), lorsque vous lancez un service de premier plan, le système vérifie les conditions préalables spécifiques en fonction du type de service. 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. Si ce n'est pas le cas, le système génère une exception SecurityException.

Pour cette raison, vous devez vérifier que les conditions préalables requises sont remplies avant de démarrer un service de premier plan. 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 de premier plan

Avant de demander au système d'exécuter un service en tant que service de premier plan, démarrez le service lui-même:

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

Dans le service, généralement dans onStartCommand(), vous pouvez demander que votre service s'exécute au premier plan. Pour ce faire, appelez ServiceCompat.startForeground() (disponible dans androidx-core 1.12 et versions ultérieures). Cette méthode utilise les paramètres suivants:

Ces types peuvent être un sous-ensemble des 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).

Voici un exemple qui lance un service de premier plan de l'appareil photo:

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

    //...
}

Supprimer un service du premier plan

Pour supprimer le service du premier plan, appelez stopForeground(). Cette méthode utilise une valeur booléenne, qui indique si la notification de la barre d'état doit également être supprimée. Notez que le service continue à s'exécuter.

Si vous arrêtez le service alors qu'il s'exécute au premier plan, sa notification est supprimée.

Gérer l'arrêt des applications exécutant des services de premier plan déclenché par l'utilisateur

En bas du panneau des notifications, un bouton indique le nombre d&#39;applications actuellement exécutées en arrière-plan. Lorsque vous appuyez sur ce bouton, une boîte de dialogue s&#39;affiche, qui liste les noms des différentes applications. Le bouton &quot;Arrêter&quot; se trouve à droite de chaque application.
Figure 1. Flux de travail du gestionnaire de tâches sur les appareils équipés d'Android 13 ou version ultérieure

À partir d'Android 13 (niveau d'API 33), les utilisateurs peuvent effectuer un workflow depuis le volet de notification pour arrêter une application qui utilise des services de premier plan, quelle que soit la version du SDK cible de cette application. Cette affordance, appelée Gestionnaire des tâches, affiche la liste des applications qui exécutent actuellement un service de premier plan.

Cette liste est intitulée Applications actives. À côté de chaque application se trouve un bouton Arrêter. La figure 1 illustre le workflow du gestionnaire de tâches sur un appareil exécutant Android 13.

Lorsque l'utilisateur appuie sur le bouton Stop (Arrêter) à côté de votre application dans le Gestionnaire des tâches, les actions suivantes se produisent:

  • Le système supprime votre application de la mémoire. Par conséquent, l'ensemble de votre application s'arrête, et pas seulement le service de premier plan en cours d'exécution.
  • Le système supprime la pile "Retour" de l'activité de votre application.
  • La lecture de tout contenu multimédia s'arrête.
  • La notification associée au service de premier plan est supprimée.
  • Votre application reste dans l'historique.
  • Les jobs planifiés s'exécutent à l'heure prévue.
  • Les alarmes se déclenchent à l'heure ou à la période programmée.

Pour vérifier que votre application se comporte comme prévu pendant et après qu'un utilisateur l'a arrêtée, exécutez la commande ADB suivante dans une fenêtre de terminal:

adb shell cmd activity stop-app PACKAGE_NAME

Exceptions

Le système propose plusieurs niveaux d'exemptions pour certains types d'applications, qui sont décrits dans les sections suivantes.

Les exceptions sont appliquées par application, et non par processus. Si le système exempte un processus d'une application, tous les autres processus de cette application sont également exemptés.

Exemptions d'affichage dans le gestionnaire de tâches

Les applications suivantes peuvent exécuter un service de premier plan et ne pas apparaître du tout dans le gestionnaire de tâches:

  • Applications au niveau du système
  • Applications de sécurité, c'est-à-dire applications disposant du rôle ROLE_EMERGENCY
  • Appareils en mode démo

Exceptions à l'arrêt par les utilisateurs

Lorsque les types d'applications suivants exécutent un service de premier plan, ils apparaissent dans le gestionnaire de tâches, mais aucun bouton Arrêter ne s'affiche à côté du nom de l'application pour que l'utilisateur puisse appuyer dessus:

Utiliser des API dédiées plutôt que des services de premier plan

Pour de nombreux cas d'utilisation, vous pouvez utiliser des API de plate-forme ou de Jetpack pour effectuer des tâches pour lesquelles vous pourriez utiliser un service de premier plan. Si une API dédiée est disponible, vous devez presque toujours l'utiliser au lieu d'un service de premier plan. Les API conçues à des fins spécifiques fournissent souvent des fonctionnalités supplémentaires spécifiques aux cas d'utilisation que vous auriez autrement dû créer vous-même. Par exemple, l' API Bubbles gère la logique d'UI complexe des applications de messagerie qui doivent implémenter des fonctionnalités de bulles de chat.

La documentation sur les types de services de premier plan présente de bonnes alternatives à utiliser à la place des services de premier plan.

Restrictions concernant le démarrage d'un service de premier plan en arrière-plan

Les applications qui ciblent Android 12 ou version ultérieure ne peuvent pas démarrer de services de premier plan lorsque l'application s'exécute en arrière-plan, sauf dans quelques cas particuliers. Si une application tente de démarrer un service de premier plan alors qu'elle s'exécute en arrière-plan et que le service de premier plan ne répond pas à l'un des cas exceptionnels, le système génère une ForegroundServiceStartNotAllowedException.

De plus, si une application souhaite lancer un service de premier plan qui nécessite des autorisations en cours d'utilisation (par exemple, des autorisations pour les capteurs corporels, l'appareil photo, le micro ou la position), elle ne peut pas créer le service lorsque l'application est en arrière-plan, même si elle fait partie des exceptions aux restrictions de démarrage en arrière-plan. La raison en est expliquée dans la section Restrictions sur le démarrage de services de premier plan nécessitant des autorisations en cours d'utilisation.

Exceptions aux restrictions de démarrage en arrière-plan

Dans les situations suivantes, votre application peut démarrer des services de premier plan même lorsqu'elle s'exécute en arrière-plan:

Restrictions concernant le démarrage de services de premier plan nécessitant des autorisations en cours d'utilisation

Sur Android 14 (niveau d'API 34) ou version ultérieure, vous devez tenir compte de situations spéciales si vous démarrez un service de premier plan qui nécessite des autorisations en cours d'utilisation.

Si votre application cible Android 14 ou une version ultérieure, le système d'exploitation vérifie lorsque vous créez un service de premier plan que votre application dispose de toutes les autorisations appropriées pour ce type de service. Par exemple, lorsque vous créez un service de premier plan de type microphone, le système d'exploitation vérifie que votre application dispose actuellement de l'autorisation RECORD_AUDIO. Si vous ne disposez pas de cette autorisation, le système génère une exception SecurityException.

Pour les autorisations d'utilisation, cela peut poser problème. Si votre application dispose d'une autorisation "si l'application est ouverte", elle ne dispose de cette autorisation que lorsque l'application est au premier plan. Cela signifie que si votre application est en arrière-plan et qu'elle tente de créer un service de premier plan de type appareil photo, position ou micro, le système voit que votre application ne dispose pas actuellement des autorisations requises et génère une erreur SecurityException.

De même, si votre application s'exécute en arrière-plan et qu'elle crée un service de santé qui nécessite l'autorisation BODY_SENSORS, elle ne dispose pas actuellement de cette autorisation et le système génère une exception. (Cela ne s'applique pas s'il s'agit d'un service de santé nécessitant des autorisations différentes, comme ACTIVITY_RECOGNITION.) L'appel de PermissionChecker.checkSelfPermission() n'empêche pas ce problème. Si votre application dispose d'une autorisation d'utilisation et qu'elle appelle checkSelfPermission() pour vérifier si elle dispose de cette autorisation, la méthode renvoie PERMISSION_GRANTED, même si l'application est en arrière-plan. Lorsque la méthode renvoie PERMISSION_GRANTED, cela signifie que votre application dispose de cette autorisation lorsque l'application est en cours d'utilisation.

Par conséquent, si votre service de premier plan a besoin d'une autorisation "si l'application est ouverte", vous devez appeler Context.startForegroundService() ou Context.bindService() lorsque votre application a une activité visible, sauf si le service fait partie de l'une des exceptions définies.

Exceptions aux restrictions concernant les autorisations en cours d'utilisation

Dans certains cas, même si un service de premier plan est démarré alors que l'application s'exécute en arrière-plan, il peut toujours accéder aux informations de localisation, de l'appareil photo et du micro lorsque l'application s'exécute au premier plan ("while-in-use").

Dans ces mêmes situations, si le service déclare un type de service de premier plan de location et est lancé par une application disposant de l'autorisation ACCESS_BACKGROUND_LOCATION, ce service peut accéder aux informations de localisation en permanence, même lorsque l'application s'exécute en arrière-plan.

La liste suivante contient ces situations:

  • Un composant système démarre le service.
  • Le service commence par interagir avec les widgets d'application.
  • Le service commence par interagir avec une notification.
  • Le service démarre en tant que PendingIntent envoyé à partir d'une autre application visible.
  • Le service est lancé par une application qui est un outil de contrôle des règles relatives aux appareils qui s'exécute en mode propriétaire de l'appareil.
  • Le service est démarré par une application qui fournit le VoiceInteractionService.
  • Le service est démarré par une application disposant de l'autorisation privilégiée START_ACTIVITIES_FROM_BACKGROUND.
Déterminer les services concernés dans votre application

Lorsque vous testez votre application, démarrez ses services de premier plan. Si un service lancé a un accès limité à la position, au micro et à la caméra, le message suivant s'affiche dans Logcat:

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