Tworzenie powiadomienia

Powiadomienia zawierają krótkie i aktualne informacje o zdarzeniach w aplikacji, gdy nie jest ona używana. W tym dokumencie opisujemy, jak utworzyć powiadomienie z różnymi funkcjami. Szczegółowe informacje o sposobie wyświetlania powiadomień na Androidzie znajdziesz w artykule Omówienie powiadomień. Przykładowy kod, który korzysta z powiadomień, znajdziesz w przykładzie na GitHubie.

Kod na tej stronie korzysta z interfejsów API NotificationCompat z biblioteki AndroidaX. Te interfejsy API pozwalają dodawać funkcje dostępne tylko w nowszych wersjach Androida, zachowując zgodność z Androidem 9 (poziom API 28). Jednak niektóre funkcje, takie jak odpowiedź w tekście, we wcześniejszych wersjach powodują brak działania.

Dodawanie podstawowej biblioteki AndroidaX

Chociaż większość projektów tworzonych w Android Studio zawiera zależności niezbędne do korzystania z NotificationCompat, sprawdź, czy plik build.gradle na poziomie modułu zawiera tę zależność:

Odlotowe

dependencies {
    implementation "androidx.core:core:2.2.0"
}

Kotlin

dependencies {
    implementation("androidx.core:core-ktx:2.2.0")
}

Tworzenie powiadomienia podstawowego

Powiadomienie w najbardziej podstawowej i zwięzłej formie – nazywanej też formą zwiniętej – zawiera ikonę, tytuł i niewielką ilość tekstu. W tej sekcji pokazujemy, jak utworzyć powiadomienie, które użytkownik będzie mógł kliknąć, aby uruchomić aktywność w Twojej aplikacji.

Rysunek 1. Powiadomienie z ikoną, tytułem i tekstem.

Aby dowiedzieć się więcej o poszczególnych częściach powiadomienia, przeczytaj artykuł o anatomii powiadomień.

Deklarowanie uprawnień w czasie działania

Android 13 (poziom interfejsu API 33) i nowsze wersje obsługują uprawnienia w czasie działania umożliwiające publikowanie z aplikacji powiadomień, które nie są zwolnione z obowiązku posiadania licencji (w tym powiadomień usług działających na pierwszym planie).

Uprawnienie, które musisz zadeklarować w pliku manifestu aplikacji, pojawia się w tym fragmencie kodu:

<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

Więcej informacji o uprawnieniach w czasie działania znajdziesz w sekcji Uprawnienia w środowisku działania powiadomień.

Ustawianie treści powiadomień

Aby rozpocząć, ustaw treść i kanał powiadomienia za pomocą obiektu NotificationCompat.Builder. Poniższy przykład pokazuje, jak utworzyć powiadomienie z tymi informacjami:

  • Mała ikona, ustawiona przez: setSmallIcon(). To jedyna wymagana treść widoczna dla użytkowników.

  • Tytuł określony przez: setContentTitle().

  • Tekst główny ustawiony przez: setContentText().

  • Priorytet powiadomień ustawiony przez setPriority(). Priorytet określa, jak uciążliwe jest powiadomienie na Androidzie 7.1 i starszych. W przypadku Androida w wersji 8.0 i nowszych ustaw znaczenie kanału w sposób pokazany w następnej sekcji.

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle(textTitle)
        .setContentText(textContent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle(textTitle)
        .setContentText(textContent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

Konstruktor NotificationCompat.Builder wymaga podania identyfikatora kanału. Jest to wymagane na potrzeby zgodności z Androidem 8.0 (poziom interfejsu API 26) i nowszymi wersjami, ale jest ignorowane przez wcześniejsze wersje.

Domyślnie tekst powiadomienia jest skracany do 1 wiersza. Dodatkowe informacje możesz wyświetlić, tworząc powiadomienie rozwijane.

Rysunek 2. Rozwijane powiadomienie w postaci zwiniętych i rozwiniętych.

Jeśli chcesz wydłużyć powiadomienie, możesz włączyć powiadomienie rozwijane, dodając szablon stylu za pomocą właściwości setStyle(). Na przykład ten kod tworzy większy obszar tekstowy:

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(new NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

Więcej informacji o innych stylach powiadomień wyświetlanych w dużych rozmiarach, w tym o dodawaniu obrazów i elementów sterujących odtwarzaniem multimediów, znajdziesz w artykule Tworzenie powiadomienia rozwijanego.

Tworzenie kanału i określanie ważności

Zanim będzie możliwe dostarczenie powiadomienia na Androidzie 8.0 i nowszych, zarejestruj kanał powiadomień aplikacji w systemie, przekazując wystąpienie NotificationChannel do createNotificationChannel(). Ten kod jest blokowany przez warunek w wersji SDK_INT:

Kotlin

private fun createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is not in the Support Library.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val name = getString(R.string.channel_name)
        val descriptionText = getString(R.string.channel_description)
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
            description = descriptionText
        }
        // Register the channel with the system.
        val notificationManager: NotificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

Java

private void createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is not in the Support Library.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        CharSequence name = getString(R.string.channel_name);
        String description = getString(R.string.channel_description);
        int importance = NotificationManager.IMPORTANCE_DEFAULT;
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
        channel.setDescription(description);
        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this.
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
    }
}

Ponieważ musisz utworzyć kanał powiadomień przed opublikowaniem jakichkolwiek powiadomień na Androidzie 8.0 i nowszych, wykonaj ten kod od razu po uruchomieniu aplikacji. Możesz bezpiecznie wywoływać to wielokrotnie, ponieważ utworzenie istniejącego kanału powiadomień nie powoduje żadnej operacji.

Konstruktor NotificationChannel wymaga elementu importance zawierającego jedną ze stałych z klasy NotificationManager. Ten parametr określa sposób, w jaki użytkownik może przerywać interesowanie użytkownika w przypadku każdego powiadomienia, które należy do tego kanału. Ustaw priorytet za pomocą ustawienia setPriority(), aby zapewnić obsługę Androida w wersji 7.1 i starszych, jak pokazano w poprzednim przykładzie.

Mimo że musisz ustawić ważność lub priorytet powiadomienia, zgodnie z poniższym przykładem, system nie gwarantuje zachowania alertu. W niektórych przypadkach system może zmienić poziom ważności na podstawie innych czynników, a użytkownik może zawsze ponownie zdefiniować poziom ważności dla danego kanału.

Aby dowiedzieć się więcej o tym, co oznaczają poszczególne poziomy, przeczytaj artykuł o poziomach ważności powiadomień.

Ustawianie działania kliknięcia powiadomienia

Każde powiadomienie musi reagować na kliknięcie – zwykle uruchamia ono powiązane z nim działanie w aplikacji. Aby to zrobić, określ intencję treści zdefiniowaną za pomocą obiektu PendingIntent i przekaż ją do setContentIntent().

Ten fragment kodu pokazuje, jak utworzyć podstawową intencję otwierającą działanie, gdy użytkownik kliknie powiadomienie:

Kotlin

// Create an explicit intent for an Activity in your app.
val intent = Intent(this, AlertDetails::class.java).apply {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)

val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        // Set the intent that fires when the user taps the notification.
        .setContentIntent(pendingIntent)
        .setAutoCancel(true)

Java

// Create an explicit intent for an Activity in your app.
Intent intent = new Intent(this, AlertDetails.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        // Set the intent that fires when the user taps the notification.
        .setContentIntent(pendingIntent)
        .setAutoCancel(true);

Wywołuje on metodę setAutoCancel(), która automatycznie usuwa powiadomienie, gdy użytkownik je kliknie.

Metoda setFlags() przedstawiona w poprzednim przykładzie zachowuje oczekiwany sposób nawigacji użytkownika po otwarciu aplikacji za pomocą powiadomienia. Możesz jej użyć w zależności od rodzaju rozpoczynanej aktywności, którym może być:

  • Działanie, które istnieje wyłącznie w odniesieniu do odpowiedzi na powiadomienie. Nie ma powodu, dla którego użytkownik przechodzi do tego działania podczas normalnego korzystania z aplikacji, więc uruchamia nowe zadanie, a nie zostaje dodane do istniejącego zadania i stosu aplikacji. Jest to typ intencji utworzonej w poprzednim przykładzie.

  • Aktywność występująca w zwykłym przepływie aplikacji. W takim przypadku uruchomienie działania powoduje utworzenie stosu wstecznego, dzięki czemu użytkownik może zachować oczekiwania związane z przyciskami Kopia zapasowa i Wstecz.

Więcej informacji o różnych sposobach konfigurowania intencji powiadomienia znajdziesz w artykule Rozpoczynanie działania z poziomu powiadomienia.

Wyświetlanie powiadomienia

Aby wyświetlić powiadomienie, wywołaj metodę NotificationManagerCompat.notify(), przekazując mu unikalny identyfikator powiadomienia oraz wynik NotificationCompat.Builder.build(). Widać to w tym przykładzie:

Kotlin

with(NotificationManagerCompat.from(this)) {
    if (ActivityCompat.checkSelfPermission(
            this@MainActivity,
            Manifest.permission.POST_NOTIFICATIONS
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        // TODO: Consider calling
        // ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        // public fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
        //                                        grantResults: IntArray)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.

        return@with
    }
    // notificationId is a unique int for each notification that you must define.
    notify(NOTIFICATION_ID, builder.build())
}

Java

with(NotificationManagerCompat.from(this)) {
   if (ActivityCompat.checkSelfPermission(
           this@MainActivity,
           Manifest.permission.POST_NOTIFICATIONS
       ) != PackageManager.PERMISSION_GRANTED
   ) {
       // TODO: Consider calling
       // ActivityCompat#requestPermissions
       // here to request the missing permissions, and then overriding
       // public void onRequestPermissionsResult(int requestCode, String[] permissions,
       //                                        int[] grantResults)
       // to handle the case where the user grants the permission. See the documentation
       // for ActivityCompat#requestPermissions for more details.

       return
   }
   // notificationId is a unique int for each notification that you must define.
   notify(NOTIFICATION_ID, builder.build())
}

Zapisz identyfikator powiadomienia przekazywany usłudze NotificationManagerCompat.notify(), bo będzie on potrzebny podczas aktualizacji lub usunięcia powiadomienia.

Dodatkowo, aby przetestować podstawowe powiadomienia na urządzeniach z Androidem 13 lub nowszym, włącz powiadomienia ręcznie lub utwórz okno z prośbą o powiadomienia.

Dodaj przyciski poleceń

Powiadomienie może zawierać maksymalnie trzy przyciski poleceń, które pozwalają użytkownikowi szybko odpowiedzieć, np. odłożyć przypomnienie lub odpowiedzieć na SMS-a. Nie mogą one jednak powielać czynności wykonanej po kliknięciu powiadomienia przez użytkownika.

Rysunek 3. Powiadomienie z 1 przyciskiem działania.

Aby dodać przycisk polecenia, przekaż PendingIntent do metody addAction(). Przypomina to konfigurowanie domyślnego działania kliknięcia powiadomienia. Zamiast uruchamiać aktywność, możesz np. uruchomić BroadcastReceiver, które wykonuje zadanie w tle, by nie przerywało działania aplikacji, która jest już otwarta.

Na przykład ten kod pokazuje, jak wysłać komunikat do określonego odbiornika:

Kotlin


val ACTION_SNOOZE = "snooze"

val snoozeIntent = Intent(this, MyBroadcastReceiver::class.java).apply {
    action = ACTION_SNOOZE
    putExtra(EXTRA_NOTIFICATION_ID, 0)
}
val snoozePendingIntent: PendingIntent =
    PendingIntent.getBroadcast(this, 0, snoozeIntent, 0)
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent)

Java


String ACTION_SNOOZE = "snooze"

Intent snoozeIntent = new Intent(this, MyBroadcastReceiver.class);
snoozeIntent.setAction(ACTION_SNOOZE);
snoozeIntent.putExtra(EXTRA_NOTIFICATION_ID, 0);
PendingIntent snoozePendingIntent =
        PendingIntent.getBroadcast(this, 0, snoozeIntent, 0);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent);

Więcej informacji o tworzeniu funkcji BroadcastReceiver do uruchamiania zadań w tle znajdziesz w artykule Omówienie transmisji.

Jeśli zamiast tego próbujesz utworzyć powiadomienie za pomocą przycisków odtwarzania multimediów, np. wstrzymywać lub pomijać utwory, dowiedz się, jak utworzyć powiadomienie za pomocą elementów sterujących multimediami.

Dodawanie bezpośredniej odpowiedzi

Działanie bezpośredniej odpowiedzi, wprowadzone w Androidzie 7.0 (poziom interfejsu API 24), umożliwia użytkownikom wpisywanie tekstu bezpośrednio w powiadomieniu. Następnie tekst jest dostarczany do aplikacji bez otwierania aktywności. Możesz na przykład użyć bezpośredniej odpowiedzi, aby z poziomu powiadomienia zezwolić użytkownikom na odpowiadanie na SMS-y lub aktualizować listy zadań.

Rysunek 4. Dotknięcie przycisku „Odpowiedz” powoduje otwarcie tekstu.

Bezpośrednia odpowiedź pojawia się w powiadomieniu jako dodatkowy przycisk, który umożliwia wpisanie tekstu. Gdy użytkownik skończy pisać, system dołączy odpowiedź tekstową do intencji określonej dla działania powiadomienia i wysyła intencję do aplikacji.

Dodawanie przycisku odpowiedzi

Aby utworzyć działanie związane z powiadomieniem, które obsługuje bezpośrednią odpowiedź, wykonaj te czynności:

  1. Utwórz instancję RemoteInput.Builder, którą możesz dodać do działania powiadamiania. Konstruktor tej klasy akceptuje ciąg znaków, którego system używa jako klucza w danych wejściowych. Aplikacja używa później tego klucza do pobrania tekstu danych wejściowych.

    Kotlin

      // Key for the string that's delivered in the action's intent.
      private val KEY_TEXT_REPLY = "key_text_reply"
      var replyLabel: String = resources.getString(R.string.reply_label)
      var remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run {
          setLabel(replyLabel)
          build()
      }
      

    Java

      // Key for the string that's delivered in the action's intent.
      private static final String KEY_TEXT_REPLY = "key_text_reply";
    
      String replyLabel = getResources().getString(R.string.reply_label);
      RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
              .setLabel(replyLabel)
              .build();
      
  2. Utwórz PendingIntent dla działania dotyczącego odpowiedzi.

    Kotlin

      // Build a PendingIntent for the reply action to trigger.
      var replyPendingIntent: PendingIntent =
          PendingIntent.getBroadcast(applicationContext,
              conversation.getConversationId(),
              getMessageReplyIntent(conversation.getConversationId()),
              PendingIntent.FLAG_UPDATE_CURRENT)
      

    Java

      // Build a PendingIntent for the reply action to trigger.
      PendingIntent replyPendingIntent =
              PendingIntent.getBroadcast(getApplicationContext(),
                      conversation.getConversationId(),
                      getMessageReplyIntent(conversation.getConversationId()),
                      PendingIntent.FLAG_UPDATE_CURRENT);
      
  3. Dołącz obiekt RemoteInput do działania za pomocą addRemoteInput().

    Kotlin

      // Create the reply action and add the remote input.
      var action: NotificationCompat.Action =
          NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
              getString(R.string.label), replyPendingIntent)
              .addRemoteInput(remoteInput)
              .build()
      

    Java

      // Create the reply action and add the remote input.
      NotificationCompat.Action action =
              new NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
                      getString(R.string.label), replyPendingIntent)
                      .addRemoteInput(remoteInput)
                      .build();
      
  4. Zastosuj działanie do powiadomienia i wyślij powiadomienie.

    Kotlin

      // Build the notification and add the action.
      val newMessageNotification = Notification.Builder(context, CHANNEL_ID)
              .setSmallIcon(R.drawable.ic_message)
              .setContentTitle(getString(R.string.title))
              .setContentText(getString(R.string.content))
              .addAction(action)
              .build()
    
      // Issue the notification.
      with(NotificationManagerCompat.from(this)) {
          notificationManager.notify(notificationId, newMessageNotification)
      }
      

    Java

      // Build the notification and add the action.
      Notification newMessageNotification = new Notification.Builder(context, CHANNEL_ID)
              .setSmallIcon(R.drawable.ic_message)
              .setContentTitle(getString(R.string.title))
              .setContentText(getString(R.string.content))
              .addAction(action)
              .build();
    
      // Issue the notification.
      NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
      notificationManager.notify(notificationId, newMessageNotification);
      

System prosi użytkownika o wpisanie odpowiedzi po wywołaniu działania powiadomienia, jak widać na rysunku 4.

Pobierz dane wejściowe użytkownika z odpowiedzi

Aby w interfejsie odpowiedzi powiadomienia otrzymywać informacje od użytkownika, wywołaj RemoteInput.getResultsFromIntent(), przekazując w ten sposób Intent otrzymaną przez urządzenie BroadcastReceiver:

Kotlin

private fun getMessageText(intent: Intent): CharSequence? {
    return RemoteInput.getResultsFromIntent(intent)?.getCharSequence(KEY_TEXT_REPLY)
}

Java

private CharSequence getMessageText(Intent intent) {
    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
    if (remoteInput != null) {
        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
    }
    return null;
 }

Po przetworzeniu tekstu zaktualizuj powiadomienie, wywołując funkcję NotificationManagerCompat.notify() z tym samym identyfikatorem i tagiem, jeśli jest używany. Konieczne jest ukrycie interfejsu bezpośredniej odpowiedzi i potwierdzenie użytkownika, że jego odpowiedź została prawidłowo odebrana i przetworzona.

Kotlin

// Build a new notification, which informs the user that the system
// handled their interaction with the previous notification.
val repliedNotification = Notification.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_message)
        .setContentText(getString(R.string.replied))
        .build()

// Issue the new notification.
NotificationManagerCompat.from(this).apply {
    notificationManager.notify(notificationId, repliedNotification)
}

Java

// Build a new notification, which informs the user that the system
// handled their interaction with the previous notification.
Notification repliedNotification = new Notification.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_message)
        .setContentText(getString(R.string.replied))
        .build();

// Issue the new notification.
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(notificationId, repliedNotification);

Pracując z tym nowym powiadomieniem, użyj kontekstu przekazanego do metody onReceive() odbiorcy.

Dołącz odpowiedź u dołu powiadomienia, wywołując metodę setRemoteInputHistory(). Jeśli jednak tworzysz aplikację do obsługi wiadomości, utwórz powiadomienie w stylu wiadomości i dołącz nową wiadomość do rozmowy.

Więcej wskazówek dotyczących powiadomień z komunikatorów znajdziesz w sekcji ze sprawdzonymi metodami dotyczącymi aplikacji do obsługi wiadomości.

Dodaj pasek postępu

Powiadomienia mogą zawierać animowany wskaźnik postępu, który pokazuje użytkownikom stan trwającej operacji.

Rysunek 5. Pasek postępu podczas wykonywania operacji.

Jeśli w dowolnym momencie możesz oszacować, jaka część operacji została ukończona, użyj wskaźnika oznaczającego, jak to widać na ilustracji 5, przez wywołanie metody setProgress(max, progress, false). Pierwszym z nich jest wartość „complete”, np. 100. Po drugie, w jakim stopniu. Ostatni oznacza, że jest to pasek określonego postępu.

W trakcie operacji stale wywołuj setProgress(max, progress, false) ze zaktualizowaną wartością progress i ponownie wysyłaj powiadomienie, jak pokazano w przykładzie poniżej.

Kotlin

val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
    setContentTitle("Picture Download")
    setContentText("Download in progress")
    setSmallIcon(R.drawable.ic_notification)
    setPriority(NotificationCompat.PRIORITY_LOW)
}
val PROGRESS_MAX = 100
val PROGRESS_CURRENT = 0
NotificationManagerCompat.from(this).apply {
    // Issue the initial notification with zero progress.
    builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false)
    notify(notificationId, builder.build())

    // Do the job that tracks the progress here.
    // Usually, this is in a worker thread.
    // To show progress, update PROGRESS_CURRENT and update the notification with:
    // builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
    // notificationManager.notify(notificationId, builder.build());

    // When done, update the notification once more to remove the progress bar.
    builder.setContentText("Download complete")
            .setProgress(0, 0, false)
    notify(notificationId, builder.build())
}

Java

...
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setContentTitle("Picture Download")
        .setContentText("Download in progress")
        .setSmallIcon(R.drawable.ic_notification)
        .setPriority(NotificationCompat.PRIORITY_LOW);

// Issue the initial notification with zero progress.
int PROGRESS_MAX = 100;
int PROGRESS_CURRENT = 0;
builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
notificationManager.notify(notificationId, builder.build());

// Do the job that tracks the progress here.
// Usually, this is in a worker thread.
// To show progress, update PROGRESS_CURRENT and update the notification with:
// builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
// notificationManager.notify(notificationId, builder.build());

// When done, update the notification once more to remove the progress bar.
builder.setContentText("Download complete")
        .setProgress(0,0,false);
notificationManager.notify(notificationId, builder.build());

Na końcu operacji progress musi być równa max. Możesz opuścić pasek postępu, aby pokazać, że operacja została wykonana, lub ją usunąć. W obu przypadkach zaktualizuj tekst powiadomienia, aby wskazać, że operacja została zakończona. Aby usunąć pasek postępu, wywołaj setProgress(0, 0, false).

Aby wyświetlić nieokreślony pasek postępu (pasek, który nie wskazuje procentu ukończenia), wywołaj funkcję setProgress(0, 0, true). Wynik to wskaźnik mający taki sam styl jak poprzedni pasek postępu, z tym że jest to ciągła animacja, która nie wskazuje ukończenia. Animacja postępu będzie się wyświetlać, dopóki nie wywołasz funkcji setProgress(0, 0, false). Następnie zaktualizuje powiadomienie, by usunąć wskaźnik aktywności.

Pamiętaj, aby zmienić tekst powiadomienia, aby wskazać, że operacja została zakończona.

Ustawianie kategorii systemowej

Android używa zdefiniowanych wstępnie kategorii systemowych, aby określić, czy chcesz zakłócić dane powiadomienie, gdy użytkownik włączy tryb Nie przeszkadzać.

Jeśli Twoje powiadomienie zalicza się do jednej z kategorii powiadomień zdefiniowanych w NotificationCompat – np. CATEGORY_ALARM, CATEGORY_REMINDER, CATEGORY_EVENT lub CATEGORY_CALL, zadeklaruj je, przesyłając odpowiednią kategorię do setCategory():

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE)

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE);

System wykorzystuje te informacje o kategorii powiadomień do podejmowania decyzji o wyświetlaniu powiadomienia, gdy urządzenie jest w trybie Nie przeszkadzać. Nie musisz jednak tego robić. Rób to tylko wtedy, gdy Twoje powiadomienia pasują do jednej z kategorii zdefiniowanych w NotificationCompat.

Pokaż pilną wiadomość

Twoja aplikacja może chcieć wyświetlić pilną wiadomość, np. informację o nadchodzącym połączeniu telefonicznym lub dzwoniącym alarmie. W takich sytuacjach możesz powiązać z powiadomieniem intencję pełnoekranową.

W zależności od stanu blokady urządzenia po wywołaniu powiadomienia użytkownik zobaczy jedną z tych sytuacji:

  • Jeśli urządzenie użytkownika jest zablokowane, aktywność na pełnym ekranie zasłania ekran blokady.
  • Jeśli urządzenie użytkownika jest odblokowane, powiadomienie jest wyświetlane w rozwiniętej formie z opcjami obsługi lub zamknięcia powiadomienia.

Ten fragment kodu pokazuje, jak powiązać powiadomienie z intencją pełnoekranową:

Kotlin

val fullScreenIntent = Intent(this, ImportantActivity::class.java)
val fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
    fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setFullScreenIntent(fullScreenPendingIntent, true)

Java

Intent fullScreenIntent = new Intent(this, ImportantActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
        fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setFullScreenIntent(fullScreenPendingIntent, true);

Ustawianie widoczności ekranu blokady

Aby kontrolować poziom szczegółów widocznych w powiadomieniu na ekranie blokady, wywołaj metodę setVisibility() i podaj jedną z tych wartości:

  • VISIBILITY_PUBLIC: na ekranie blokady jest pełna treść powiadomienia.

  • VISIBILITY_SECRET: na ekranie blokady nie wyświetla się żadna część powiadomienia.

  • VISIBILITY_PRIVATE: na ekranie blokady wyświetlają się tylko podstawowe informacje, takie jak ikona powiadomienia i tytuł treści. Nie widać całej treści powiadomienia.

Po ustawieniu VISIBILITY_PRIVATE możesz też podać alternatywną wersję treści powiadomień, która ukrywa niektóre szczegóły. Na przykład aplikacja do SMS-ów może wyświetlać powiadomienie „Masz 3 nowe SMS-y”, ale ich treść i nadawcy będą ukryte. Aby przekazać to powiadomienie alternatywne, najpierw utwórz powiadomienie alternatywne przy użyciu NotificationCompat.Builder w zwykły sposób. Następnie dołącz powiadomienie alternatywne do zwykłego powiadomienia za pomocą setPublicVersion().

Pamiętaj, że użytkownik zawsze ma pełną kontrolę nad tym, czy jego powiadomienia są wyświetlane na ekranie blokady, i może je kontrolować na podstawie kanałów powiadomień aplikacji.

Aktualizowanie powiadomienia

Aby zaktualizować powiadomienie po jego wysłaniu, wywołaj ponownie NotificationManagerCompat.notify(), przekazując mu ten sam identyfikator co wcześniej. Jeśli poprzednie powiadomienie zostanie odrzucone, zamiast niego zostanie utworzone nowe.

Opcjonalnie możesz wywołać metodę setOnlyAlertOnce(), aby powiadomienie przeszkadzało użytkownikowi – w postaci dźwięków, wibracji lub wskazówek wizualnych – tylko przy pierwszym wyświetleniu powiadomienia, a nie przy kolejnych aktualizacjach.

Usuwanie powiadomienia

Powiadomienia pozostają widoczne, dopóki nie wystąpi jedna z tych sytuacji:

  • Użytkownik odrzuci powiadomienie.
  • Użytkownik klika powiadomienie, jeśli podczas tworzenia powiadomienia zadzwonisz do użytkownika setAutoCancel().
  • Wywołujesz cancel(), aby uzyskać konkretny identyfikator powiadomienia. Ta metoda usuwa też bieżące powiadomienia.
  • Wywołujesz cancelAll(), co spowoduje usunięcie wszystkich wysłanych wcześniej powiadomień.
  • Upływ czasu upłynie, jeśli podczas tworzenia powiadomienia ustawisz limit czasu przy użyciu setTimeoutAfter(). W razie potrzeby możesz anulować powiadomienie przed upływem określonego czasu oczekiwania.

Sprawdzone metody dotyczące aplikacji do obsługi wiadomości

Tworząc powiadomienia dla aplikacji do obsługi wiadomości i czatu, pamiętaj o wymienionych tu sprawdzonych metodach.

Używaj MessagingStyle

Począwszy od Androida 7.0 (poziom interfejsu API 24) Android udostępnia szablon stylu powiadomień przeznaczony specjalnie do treści wiadomości. Za pomocą klasy NotificationCompat.MessagingStyle możesz zmienić niektóre etykiety wyświetlane w powiadomieniu, w tym tytuł wątku, dodatkowe wiadomości oraz widok treści powiadomienia.

Ten fragment kodu pokazuje, jak dostosować styl powiadomienia za pomocą klasy MessagingStyle.

Kotlin

val user = Person.Builder()
    .setIcon(userIcon)
    .setName(userName)
    .build()

val notification = NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("2 new messages with $sender")
    .setContentText(subject)
    .setSmallIcon(R.drawable.new_message)
    .setStyle(NotificationCompat.MessagingStyle(user)
        .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
        .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
    )
    .build()

Java

Person user = new Person.Builder()
    .setIcon(userIcon)
    .setName(userName)
    .build();

Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("2 new messages with " + sender)
    .setContentText(subject)
    .setSmallIcon(R.drawable.new_message)
    .setStyle(new NotificationCompat.MessagingStyle(user)
        .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
        .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
    )
    .build();

Począwszy od Androida 9.0 (poziom interfejsu API 28) trzeba też używać klasy Person, aby optymalnie wyrenderować powiadomienie i jego awatary.

Jeśli używasz NotificationCompat.MessagingStyle, wykonaj te czynności:

  • Zadzwoń pod numer MessagingStyle.setConversationTitle(), aby ustawić tytuł czatów grupowych z więcej niż 2 osobami. Prawidłowym tytułem rozmowy może być nazwa czatu grupowego lub lista uczestników rozmowy (jeśli jej nie ma). W przeciwnym razie wiadomość może zostać pomylona jako należąca do rozmowy 1:1 z nadawcą ostatniej wiadomości w wątku.
  • Aby dołączyć wiadomości multimedialne, takie jak obrazy, użyj metody MessagingStyle.setData(). Obsługiwane są typy MIME wzorca image/*.

Używaj odpowiedzi bezpośredniej

Bezpośrednia odpowiedź pozwala użytkownikowi odpowiedzieć bezpośrednio na wiadomość.

  • Gdy użytkownik odpowie w treści odpowiedzi w ramach odpowiedzi w tekście, użyj polecenia MessagingStyle.addMessage(), aby zaktualizować powiadomienie MessagingStyle. Nie wycofuj go ani nie anuluj. Jeśli nie anulujesz powiadomienia, użytkownik będzie mógł wysłać kilka odpowiedzi z poziomu powiadomienia.
  • Aby funkcja odpowiedzi w tekście była zgodna z Wear OS, wywołaj Action.WearableExtender.setHintDisplayInlineAction(true).
  • Użyj metody addHistoricMessage(), aby zapewnić kontekst bezpośredniej odpowiedzi, dodając do powiadomienia wiadomości historyczne.

Włącz Inteligentną odpowiedź

  • Aby włączyć Inteligentną odpowiedź, wywołaj setAllowGeneratedResponses(true) przy odpowiedzi. Dzięki temu odpowiedzi Inteligentnej odpowiedzi będą dostępne dla użytkowników, gdy powiadomienie zostanie połączone z urządzeniem z Wear OS. Odpowiedzi Inteligentnej odpowiedzi są generowane przez model systemów uczących się działający w całości na zegarku, wykorzystując kontekst podany w powiadomieniu NotificationCompat.MessagingStyle. Żadne dane nie są przesyłane do internetu w celu wygenerowania odpowiedzi.

Dodaj metadane powiadomień