Services de premier plan

Les services de premier plan effectuent des opérations que l'utilisateur peut remarquer.

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

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

  • Une application de lecteur de musique qui lit de la musique dans un service de premier plan. La notification peut indiquer 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 indiquer la distance parcourue par l'utilisateur au cours de 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 faible 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. Il explique également comment démarrer un service de premier plan et le supprimer de l'arrière-plan. Il explique é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 qui s'exécute 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 par défaut la notification associée à un service de premier plan. 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 souhaitez que la notification ne puisse pas être ignorée par l'utilisateur, transmettez true à la méthode setOngoing() lorsque vous créez la notification à l'aide de Notification.Builder.

Services affichant 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 équipés d'Android 12 ou version ultérieure:

Sur Android 13 (niveau d'API 33) ou version ultérieure, si l'utilisateur refuse l'autorisation de notification, les notifications liées aux services de premier plan s'affichent toujours 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 lit de la musique, vous pouvez déclarer le service comme suit:

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

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

Si vos différents 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éclarerait comme suit:

android:foregroundServiceType="camera|microphone"

Demander les autorisations du service de premier plan

Les applications qui ciblent Android 9 (niveau d'API 28) ou version ultérieure et utilisent des services de premier plan doivent demander le fichier 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.

En outre, 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 réalisé par le service de premier plan. Chaque type de service de premier plan possède un type d'autorisation correspondant. 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 de autorisations normales. Le système les accorde automatiquement si elles sont répertorié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>

Conditions préalables pour le service de premier plan

À partir d'Android 14 (niveau d'API 34), lorsque vous lancez un service de premier plan, le système recherche des 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 les types de services de premier plan répertorie les conditions préalables requises pour chaque type de service de premier plan.

Démarrer 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 à ce qu'il 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 correspondre à 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 à nouveau startForeground().

Par exemple, supposons qu'une application de fitness exécute un service de suivi de la course à pied qui a toujours besoin des informations location, mais qui peut avoir besoin ou non de lire du contenu multimédia. Vous devez déclarer location et mediaPlayback dans le fichier manifeste. Si un utilisateur démarre une course et souhaite simplement suivre sa position, 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 bit à bit 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 pour une caméra:

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 =
            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 {
        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 au 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 de fonctionner.

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 initié par l'utilisateur des applications exécutant des services de premier plan

En bas du panneau des notifications, un bouton indique le nombre d&#39;applications en cours d&#39;exécution en arrière-plan. Lorsque vous appuyez sur ce bouton, une boîte de dialogue s&#39;affiche et répertorie les noms des différentes applications. Le bouton &quot;Arrêter&quot; se trouve à droite de chaque application.
Figure 1. Workflow 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 suivre un workflow depuis le panneau des notifications pour arrêter une application qui dispose de services de premier plan actifs, quelle que soit la version du SDK cible de cette application. Cette affordance, appelée gestionnaire de tâches, affiche la liste des applications qui exécutent actuellement un service de premier plan.

Cette liste est intitulée Applications actives. Un bouton Stop apparaît à côté de chaque application. 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 à côté de votre application dans le gestionnaire de tâches, les actions suivantes se produisent:

  • Le système supprime votre application de la mémoire. Par conséquent, l'intégralité 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 des contenus multimédias 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 à l'heure programmées.

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

adb shell cmd activity stop-app PACKAGE_NAME

Exceptions

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

Les exceptions s'appliquent à une application et non à un processus. Si le système exempte un processus dans une application, tous les autres processus de cette application en sont également exemptés.

Aucune exception n'apparaît 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
  • Les applications de sécurité, c'est-à-dire les applications ayant le rôle ROLE_EMERGENCY
  • Appareils en mode démo

Exonérations de l'arrêt de la part des utilisateurs

Lorsque les types d'applications suivants exécutent un service de premier plan, elles apparaissent dans le gestionnaire de tâches, mais il n'y a pas de bouton Stop à côté du nom de l'application sur lequel l'utilisateur peut appuyer:

Utiliser des API spécifiques plutôt que des services de premier plan

Dans de nombreux cas d'utilisation, il existe des API de plate-forme ou Jetpack pour effectuer des tâches. Pour lesquelles vous pourriez sinon utiliser un service de premier plan. S'il existe une API adaptée et adaptée, vous devez presque toujours l'utiliser au lieu d'un service de premier plan. Les API spécifiques fournissent souvent des fonctionnalités supplémentaires spécifiques à des cas d'utilisation que vous auriez normalement dû développer par vous-même. Par exemple, l' API Bubbles gère la logique d'interface utilisateur complexe pour les applications de chat qui doivent implémenter des fonctionnalités d'info-bulle de chat.

La documentation sur les types de services de premier plan répertorie les 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 une version ultérieure ne peuvent pas démarrer de services de premier plan lorsqu'elles s'exécutent 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 erreur ForegroundServiceStartNotAllowedException.

En outre, si une application souhaite lancer un service de premier plan nécessitant des autorisations pendant l'utilisation (par exemple, autorisations d'accès aux capteurs corporels, à l'appareil photo, au micro ou à la position), elle ne peut pas créer le service lorsque l'application est en arrière-plan, même si elle relève de l'une des exceptions des restrictions de démarrage en arrière-plan. Pour en savoir plus, consultez la section Restrictions au démarrage de services de premier plan nécessitant des autorisations en cours d'utilisation.

Exemptions des restrictions de démarrage en arrière-plan

Dans les situations suivantes, votre application peut lancer 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 prendre en compte des situations particulières 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, afin de s'assurer qu'elle 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 micro, 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 en cours d'utilisation, cela peut poser un problème. Si votre application dispose d'une autorisation en cours d'utilisation, elle ne dispose de cette autorisation que lorsqu'elle est au premier plan. Cela signifie que si votre application est exécutée 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 détecte que votre application ne dispose actuellement pas des autorisations requises et génère une exception SecurityException.

De même, si votre application est exécutée en arrière-plan et qu'elle crée un service de santé nécessitant l'autorisation BODY_SENSORS_BACKGROUND, l'application 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é qui nécessite des autorisations différentes, comme ACTIVITY_RECOGNITION.) L'appel de ContextCompat.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 pendant qu'elle est utilisée".

Pour cette raison, si votre service de premier plan a besoin d'une autorisation d'utilisation, vous devez appeler Context.startForegroundService() ou Context.bindService() tant que l'activité de votre application est visible, sauf si le service relève de l'une des exceptions définies.

Exemptions des restrictions sur 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, elle peut toujours accéder aux informations de localisation, à l'appareil photo et au micro lorsque l'application s'exécute au premier plan ("en cours d'utilisation").

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

La liste suivante contient les situations suivantes:

  • 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 commence par un élément PendingIntent envoyé à partir d'une autre application visible.
  • Le service démarre par une application qui est un contrôleur des règles relatives aux appareils, qui s'exécute en mode propriétaire de l'appareil.
  • Le service commence par une application qui fournit le VoiceInteractionService.
  • Le service démarre 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 démarré a restreint l'accès à la position, au micro et à l'appareil photo, le message suivant s'affiche dans Logcat:

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