Notifiche persistenti condivise

A partire dal livello API Android 26, sono necessarie notifiche permanenti per i servizi in primo piano. Questo requisito ha lo scopo di evitare di nascondere i servizi che potrebbero richiedere troppe risorse di sistema, in particolare la batteria. Questo requisito crea un potenziale problema: se un'app con più servizi in primo piano non gestisce attentamente la notifica in modo che sia condivisa tra tutti i servizi, ci saranno più notifiche persistenti non ignorabili, che causano disordine indesiderato nell'elenco delle notifiche attive.

Questo problema diventa più difficile quando utilizzi SDK come l'SDK di navigazione, che eseguono servizi in primo piano indipendenti dall'app, che possono avere notifiche permanenti indipendenti, rendendole difficili da consolidare. Per risolvere questi problemi, l'SDK Navigation v1.11 ha introdotto una semplice API per gestire le notifiche persistenti in tutta l'app, anche all'interno dell'SDK.

Consolidare le notifiche persistenti

Componenti

Il gestore del servizio in primo piano fornisce un wrapper intorno alla classe del servizio in primo piano Android e alla classe di notifica permanente. La funzione principale di questo wrapper è l'applicazione forzata del riutilizzo dell'ID notifica in modo che la notifica venga condivisa tra tutti i servizi in primo piano che utilizzano il gestore.


NavigationAPI contiene metodi statici per l'inizializzazione e il recupero del singleton ForegroundServiceManager. Questo singleton può essere inizializzato solo una volta durante il ciclo di vita dell'SDK di navigazione. Di conseguenza, se utilizzi una delle chiamate di inizializzazione (initForegroundServiceManagerMessageAndIntent() o initForegroundServiceManagerProvider()), dovresti racchiuderla in un blocco generate/catch nel caso in cui il percorso venga reinserito. Per evitare problemi di incompatibilità, l'SDK di navigazione genera un'eccezione di runtime se chiami uno dei due metodi più di una volta, a meno che prima non cancelli tutti i riferimenti a ForegroundServiceManager e chiami clearForegroundServiceManager() prima di ogni chiamata successiva. A questo scopo, nella versione 2.0 dell'SDK di navigazione viene aggiunta un'eccezione selezionata all'API.

I quattro parametri di initForegroundServiceManagerMessageAndIntent() sono application, notificationId, defaultMessage e resumeIntent. Se gli ultimi tre parametri sono nulli, la notifica è la notifica 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 configurarla in modo esplicito per aggirare i conflitti con altre notifiche, come quelle di un altro SDK. defaultMessage è una stringa che viene visualizzata quando il sistema non è in modalità di navigazione. resumeIntent è un intent che viene attivato quando si fa clic sulla notifica. Se resumeIntent è nullo, i clic sulla notifica vengono ignorati.

I tre parametri di initForegroundServiceManagerProvider() sono application, notificationId e notificationProvider. Se gli ultimi due parametri sono nulli, la notifica è la notifica standard dell'SDK di navigazione. Il parametro notificationId specifica l'ID notifica da utilizzare per la notifica. Se è null, viene utilizzato un valore arbitrario. Puoi configurarla in modo esplicito per aggirare i conflitti con altre notifiche, come quelle di un altro SDK. Se il criterio notificationProvider è impostato, il provider è sempre responsabile di generare la notifica da visualizzare.

Il metodo getForegroundServiceManager() dell'SDK di navigazione restituisce il singleton del gestore del servizio 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 semplici metodi. I primi due consentono di spostare un servizio da e verso il primo piano e vengono generalmente chiamati dall'interno del servizio creato. L'uso di questi metodi garantisce che i servizi siano associati alla notifica permanente condivisa. Il metodo finale, updateNotification(), segnala al gestore che la notifica è cambiata e deve essere sottoposta di nuovo al rendering.

Se vuoi avere il controllo completo sui contenuti della notifica persistente condivisa, la nuova API fornisce un'interfaccia NotificationContentProvider per definire un provider di notifiche, che contiene un unico metodo per ricevere una notifica con i contenuti correnti. Fornisce inoltre una classe base, che puoi usare facoltativamente per definire il provider. Uno degli scopi principali della classe base è che fornisce un mezzo semplice per chiamare updateNotification() senza dover accedere a ForegroundServiceManager. Questo metodo helper può essere utile se utilizzi un'istanza del provider di notifica per ricevere nuovi messaggi di notifica, nel qual caso puoi chiamare questo metodo interno direttamente per eseguire il rendering del messaggio nella notifica.

Scenari di utilizzo

Questa sezione descrive in dettaglio gli scenari di utilizzo per l'utilizzo delle notifiche permanenti condivise.

Nascondi notifiche permanenti di altri servizi in primo piano delle app
Lo scenario più semplice è preservare il comportamento attuale e utilizzare solo la notifica persistente per visualizzare le informazioni dell'SDK di navigazione. Altri servizi possono nascondersi dietro questa notifica utilizzando i metodi di gestore del servizio in primo piano startForeground() e stopForeground().
Nascondi notifiche permanenti di altri servizi delle app in primo piano, ma imposta il testo predefinito mostrato quando non navighi
Il secondo scenario più semplice consiste nel preservare il comportamento attuale e utilizzare solo la notifica persistente per visualizzare le informazioni dell'SDK di navigazione, tranne quando il sistema non è in modalità di navigazione. Quando il sistema non naviga, viene visualizzata la stringa fornita a initForegroundServiceManagerMessageAndIntent() anziché la stringa predefinita dell'SDK di navigazione che menziona "Google Maps". Questa chiamata può essere utilizzata anche per impostare l'intent che si attiva quando si fa clic sulla notifica.
Assumi il pieno controllo del rendering della notifica persistente
Lo scenario finale richiede la definizione e la creazione di un fornitore di notifiche e il suo trasferimento a ForegroundServiceManager tramite initForegroundServiceManagerProvider(). Questa opzione ti offre il pieno controllo degli elementi visualizzati nella notifica, ma disconnette anche le informazioni di notifica dell'SDK di navigazione dalla notifica, rimuovendo così le utili richieste passo passo mostrate nella notifica. Google non fornisce ancora un semplice mezzo per recuperare queste informazioni e inserirle nella notifica.

Esempio di fornitore di notifiche

L'esempio di codice seguente mostra come creare e restituire notifiche utilizzando un semplice fornitore di contenuti delle notifiche.

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

Precisazioni e piani futuri

  • Assicurati di chiamare initForegroundServiceManagerMessageAndIntent() o initForegroundServiceManagerProvider() in anticipo, in modo da definire bene lo scenario di utilizzo previsto. Devi chiamare questo metodo prima di creare un nuovo navigatore.
  • Assicurati di rilevare le eccezioni dalle chiamate a initForegroundServiceManagerMessageAndIntent() o initForegroundServiceManagerProvider() nel caso in cui il percorso di codice venga inserito più di una volta. In Navigation SDK v2.0, se chiami questo metodo più volte, viene generata un'eccezione selezionata anziché un'eccezione di runtime.
  • Google potrebbe avere ancora del lavoro da fare per ottenere uno stile coerente per tutta la durata della notifica in base allo stile dell'intestazione.
  • Quando definisci un fornitore di notifiche, puoi controllare il comportamento delle notifiche in base alla priorità.
  • Google non fornisce ancora un modo semplice per recuperare informazioni passo passo che un fornitore di notifiche potrebbe inserire nella notifica.