Services de premier plan

Les services de premier plan effectuent des opérations qui peuvent être remarquées 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 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 afficher le titre en cours de lecture.
  • Une application de fitness qui enregistre l'exécution 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 que l'utilisateur peut remarquer, même lorsqu'il n'interagit pas directement avec elle. 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 des services de premier plan et explique comment démarrer un service de premier plan et le supprimer de l'arrière-plan. Elle explique également comment associer certains cas d'utilisation à des types de services de premier plan, ainsi que 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 par défaut la notification associée à un service de premier plan. Pour ce faire, les utilisateurs doivent balayer l'écran 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 l'utilisateur ne puisse pas ignorer la notification, transmettez true à la méthode setOngoing() lorsque vous créez la 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 é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, il continue de voir des notifications liées aux services de premier plan dans le Gestionnaire de tâches, mais ne les voit pas dans le panneau des notifications.

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

Dans le fichier manifeste de votre application, déclarez chacun des services de premier plan de votre application 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 le déclarer 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 vos différents types s'appliquent à votre service, séparez-les à l'aide de l'opérateur |. Par exemple, un service qui utilise la caméra et le micro déclarerait cela 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 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 tâche que le service de premier plan effectuera. 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 toutes les autorisations normales. Le système les accorde donc 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 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 erreur 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 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 constituer un sous-ensemble des types déclarés dans le fichier manifeste, en fonction du cas d'utilisation spécifique. Si vous devez ensuite ajouter d'autres types de services, vous pouvez à nouveau appeler 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 ou non avoir besoin de lire des contenus multimédias. 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 d'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 =
            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 s'exécuter.

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

Gérer l'arrêt déclenché 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 actuellement exécutées en arrière-plan. Lorsque vous appuyez sur ce bouton, une boîte de dialogue s&#39;affiche, contenant 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 à partir du panneau des notifications pour arrêter une application dont les services de premier plan sont en cours, quelle que soit la version du SDK cible de cette application. Cette affordance, appelée gestionnaire de tâches, affiche une liste d'applications qui exécutent actuellement un service de premier plan.

Cette liste est intitulée Applications actives. Un bouton Arrêter 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" d'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 est conservée dans l'historique.
  • Les jobs planifiés s'exécutent à l'heure prévue.
  • Les alarmes sonnent à l'heure ou à la fenêtre programmée.

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 propose plusieurs niveaux d'exemption pour certains types d'applications, décrits dans les sections suivantes.

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

Des exceptions d’apparaître 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 système
  • Les applications de sécurité, c'est-à-dire celles ayant le rôle ROLE_EMERGENCY
  • Appareils en mode démo

Exemption de la désactivation 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 il n'y a pas de bouton Stop à côté du nom de l'application sur lequel l'utilisateur peut appuyer:

Utiliser des API sur mesure plutôt que des services de premier plan

Dans de nombreux cas d'utilisation, il existe des API de plate-forme ou Jetpack que vous pouvez utiliser pour effectuer des tâches pour lesquelles vous pourriez autrement utiliser un service de premier plan. S'il existe une API sur mesure adaptée, il est presque toujours préférable de l'utiliser plutôt que d'utiliser un service de premier plan. Les API sur mesure fournissent souvent des fonctionnalités supplémentaires spécifiques à des cas d'utilisation que vous auriez autrement à créer par vous-même. Par exemple, l' API Bubbles gère la logique d'interface utilisateur complexe pour les applications de messagerie qui doivent implémenter les fonctionnalités des bulles de chat.

La documentation sur les types de services de premier plan répertorie 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 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 qui nécessite des autorisations pendant l'utilisation (par exemple, des autorisations liées au capteur corporel, à l'appareil photo, au micro ou à la localisation), elle ne peut pas créer le service tant qu'elle est exécutée en arrière-plan, même si l'application est concernée par les exceptions des restrictions de démarrage en arrière-plan. La raison de cela est expliquée dans la section Restrictions concernant le démarrage des 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 démarrer des services de premier plan même lorsqu'elle s'exécute en arrière-plan:

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

Sur Android 14 (niveau d'API 34) ou version ultérieure, vous devez connaître certaines 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 pour 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.

Cela peut poser problème pour les autorisations en cours d'utilisation. Si votre application dispose d'une autorisation pendant l'utilisation, elle ne dispose de cette autorisation que quand 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, localisation 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 est exécutée en arrière-plan et qu'elle crée un service de santé qui a besoin de l'autorisation BODY_SENSORS_BACKGROUND, elle ne dispose pas de cette autorisation pour le moment, 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, telles que ACTIVITY_RECOGNITION.) Appeler ContextCompat.checkSelfPermission() n'empêche pas ce problème. Si votre application dispose d'une autorisation pendant l'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 exécutée en arrière-plan. Lorsque la méthode renvoie PERMISSION_GRANTED, le message indique "votre application dispose de cette autorisation pendant que l'application est en cours d'utilisation".

Pour cette raison, si votre service de premier plan nécessite une autorisation en cours d'utilisation, vous devez appeler Context.startForegroundService() ou Context.bindService() tant que votre application présente une activité visible, sauf si le service correspond à l'une des exceptions définies.

Exemptions des restrictions sur les autorisations 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 sur la localisation, l'appareil photo et le micro pendant que l'application s'exécute au premier plan ("lorsqu'elle est 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, ce service peut accéder aux informations de localisation en permanence, même lorsque l'application s'exécute en arrière-plan.

Vous trouverez dans la liste suivante 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 démarre en tant que PendingIntent envoyé depuis une autre application visible.
  • Le service commence 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 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 à 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