Ab Android-API-Level 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 für alle Dienste freigegeben ist, 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 Dienste im Vordergrund unabhängig von der App ausführen und eigene unabhängige dauerhafte Benachrichtigungen haben, die sich nur schwer konsolidieren lassen.
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, einschließlich des SDK, verwalten lassen.

Komponenten
Der Dienstmanager für den Vordergrund bietet einen Wrapper für die Android-Klasse für Dienste im Vordergrund und die Klasse für persistente 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 einen der Initialisierungsaufrufe (initForegroundServiceManagerMessageAndIntent() oder initForegroundServiceManagerProvider()) verwenden, sollten Sie ihn daher mit einem try-catch-Block umgeben, falls dieser Pfad noch einmal aufgerufen wird. Das Navigation SDK löst eine Laufzeit-Ausnahme 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, z. B. von einem anderen SDK, zu vermeiden. 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 die Generierung der Benachrichtigung verantwortlich, die gerendert werden soll.
Die getForegroundServiceManager()-Methode des Navigation SDK gibt das Singleton des Dienstmanagers im Vordergrund zurück. Wenn Sie noch keinen generiert haben, entspricht dies dem Aufrufen von initForegroundServiceManagerMessageAndIntent() mit Nullparametern für notificationId, defaultMessage und resumeIntent.
Die ForegroundServiceManager bietet drei einfache Methoden. Die ersten beiden dienen dazu, einen Dienst in den Vordergrund und aus dem Vordergrund zu verschieben. Sie werden in der Regel vom Dienst aufgerufen, der erstellt wurde. Durch die Verwendung dieser Methoden wird sichergestellt, dass die Dienste mit der gemeinsamen persistenten Benachrichtigung verknüpft sind. Die letzte Methode, updateNotification(), weist den Manager darauf hin, 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 die 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.
Anwendungsszenarien
In diesem Abschnitt werden die Anwendungsfälle für die Verwendung von freigegebenen persistenten Benachrichtigungen beschrieben.
- Permanente Benachrichtigungen von anderen App-Vordergrunddiensten ausblenden
- Am einfachsten ist es, das aktuelle Verhalten beizubehalten und die dauerhafte Benachrichtigung nur zum Rendern von Informationen aus dem Navigation SDK zu verwenden. Andere Dienste können sich hinter dieser Benachrichtigung verbergen, indem sie die Methoden
startForeground()undstopForeground()des Dienstmanagers für Dienste im Vordergrund verwenden. - Dauerhafte Benachrichtigungen anderer Vordergrunddienste 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 für
initForegroundServiceManagerMessageAndIntent()bereitgestellte String anstelle des Standard-Navigation SDK-Strings angezeigt, in dem „Google Maps“ erwähnt wird. Mit diesem Aufruf können Sie auch die Resume-Absicht festlegen, die ausgelöst wird, wenn auf die Benachrichtigung geklickt wird. - Volle Kontrolle über das Rendern der dauerhaften Benachrichtigung
- Im letzten Szenario muss ein Benachrichtigungsanbieter definiert und erstellt und mit
initForegroundServiceManagerProvider()anForegroundServiceManagerü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 Hinweise zur detaillierten Routenführung 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()oderinitForegroundServiceManagerProvider()frühzeitig auf, damit das erwartete Nutzungsszenario gut definiert ist. Sie müssen diese Methode aufrufen, bevor Sie einen neuen Navigator erstellen. - Fangen Sie Ausnahmen von Aufrufen von
initForegroundServiceManagerMessageAndIntent()oderinitForegroundServiceManagerProvider()ab, 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.