Regrouper les notifications mobiles

À partir du niveau d'API Android 26, des notifications persistantes sont requises pour les services de premier plan. Cette exigence vise à vous éviter de masquer les services susceptibles de solliciter des ressources système de manière excessive, y compris la batterie. Cette exigence peut entraîner un problème: si une application avec plusieurs services de premier plan ne gère pas soigneusement la notification pour qu'elle soit partagée entre tous les services, plusieurs notifications persistantes impossibles à ignorer peuvent entraîner un encombrement indésirable dans la liste active des notifications.

Ce problème devient plus difficile lorsque vous utilisez des SDK tels que le SDK Navigation, qui exécutent des services de premier plan indépendants de l'application et qui disposent de leurs propres notifications persistantes, ce qui les rend difficiles à consolider. Pour résoudre ces problèmes, le SDK Navigation v1.11 a introduit une API simple pour faciliter la gestion des notifications persistantes dans l'application, y compris dans le SDK.

Consolider les notifications persistantes

Composants

Le gestionnaire de services de premier plan fournit un wrapper pour la classe de service de premier plan Android et la classe de notification persistante. La fonction principale de ce wrapper est d'appliquer la réutilisation de l'ID de notification afin que la notification soit partagée entre tous les services de premier plan à l'aide du gestionnaire.


Le SDK Navigation contient des méthodes statiques permettant d'initialiser et d'obtenir le singleton ForegroundServiceManager. Ce singleton ne peut être initialisé qu'une seule fois au cours de la durée de vie du SDK Navigation. Par conséquent, si vous utilisez l'un des appels d'initialisation (initForegroundServiceManagerMessageAndIntent() ou initForegroundServiceManagerProvider()), vous devez l'entourer d'un bloc try-catch au cas où ce chemin serait à nouveau saisi. Le SDK Navigation génère une exception d'exécution si vous appelez l'une ou l'autre méthode plusieurs fois, sauf si vous effacez d'abord toutes les références à ForegroundServiceManager et appelez clearForegroundServiceManager() avant chaque appel suivant.

Les quatre paramètres de initForegroundServiceManagerMessageAndIntent() sont application, notificationId, defaultMessage et resumeIntent. Si les trois derniers paramètres sont nuls, il s'agit de la notification standard du SDK Navigation. Il est toujours possible de masquer d'autres services de premier plan dans l'application derrière cette notification. Le paramètre notificationId spécifie l'ID de notification à utiliser pour la notification. Si la valeur est "null", une valeur arbitraire est utilisée. Vous pouvez la configurer explicitement pour contourner les conflits avec d'autres notifications, telles que celles d'un autre SDK. defaultMessage est une chaîne qui s'affiche lorsque le système n'est pas en train de naviguer. resumeIntent est un intent qui se déclenche lorsque l'utilisateur clique sur la notification. Si resumeIntent présente une valeur nulle, les clics sur la notification sont ignorés.

Les trois paramètres de initForegroundServiceManagerProvider() sont application, notificationId et notificationProvider. Si les deux derniers paramètres sont nuls, la notification est la notification standard du SDK Navigation. Le paramètre notificationId spécifie l'ID de notification à utiliser pour la notification. Si elle est nulle, une valeur arbitraire est utilisée. Vous pouvez la configurer explicitement pour contourner les conflits avec d'autres notifications, telles que celles d'un autre SDK. Si notificationProvider est défini, le fournisseur est toujours chargé de générer la notification à afficher.

La méthode getForegroundServiceManager() du SDK Navigation renvoie le singleton du gestionnaire de services de premier plan. Si vous n'en avez pas encore généré, cela revient à appeler initForegroundServiceManagerMessageAndIntent() avec des paramètres nuls pour notificationId, defaultMessage et resumeIntent.

ForegroundServiceManager comporte trois méthodes simples. Les deux premiers permettent de déplacer un service vers et depuis le premier plan. Ils sont généralement appelés à partir du service créé. L'utilisation de ces méthodes garantit que les services sont associés à la notification persistante partagée. La dernière méthode, updateNotification(), indique au gestionnaire que la notification a été modifiée et qu'elle doit être à nouveau affichée.

Si vous avez besoin d'un contrôle total sur la notification persistante partagée, l'API fournit une interface NotificationContentProvider permettant de définir un fournisseur de notifications, qui contient une seule méthode pour recevoir une notification avec le contenu actuel. Elle fournit également une classe de base que vous pouvez éventuellement utiliser pour définir le fournisseur. L'un des principaux objectifs de la classe de base est qu'elle permet d'appeler updateNotification() sans avoir à accéder à ForegroundServiceManager. Si vous utilisez une instance du fournisseur de notifications pour recevoir de nouveaux messages de notification, vous pouvez appeler directement cette méthode interne pour afficher le message dans la notification.

Scénarios d'utilisation

Cette section détaille les scénarios d'utilisation des notifications persistantes partagées.

Masquer les notifications persistantes des autres services de premier plan de l'appli
Le scénario le plus simple consiste à conserver le comportement actuel et à n'utiliser la notification persistante que pour afficher les informations du SDK Navigation. D'autres services peuvent être masqués derrière cette notification à l'aide des méthodes startForeground() et stopForeground() du gestionnaire de services de premier plan.
Masquer les notifications persistantes des autres services de premier plan de l'appli, mais définir le texte par défaut affiché lorsque la navigation n'est pas activée
Le deuxième scénario le plus simple consiste à conserver le comportement actuel et à n'utiliser la notification persistante que pour afficher les informations du SDK Navigation, sauf lorsque le système n'est pas en train de naviguer. Lorsque le système ne navigue pas, la chaîne fournie à initForegroundServiceManagerMessageAndIntent() s'affiche à la place de la chaîne du SDK Navigation par défaut qui mentionne "Google Maps". Vous pouvez également utiliser cet appel pour définir l'intent de reprise qui se déclenche lorsque l'utilisateur clique sur la notification.
Contrôler totalement l'affichage de la notification persistante
Le scénario final nécessite de définir et de créer un fournisseur de notifications, puis de le transmettre au ForegroundServiceManager à l'aide de initForegroundServiceManagerProvider(). Cette option vous permet de contrôler entièrement ce qui s'affiche dans la notification, mais elle dissocie également les informations de notification du SDK Navigation de la notification, supprimant ainsi les invites de navigation détaillées qui y sont affichées. Google ne fournit pas de moyen simple pour récupérer ces informations et les insérer dans la notification.

Exemple de fournisseur de notifications

L'exemple de code suivant montre comment créer et renvoyer des notifications à l'aide d'un fournisseur de contenu de notification simple.

public class NotificationContentProviderImpl
   extends NotificationContentProviderBase
   implements NotificationContentProvider {
 private String channelId;
 private Context context;
 private String message;

 /** Constructor */
 public NotificationContentProviderImpl(Application application) {
   super(application);
   message = "-- uninitialized --";
   channelId = null;
   this.context = application;
 }

 /**
  * Sets message to display in the notification. Calls updateNotification
  * to display the message immediately.
  *
  * @param msg The message to display in the notification.
  */
 public void setMessage(String msg) {
   message = msg;
   updateNotification();
 }

 /**
  * Returns the notification as it should be rendered.
  */
 @Override
 public Notification getNotification() {
   Notification notification;

   if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
     Spanned styledText = Html.fromHtml(message, FROM_HTML_MODE_LEGACY);
     String channelId = getChannelId(context);
     notification =
         new Notification.Builder(context, channelId)
             .setContentTitle("Notifications Demo")
             .setStyle(new Notification.BigTextStyle()
                 .bigText(styledText))
             .setSmallIcon(R.drawable.ic_navigation_white_24dp)
             .setTicker("ticker text")
             .build();
   } else {
     notification = new Notification.Builder(context)
         .setContentTitle("Notification Demo")
         .setContentText("testing non-O text")
         .build();
   }

   return notification;
 }

 // Helper to set up a channel ID.
 private String getChannelId(Context context) {
   if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
     if (channelId == null) {
       NotificationManager notificationManager =
           (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
       NotificationChannel channel = new NotificationChannel(
           "default", "navigation", NotificationManager.IMPORTANCE_DEFAULT);
       channel.setDescription("For navigation persistent notification.");
       notificationManager.createNotificationChannel(channel);
       channelId = channel.getId();
     }
     return channelId;
   } else {
     return "";
   }
 }
}

Après avoir créé NotificationContentProviderImpl, connectez-y le SDK Navigation à l'aide du code suivant:

ForegroundServiceManager f = NavigationApi.getForegroundServiceManager(getApplication());
mNotification = new NotificationContentProviderImpl(getApplication());
NavigationApi.clearForegroundServiceManager();
NavigationApi.initForegroundServiceManagerProvider(getApplication(), null, mNotification);

Mises en garde et projets futurs

  • Veillez à appeler initForegroundServiceManagerMessageAndIntent() ou initForegroundServiceManagerProvider() au préalable afin que le scénario d'utilisation attendu soit bien défini. Vous devez appeler cette méthode avant de créer un navigateur.
  • Veillez à détecter les exceptions concernant les appels à initForegroundServiceManagerMessageAndIntent() ou initForegroundServiceManagerProvider() si le chemin de code est saisi plusieurs fois. Dans le SDK Navigation v2.0, l'appel de cette méthode plusieurs fois génère une exception vérifiée au lieu d'une exception d'exécution.
  • Google aura peut-être encore du travail à accomplir pour obtenir un style cohérent pendant toute la durée de vie de la notification, qui correspond au style de l'en-tête.
  • Lorsque vous définissez un fournisseur de notifications, vous pouvez contrôler le comportement des avertissements avec le niveau de priorité.
  • Google ne fournit pas de moyen simple de récupérer des informations de navigation détaillées qu'un fournisseur de notifications pourrait insérer dans la notification.