A partire dal livello API Android 26, sono necessarie notifiche persistenti per i servizi in primo piano. Questo requisito ha lo scopo di impedirti di nascondere servizi che potrebbero richiedere un utilizzo eccessivo delle risorse di sistema, in particolare della batteria. Questo requisito crea un potenziale problema: se un'app con più servizi in primo piano non gestisce con attenzione la notifica in modo che venga condivisa tra tutti i servizi, possono essere presenti più notifiche persistenti non ignorabili, il che comporta un disordine indesiderato nell'elenco attivo delle notifiche.
Questo problema diventa più difficile quando utilizzi SDK come l'SDK di navigazione, che eseguono servizi in primo piano indipendenti dall'app e hanno notifiche persistenti indipendenti, il che rende difficile consolidarle.
Per risolvere questi problemi, l'SDK Navigation v1.11 ha introdotto una semplice API per
gestire le notifiche persistenti nell'app, anche all'interno dell'SDK.

Componenti
Il gestore dei servizi in primo piano fornisce un wrapper per la classe del servizio in primo piano Android e la classe delle notifiche persistenti. La funzione principale di questo wrapper è imporre il riutilizzo dell'ID notifica in modo che la notifica venga condivisa tra tutti i servizi in primo piano che utilizzano il gestore.

L'SDK di navigazione contiene metodi statici per l'inizializzazione e l'ottenimento del singleton ForegroundServiceManager. Questo singleton può essere inizializzato una sola volta nel ciclo di vita di Navigation SDK. Di conseguenza, se utilizzi una delle chiamate di inizializzazione (initForegroundServiceManagerMessageAndIntent() o initForegroundServiceManagerProvider()), devi racchiuderla in un blocco try-catch nel caso in cui venga eseguito nuovamente l'accesso a quel percorso. L'SDK di navigazione genera un'eccezione di runtime se chiami uno dei due metodi più di una volta, a meno che non cancelli prima tutti i riferimenti a ForegroundServiceManager e chiami clearForegroundServiceManager() prima di ogni chiamata successiva.
I quattro parametri di initForegroundServiceManagerMessageAndIntent() sono
application, notificationId, defaultMessage e resumeIntent. Se gli ultimi tre parametri sono null, la notifica è quella standard dell'SDK di navigazione. È comunque possibile nascondere altri servizi in primo piano nell'app dietro questa notifica. Il parametro notificationId specifica l'ID notifica da utilizzare per la notifica. Se è null, viene utilizzato un valore arbitrario. Puoi impostarlo esplicitamente per aggirare i conflitti con altre notifiche, ad esempio quelle di un altro SDK. defaultMessage è una stringa visualizzata quando il sistema non è in navigazione. resumeIntent è un intent che viene attivato quando si fa clic sulla notifica. Se resumeIntent è null, i clic sulla notifica
vengono ignorati.
I tre parametri di initForegroundServiceManagerProvider() sono
application, notificationId e notificationProvider. Se gli ultimi due parametri sono null, la notifica è quella standard di Navigation SDK. Il parametro notificationId specifica l'ID notifica da utilizzare per la notifica. Se è null, viene utilizzato un valore arbitrario. Puoi impostarlo esplicitamente per evitare conflitti con altre notifiche, ad esempio quelle di un altro SDK. Se notificationProvider è impostato, il provider è sempre responsabile della generazione della notifica da visualizzare.
Il metodo getForegroundServiceManager() dell'SDK Navigation restituisce il singleton del gestore dei servizi in primo piano. Se non ne hai ancora generato uno, equivale a chiamare initForegroundServiceManagerMessageAndIntent() con parametri nulli per notificationId, defaultMessage e resumeIntent.
ForegroundServiceManager ha tre metodi semplici. I primi due servono per spostare un servizio in primo piano e in background e vengono in genere chiamati dall'interno del servizio creato. L'utilizzo di questi metodi garantisce che i servizi siano associati alla notifica persistente condivisa. L'ultimo metodo, updateNotification(), segnala al gestore che la notifica è cambiata e deve essere visualizzata di nuovo.
Se hai bisogno di un controllo completo della notifica persistente condivisa, l'API fornisce un'interfaccia NotificationContentProvider per definire un provider di notifiche, che contiene un singolo metodo per ottenere una notifica con i contenuti attuali. Fornisce inoltre una classe base, che puoi utilizzare facoltativamente per definire il provider. Uno degli scopi principali della classe base è fornire un modo per chiamare updateNotification() senza dover accedere a ForegroundServiceManager. Se utilizzi un'istanza del provider di notifiche per ricevere nuovi messaggi di notifica, puoi chiamare direttamente questo metodo interno per eseguire il rendering del messaggio nella notifica.
Scenari di utilizzo
Questa sezione descrive in dettaglio gli scenari di utilizzo delle notifiche persistenti condivise.
- Nascondi le notifiche persistenti dei servizi in primo piano di altre app
- Lo scenario più semplice è mantenere il comportamento attuale e utilizzare la notifica persistente solo per il rendering delle informazioni dell'SDK di navigazione. Altri servizi possono nascondersi dietro questa notifica utilizzando i metodi
startForeground()estopForeground()del gestore dei servizi in primo piano. - Nascondi le notifiche persistenti di altri servizi in primo piano dell'app, ma imposta il testo predefinito mostrato quando non è attiva la navigazione
- Il secondo scenario più semplice è mantenere il comportamento attuale e utilizzare la notifica persistente solo per il rendering delle informazioni dell'SDK di navigazione, tranne quando il sistema non è in navigazione. Quando il sistema non è in navigazione, viene visualizzata la stringa fornita a
initForegroundServiceManagerMessageAndIntent()anziché la stringa predefinita dell'SDK di navigazione che menziona "Google Maps". Puoi anche utilizzare questa chiamata per impostare l'intent di ripresa che viene attivato quando si fa clic sulla notifica. - Assumi il controllo completo del rendering della notifica persistente
- Lo scenario finale richiede la definizione e la creazione di un provider di notifiche e il suo passaggio a
ForegroundServiceManagerutilizzandoinitForegroundServiceManagerProvider(). Questa opzione ti offre il controllo completo di ciò che viene visualizzato nella notifica, ma scollega anche le informazioni di notifica di Navigation SDK dalla notifica, rimuovendo così le utili indicazioni passo passo mostrate nella notifica. Google non fornisce un modo semplice per recuperare queste informazioni e inserirle nella notifica.
Esempio di provider di notifiche
Il seguente esempio di codice mostra come creare e restituire notifiche utilizzando un semplice provider di contenuti di notifica.
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 "";
}
}
}
Dopo aver creato NotificationContentProviderImpl, connetti l'SDK di navigazione utilizzando il seguente codice:
ForegroundServiceManager f = NavigationApi.getForegroundServiceManager(getApplication());
mNotification = new NotificationContentProviderImpl(getApplication());
NavigationApi.clearForegroundServiceManager();
NavigationApi.initForegroundServiceManagerProvider(getApplication(), null, mNotification);
Avvertenze e piani futuri
- Assicurati di chiamare
initForegroundServiceManagerMessageAndIntent()oinitForegroundServiceManagerProvider()in anticipo in modo che lo scenario di utilizzo previsto sia ben definito. Devi chiamare questo metodo prima di creare un nuovo navigatore. - Assicurati di rilevare le eccezioni dalle chiamate a
initForegroundServiceManagerMessageAndIntent()oinitForegroundServiceManagerProvider()nel caso in cui il percorso del codice venga inserito più di una volta. In Navigation SDK v2.0, la chiamata di questo metodo più volte genera un'eccezione controllata anziché un'eccezione di runtime. - Google potrebbe dover ancora lavorare per ottenere uno stile coerente per tutta la durata della notifica che corrisponda allo stile dell'intestazione.
- Quando definisci un provider di notifiche, puoi controllare il comportamento delle notifiche heads-up con la priorità.
- Google non fornisce un modo semplice per recuperare le informazioni passo passo che un provider di notifiche potrebbe inserire nella notifica.