Skonsoliduj powiadomienia na urządzeniach mobilnych

Od poziomu interfejsu API Androida 26 usługi na pierwszym planie wymagają stałych powiadomień. To wymaganie ma na celu zapobieganie ukrywaniu usług, które mogą nadmiernie obciążać zasoby systemowe, w szczególności baterię. To wymaganie stwarza potencjalny problem: jeśli aplikacja z wieloma usługami na pierwszym planie nie zarządza powiadomieniami w taki sposób, aby były one udostępniane we wszystkich usługach, może pojawić się wiele trwałych powiadomień, których nie można odrzucić, co prowadzi do niepożądanego bałaganu na aktywnej liście powiadomień.

Problem ten staje się jeszcze trudniejszy, gdy używasz pakietów SDK, takich jak Navigation SDK, które uruchamiają usługi działające na pierwszym planie niezależnie od aplikacji i mają własne, niezależne trwałe powiadomienia, co utrudnia ich konsolidację. Aby rozwiązać te problemy, w pakiecie Navigation SDK w wersji 1.11 wprowadziliśmy prosty interfejs API, który pomaga zarządzać trwałymi powiadomieniami w aplikacji, w tym w pakiecie SDK.

Konsolidacja stałych powiadomień

Komponenty

Menedżer usług na pierwszym planie udostępnia kod wokół klasy usługi na pierwszym planie na Androidzie i klasy powiadomień trwałych. Główną funkcją tego kodu jest wymuszanie ponownego użycia identyfikatora powiadomienia, dzięki czemu powiadomienie jest udostępniane we wszystkich usługach na pierwszym planie korzystających z menedżera.


Pakiet Navigation SDK zawiera metody statyczne do inicjowania i pobierania obiektu pojedynczego ForegroundServiceManager. Ten singleton można zainicjować tylko raz w czasie działania pakietu Navigation SDK. W związku z tym, jeśli używasz jednego z wywołań inicjujących (initForegroundServiceManagerMessageAndIntent() lub initForegroundServiceManagerProvider()), umieść je w bloku try-catch na wypadek ponownego wejścia na tę ścieżkę. Pakiet Navigation SDK zgłasza wyjątek czasu działania, jeśli wywołasz którąś z tych metod więcej niż raz, chyba że najpierw usuniesz wszystkie odwołania do obiektu ForegroundServiceManager i wywołasz metodę clearForegroundServiceManager() przed każdym kolejnym wywołaniem.

Cztery parametry initForegroundServiceManagerMessageAndIntent() to application, notificationId, defaultMessage i resumeIntent. Jeśli 3 ostatnie parametry mają wartość null, powiadomienie jest standardowym powiadomieniem pakietu Navigation SDK. Nadal można ukryć inne usługi działające na pierwszym planie w aplikacji za tym powiadomieniem. Parametr notificationId określa identyfikator powiadomienia, który powinien być używany w powiadomieniu. Jeśli jest pusta, używana jest dowolna wartość. Możesz ustawić go bezpośrednio, aby uniknąć konfliktów z innymi powiadomieniami, np. z innego pakietu SDK. defaultMessage to ciąg znaków, który jest wyświetlany, gdy system nie nawiguje. resumeIntent to intencja, która jest wywoływana po kliknięciu powiadomienia. Jeśli resumeIntent ma wartość null, kliknięcia powiadomienia są ignorowane.

Trzy parametry initForegroundServiceManagerProvider() to application, notificationId i notificationProvider. Jeśli 2 ostatnie parametry mają wartość null, powiadomienie jest standardowym powiadomieniem pakietu Navigation SDK. Parametr notificationId określa identyfikator powiadomienia, który powinien być użyty w powiadomieniu. Jeśli ma wartość null, używana jest dowolna wartość. Możesz ustawić go bezpośrednio, aby uniknąć konfliktów z innymi powiadomieniami, np. z innego pakietu SDK. Jeśli ustawiono notificationProvider, dostawca jest zawsze odpowiedzialny za generowanie powiadomienia do renderowania.

Metoda getForegroundServiceManager() pakietu Navigation SDK zwraca obiekt singleton menedżera usług działających na pierwszym planie. Jeśli nie masz jeszcze wygenerowanego identyfikatora, jest to odpowiednik wywołania initForegroundServiceManagerMessageAndIntent() z parametrami null dla notificationId, defaultMessage i resumeIntent.

ForegroundServiceManager ma 3 proste metody. Pierwsze 2 służą do przenoszenia usługi na pierwszy plan i z powrotem i są zwykle wywoływane z poziomu utworzonej usługi. Dzięki tym metodom usługi są powiązane z udostępnionym stałym powiadomieniem. Ostatnia metoda, updateNotification(), informuje menedżera, że powiadomienie uległo zmianie i powinno zostać ponownie wyrenderowane.

Jeśli potrzebujesz pełnej kontroli nad udostępnionym powiadomieniem, interfejs API udostępnia interfejs NotificationContentProvider do definiowania dostawcy powiadomień, który zawiera jedną metodę pobierania powiadomienia z bieżącą treścią. Udostępnia też klasę bazową, której możesz opcjonalnie użyć do zdefiniowania dostawcy. Jednym z głównych celów klasy bazowej jest umożliwienie wywołania metody updateNotification() bez konieczności uzyskiwania dostępu do ForegroundServiceManager. Jeśli używasz instancji dostawcy powiadomień do odbierania nowych powiadomień, możesz wywołać tę metodę wewnętrzną bezpośrednio, aby wyrenderować wiadomość w powiadomieniu.

Scenariusze użycia

W tej sekcji opisujemy scenariusze korzystania z udostępnionych trwałych powiadomień.

Ukrywanie stałych powiadomień o usługach działających na pierwszym planie w innych aplikacjach
Najprostszym rozwiązaniem jest zachowanie bieżącego działania i używanie trwałego powiadomienia tylko do renderowania informacji z pakietu SDK do nawigacji. Inne usługi mogą ukrywać się za tym powiadomieniem, korzystając z metod startForeground() i stopForeground() menedżera usług na pierwszym planie.
Ukryj stałe powiadomienia innych usług działających na pierwszym planie, ale ustaw domyślny tekst wyświetlany, gdy nie korzystasz z nawigacji
Drugi najprostszy scenariusz to zachowanie bieżącego działania i używanie stałego powiadomienia tylko do renderowania informacji z pakietu Navigation SDK, z wyjątkiem sytuacji, gdy system nie nawiguje. Gdy system nie nawiguje, wyświetlany jest ciąg tekstowy przekazany do initForegroundServiceManagerMessageAndIntent(), a nie domyślny ciąg tekstowy pakietu Navigation SDK, który wspomina o „Mapach Google”. Możesz też użyć tego wywołania, aby ustawić intencję wznowienia, która jest uruchamiana po kliknięciu powiadomienia.
Przejmij pełną kontrolę nad renderowaniem stałego powiadomienia
Ostatni scenariusz wymaga zdefiniowania i utworzenia dostawcy powiadomień oraz przekazania go do ForegroundServiceManager za pomocą initForegroundServiceManagerProvider(). Ta opcja zapewnia pełną kontrolę nad tym, co jest renderowane w powiadomieniu, ale też odłącza informacje o powiadomieniach pakietu SDK do nawigacji od powiadomienia, co powoduje usunięcie przydatnych szczegółowych wskazówek dojazdu wyświetlanych w powiadomieniu. Google nie udostępnia prostego sposobu na pobranie tych informacji i wstawienie ich do powiadomienia.

Przykładowy dostawca powiadomień

Poniższy przykładowy kod pokazuje, jak tworzyć i zwracać powiadomienia za pomocą prostego mechanizmu dostarczania treści powiadomień.

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

Po utworzeniu NotificationContentProviderImpl połącz z nim pakiet SDK Navigation za pomocą tego kodu:

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

Zastrzeżenia i przyszłe plany

  • Pamiętaj, aby wywołać initForegroundServiceManagerMessageAndIntent() lub initForegroundServiceManagerProvider() na wczesnym etapie, aby oczekiwany scenariusz użycia był dobrze zdefiniowany. Tę metodę musisz wywołać przed utworzeniem nowego obiektu Navigator.
  • Pamiętaj, aby przechwytywać wyjątki z wywołań funkcji initForegroundServiceManagerMessageAndIntent() lub initForegroundServiceManagerProvider() na wypadek, gdyby ścieżka kodu została wprowadzona więcej niż raz. W pakiecie Navigation SDK w wersji 2.0 wielokrotne wywołanie tej metody powoduje zgłoszenie wyjątku sprawdzonego, a nie wyjątku czasu działania.
  • Google może jeszcze mieć trochę pracy, aby uzyskać spójny styl przez cały okres wyświetlania powiadomienia, który pasuje do stylu nagłówka.
  • Gdy definiujesz dostawcę powiadomień, możesz kontrolować zachowanie powiadomień o wysokim priorytecie za pomocą priorytetu.
  • Google nie udostępnia prostego sposobu na pobieranie szczegółowych wskazówek dojazdu, które dostawca powiadomień może wstawić do powiadomienia.