Benachrichtigungen auf Mobilgeräten zusammenfassen

Ab Android-API-Ebene 26 sind dauerhafte Benachrichtigungen für Dienste im Vordergrund erforderlich. Diese Anforderung soll verhindern, dass Sie Dienste ausblenden, die möglicherweise übermäßige Anforderungen an Systemressourcen stellen, insbesondere an den Akku. Diese Anforderung birgt ein potenzielles Problem: Wenn eine App mit mehreren Vordergrunddiensten die Benachrichtigung nicht sorgfältig verwaltet, sodass sie von allen Diensten gemeinsam genutzt wird, kann es zu mehreren persistenten, nicht schließbaren Benachrichtigungen kommen, was zu unerwünschten Unordnung in der aktiven Liste der Benachrichtigungen führt.

Dieses Problem wird noch schwieriger, wenn Sie SDKs wie das Navigation SDK verwenden, die Vordergrunddienste unabhängig von der App ausführen und eigene unabhängige dauerhafte Benachrichtigungen haben, was die Konsolidierung erschwert. Um diese Probleme zu beheben, wurde im Navigation SDK v1.11 eine einfache API eingeführt, mit der sich dauerhafte Benachrichtigungen in der gesamten App verwalten lassen, auch innerhalb des SDK.

Dauerhafte Benachrichtigungen zusammenfassen

Komponenten

Der Dienstmanager für den Vordergrund bietet einen Wrapper für die Android-Dienstklasse für den Vordergrund und die Klasse für dauerhafte Benachrichtigungen. Die Hauptfunktion dieses Wrappers besteht darin, die Wiederverwendung der Benachrichtigungs-ID zu erzwingen, damit die Benachrichtigung für alle Vordergrunddienste freigegeben wird, die den Manager verwenden.


Das Navigation SDK enthält statische Methoden zum Initialisieren und Abrufen des ForegroundServiceManager-Singleton. Dieses Singleton kann nur einmal während der Lebensdauer des Navigation SDK initialisiert werden. Wenn Sie also einen der Initialisierungsaufrufe (initForegroundServiceManagerMessageAndIntent() oder initForegroundServiceManagerProvider()) verwenden, sollten Sie ihn mit einem try-catch-Block umgeben, falls der Pfad noch einmal aufgerufen wird. Das Navigation SDK löst eine Laufzeitausnahme aus, wenn Sie eine der beiden Methoden mehr als einmal aufrufen, es sei denn, Sie löschen zuerst alle Verweise auf ForegroundServiceManager und rufen clearForegroundServiceManager() vor jedem nachfolgenden Aufruf auf.

Die vier Parameter von initForegroundServiceManagerMessageAndIntent() sind application, notificationId, defaultMessage und resumeIntent. Wenn die letzten drei Parameter „null“ sind, handelt es sich bei der Benachrichtigung um die Standardbenachrichtigung des Navigation SDK. Es ist weiterhin möglich, andere Vordergrunddienste in der App hinter dieser Benachrichtigung zu verbergen. Mit dem Parameter notificationId wird die Benachrichtigungs-ID angegeben, die für die Benachrichtigung verwendet werden soll. Wenn er null ist, wird ein beliebiger Wert verwendet. Sie können es explizit festlegen, um Konflikte mit anderen Benachrichtigungen zu vermeiden, z. B. mit Benachrichtigungen aus einem anderen SDK. defaultMessage ist ein String, der angezeigt wird, wenn das System nicht navigiert. Der resumeIntent ist ein Intent, der ausgelöst wird, wenn auf die Benachrichtigung geklickt wird. Wenn resumeIntent null ist, werden Klicks auf die Benachrichtigung ignoriert.

Die drei Parameter von initForegroundServiceManagerProvider() sind application, notificationId und notificationProvider. Wenn die letzten beiden Parameter null sind, handelt es sich bei der Benachrichtigung um die Standardbenachrichtigung des Navigation SDK. Mit dem Parameter notificationId wird die Benachrichtigungs-ID angegeben, die für die Benachrichtigung verwendet werden soll. Wenn er null ist, wird ein beliebiger Wert verwendet. Sie können sie explizit festlegen, um Konflikte mit anderen Benachrichtigungen zu vermeiden, z. B. mit Benachrichtigungen aus einem anderen SDK. Wenn notificationProvider festgelegt ist, ist der Anbieter immer für das Generieren der Benachrichtigung verantwortlich, die gerendert werden soll.

Die getForegroundServiceManager()-Methode des Navigation SDK gibt das Singleton des Foreground Service Manager zurück. Wenn Sie noch keinen generiert haben, entspricht das dem Aufrufen von initForegroundServiceManagerMessageAndIntent() mit Nullparametern für notificationId, defaultMessage und resumeIntent.

Die ForegroundServiceManager-Klasse hat drei einfache Methoden. Die ersten beiden dienen dazu, einen Dienst in den Vordergrund zu verschieben und aus dem Vordergrund zu entfernen. Sie werden in der Regel vom erstellten Dienst aufgerufen. Wenn Sie diese Methoden verwenden, werden die Dienste der gemeinsamen persistenten Benachrichtigung zugeordnet. Die letzte Methode, updateNotification(), signalisiert dem Manager, dass sich die Benachrichtigung geändert hat und neu gerendert werden sollte.

Wenn Sie die vollständige Kontrolle über die gemeinsame dauerhafte Benachrichtigung benötigen, bietet die API eine NotificationContentProvider-Schnittstelle zum Definieren eines Benachrichtigungsanbieters, der eine einzelne Methode zum Abrufen einer Benachrichtigung mit dem aktuellen Inhalt enthält. Außerdem wird eine Basisklasse bereitgestellt, die Sie optional verwenden können, um den Anbieter zu definieren. Einer der Hauptzwecke der Basisklasse besteht darin, dass sie eine Möglichkeit bietet, updateNotification() aufzurufen, ohne auf ForegroundServiceManager zugreifen zu müssen. Wenn Sie eine Instanz des Benachrichtigungsanbieters verwenden, um neue Benachrichtigungen zu empfangen, können Sie diese interne Methode direkt aufrufen, um die Nachricht in der Benachrichtigung zu rendern.

Nutzungsszenarien

In diesem Abschnitt werden die Anwendungsfälle für die Verwendung von gemeinsamen persistenten Benachrichtigungen beschrieben.

Persistente Benachrichtigungen von Vordergrunddiensten anderer Apps ausblenden
Im einfachsten Fall wird das aktuelle Verhalten beibehalten und die dauerhafte Benachrichtigung nur zum Rendern von Informationen aus dem Navigation SDK verwendet. Andere Dienste können sich hinter dieser Benachrichtigung verbergen, indem sie die Methoden startForeground() und stopForeground() des Vordergrunddienst-Managers verwenden.
Dauerhafte Benachrichtigungen von anderen Vordergrunddiensten der App ausblenden, aber Standardtext festlegen, der angezeigt wird, wenn nicht navigiert wird
Im zweitbesten Fall wird das aktuelle Verhalten beibehalten und die dauerhafte Benachrichtigung nur zum Rendern von Navigation SDK-Informationen verwendet, es sei denn, das System navigiert nicht. Wenn das System nicht navigiert, wird der String angezeigt, der für initForegroundServiceManagerMessageAndIntent() angegeben wurde, und nicht der Standard-Navigation SDK-String, in dem „Google Maps“ erwähnt wird. Mit diesem Aufruf können Sie auch die Resume-Intention festlegen, die ausgelöst wird, wenn auf die Benachrichtigung geklickt wird.
Volle Kontrolle über das Rendern der persistenten Benachrichtigung
Im letzten Szenario muss ein Benachrichtigungsanbieter definiert und erstellt und dann mit initForegroundServiceManagerProvider() an ForegroundServiceManager übergeben werden. Mit dieser Option haben Sie die volle Kontrolle darüber, was in der Benachrichtigung gerendert wird. Allerdings werden dadurch auch die Benachrichtigungsinformationen des Navigation SDK von der Benachrichtigung getrennt, sodass die hilfreichen Abbiegehinweise in der Benachrichtigung nicht mehr angezeigt werden. Google bietet keine einfache Möglichkeit, diese Informationen abzurufen und in die Benachrichtigung einzufügen.

Beispiel für einen Benachrichtigungsanbieter

Das folgende Codebeispiel zeigt, wie Benachrichtigungen mit einem einfachen Benachrichtigungsinhaltsanbieter erstellt und zurückgegeben werden.

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 "";
   }
 }
}

Nachdem Sie NotificationContentProviderImpl erstellt haben, verbinden Sie das Navigation SDK mit dem folgenden Code damit:

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

Einschränkungen und zukünftige Pläne

  • Rufen Sie initForegroundServiceManagerMessageAndIntent() oder initForegroundServiceManagerProvider() frühzeitig auf, damit das erwartete Nutzungsszenario gut definiert ist. Sie müssen diese Methode aufrufen, bevor Sie einen neuen Navigator erstellen.
  • Achten Sie darauf, Ausnahmen von Aufrufen von initForegroundServiceManagerMessageAndIntent() oder initForegroundServiceManagerProvider() abzufangen, falls der Codepfad mehr als einmal aufgerufen wird. Im Navigation SDK v2.0 wird beim mehrmaligen Aufrufen dieser Methode eine geprüfte Ausnahme anstelle einer Laufzeit-Ausnahme ausgelöst.
  • Google muss möglicherweise noch Anpassungen vornehmen, um das Styling der Benachrichtigung über ihren gesamten Lebenszyklus hinweg an das Styling des Headers anzugleichen.
  • Wenn Sie einen Benachrichtigungsanbieter definieren, können Sie das Verhalten von Kurzinfos mit der Priorität steuern.
  • Google bietet keine einfache Möglichkeit, detaillierte Informationen zur Routenführung abzurufen, die ein Benachrichtigungsanbieter in die Benachrichtigung einfügen könnte.