Freigegebene dauerhafte Benachrichtigungen

Ab Android API-Level 26 sind dauerhafte Benachrichtigungen für Dienste im Vordergrund erforderlich. Diese Anforderung soll verhindern, dass Sie Dienste verstecken, die Systemressourcen, insbesondere den Akku, übermäßig beanspruchen könnten. Diese Anforderung führt zu einem potenziellen Problem: Wenn eine App mit mehreren Diensten im Vordergrund die Benachrichtigung nicht sorgfältig verwaltet, sodass sie für alle Dienste freigegeben wird, gibt es mehrere dauerhafte, nicht schließbare Benachrichtigungen, was zu unerwünschten Überladen in der aktiven Liste der Benachrichtigungen führt.

Dieses Problem wird schwieriger, wenn Sie SDKs wie das Navigation SDK verwenden, bei denen Dienste im Vordergrund unabhängig von der App ausgeführt werden und die eigene, unabhängige persistente Benachrichtigungen haben können, was deren Konsolidierung erschwert. Um diese Probleme zu beheben, wurde mit dem Navigation SDK v1.11 eine einfache API eingeführt, die bei der Verwaltung persistenter Benachrichtigungen in der gesamten App und im SDK unterstützt.

Dauerhafte Benachrichtigungen konsolidieren

Komponenten

Der Manager für Dienste im Vordergrund bietet einen Wrapper um die Android-Dienstklasse im Vordergrund und die persistente Benachrichtigungsklasse. Die Hauptfunktion dieses Wrappers besteht darin, die Wiederverwendung der Benachrichtigungs-ID zu erzwingen, damit die Benachrichtigung über den Manager für alle Dienste im Vordergrund freigegeben wird.


Die NavigationAPI enthält statische Methoden zum Initialisieren und Abrufen des Singleton-ForegroundServiceManager. Dieser Singleton kann während der Lebensdauer des Navigation SDK nur einmal initialisiert werden. Wenn Sie einen der Initialisierungsaufrufe (initForegroundServiceManagerMessageAndIntent() oder initForegroundServiceManagerProvider()) verwenden, sollten Sie ihn in einen Try/Catch-Block einfügen, falls dieser Pfad noch einmal eingegeben wird. Um Kompatibilitätsprobleme zu vermeiden, gibt das Navigation SDK 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 vor jedem nachfolgenden Aufruf clearForegroundServiceManager() auf. In Version 2.0 des Navigation SDK wird der API zu diesem Zweck eine geprüfte Ausnahme hinzugefügt.

Die vier Parameter von initForegroundServiceManagerMessageAndIntent() sind application, notificationId, defaultMessage und resumeIntent. Wenn die letzten drei Parameter null sind, ist die Benachrichtigung die standardmäßige Navigation SDK-Benachrichtigung. Es ist weiterhin möglich, andere Dienste im Vordergrund hinter dieser Benachrichtigung in der App auszublenden. Der Parameter notificationId gibt die Benachrichtigungs-ID an, die für die Benachrichtigung verwendet werden soll. Wenn dieser Wert null ist, wird ein beliebiger Wert verwendet. Sie können sie explizit festlegen, um Konflikte mit anderen Benachrichtigungen zu umgehen, z. B. mit denen von einem anderen SDK. defaultMessage ist ein String, der angezeigt wird, wenn das System keine Navigation ausführt. 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, ist die Benachrichtigung die standardmäßige Navigation SDK-Benachrichtigung. Der Parameter notificationId gibt die Benachrichtigungs-ID an, die für die Benachrichtigung verwendet werden soll. Wenn dieser Wert null ist, wird ein beliebiger Wert verwendet. Sie können sie explizit festlegen, um Konflikte mit anderen Benachrichtigungen zu umgehen, z. B. mit denen von einem anderen SDK. Wenn notificationProvider festgelegt ist, ist der Anbieter immer dafür verantwortlich, die zu rendernde Benachrichtigung zu generieren.

Die Methode getForegroundServiceManager() des Navigation SDK gibt den Dienstmanager im Vordergrund zurück. Wenn Sie noch keine erstellt haben, entspricht dies dem Aufruf von initForegroundServiceManagerMessageAndIntent() mit Nullparametern für notificationId, defaultMessage und resumeIntent.

Für ForegroundServiceManager gibt es drei einfache Methoden. Die ersten beiden dienen zum Verschieben eines Dienstes in den Vordergrund und aus dem Vordergrund und werden normalerweise innerhalb des erstellten Dienstes aufgerufen. Mit diesen Methoden stellen Sie sicher, dass die Dienste der gemeinsamen persistenten Benachrichtigung zugeordnet sind. Bei der letzten Methode updateNotification() wird dem Manager gemeldet, dass sich die Benachrichtigung geändert hat, und er muss noch einmal gerendert werden.

Wenn Sie die vollständige Kontrolle über den Inhalt der freigegebenen dauerhaften Benachrichtigung wünschen, bietet die neue API eine NotificationContentProvider-Schnittstelle zum Definieren eines Benachrichtigungsanbieters, die eine einzelne Methode zum Abrufen einer Benachrichtigung mit dem aktuellen Inhalt enthält. Außerdem bietet sie eine Basisklasse, mit der Sie optional den Anbieter definieren können. Einer der Hauptzwecke der Basisklasse besteht darin, dass sie eine einfache Möglichkeit bietet, updateNotification() aufzurufen, ohne auf ForegroundServiceManager zugreifen zu müssen. Diese Hilfsmethode kann nützlich sein, wenn Sie eine Instanz des Benachrichtigungsanbieters zum Empfangen neuer Benachrichtigungen verwenden. In diesem Fall können Sie diese interne Methode direkt aufrufen, um die Nachricht in der Benachrichtigung zu rendern.

Nutzungsszenarien

In diesem Abschnitt werden die Nutzungsszenarien für die Verwendung gemeinsamer persistenter Benachrichtigungen beschrieben.

Dauerhafte Benachrichtigungen anderer App-Dienste im Vordergrund ausblenden
Das einfachste Szenario ist, das aktuelle Verhalten beizubehalten und nur die dauerhafte Benachrichtigung zum Rendern von Navigation SDK-Informationen zu verwenden. Mithilfe der Methoden startForeground() und stopForeground() des Dienstmanagers im Vordergrund können andere Dienste hinter dieser Benachrichtigung verborgen werden.
Dauerhafte Benachrichtigungen anderer Dienste im Vordergrund ausblenden, aber Standardtext festlegen, der angezeigt wird, wenn Sie nicht navigieren
Das zweiteinfachste Szenario ist, das aktuelle Verhalten beizubehalten und die dauerhafte Benachrichtigung nur zum Rendern von Navigation SDK-Informationen zu verwenden, es sei denn, das System ist gerade nicht aktiv. Wenn das System keine Navigation ausführt, wird der für initForegroundServiceManagerMessageAndIntent() bereitgestellte String anstelle des Standard-Navigations-SDK-Strings angezeigt, in dem „Google Maps“ erwähnt wird. Mit diesem Aufruf kann auch der Fortsetzungs-Intent festgelegt werden, der ausgelöst wird, wenn auf die Benachrichtigung geklickt wird.
Vollständige Kontrolle über das Rendern dauerhafter Benachrichtigungen
Im letzten Szenario muss ein Benachrichtigungsanbieter definiert und erstellt und über initForegroundServiceManagerProvider() an ForegroundServiceManager übergeben werden. Mit dieser Option haben Sie die volle Kontrolle darüber, was in der Benachrichtigung gerendert wird, trennt aber auch die Benachrichtigungsinformationen des Navigation SDK von der Benachrichtigung, wodurch die hilfreichen Schritt-für-Schritt-Aufforderungen entfernt werden, die in der Benachrichtigung angezeigt werden. Google bietet noch 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 Anbieter von Benachrichtigungsinhalten 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 "";
   }
 }
}

Vorbehalte und Zukunftspläne

  • Rufen Sie initForegroundServiceManagerMessageAndIntent() oder initForegroundServiceManagerProvider() frühzeitig auf, damit das erwartete Nutzungsszenario klar definiert ist. Sie müssen diese Methode aufrufen, bevor Sie einen neuen Navigator erstellen.
  • Achten Sie darauf, Ausnahmen bei Aufrufen von initForegroundServiceManagerMessageAndIntent() oder initForegroundServiceManagerProvider() zu erfassen, falls der Codepfad mehrmals eingegeben wird. Wenn im Navigation SDK v2.0 diese Methode mehrmals aufgerufen wird, wird eher eine geprüfte Ausnahme als eine Laufzeitausnahme ausgelöst.
  • Möglicherweise muss Google noch an einem einheitlichen Stil für die gesamte Lebensdauer der Benachrichtigung arbeiten, die dem Stil der Kopfzeile entspricht.
  • Wenn Sie einen Benachrichtigungsanbieter definieren, können Sie das Vorabverhalten mit der Priorität steuern.
  • Google bietet noch keine einfache Möglichkeit zum Abrufen von detaillierten Informationen, die ein Benachrichtigungsanbieter in die Benachrichtigung einfügen könnte.