Tworzenie powiadomienia

Powiadomienia dostarczają krótkich, aktualnych informacji o zdarzeniach w aplikacji, gdy nie jest ona używana. Z tego dokumentu dowiesz się, jak utworzyć powiadomienie z różnymi funkcjami. Więcej informacji o tym, jak wyglądają powiadomienia na Androidzie, znajdziesz w artykule Omówienie powiadomień. Przykładowy kod korzystający z powiadomień znajdziesz na GitHubie w przykładowym projekcie dotyczącym funkcji People.

Kod na tej stronie korzysta z interfejsów API NotificationCompat z biblioteki AndroidaX. Te interfejsy API umożliwiają dodawanie funkcji dostępnych tylko w nowszych wersjach Androida, przy zachowaniu zgodności wstecznej z Androidem 9 (poziom API 28). Niektóre funkcje, takie jak odpowiadanie w tekście, nie działają jednak w starszych wersjach.

Dodawanie podstawowej biblioteki AndroidX

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

Groovy

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

Kotlin

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

Tworzenie podstawowego powiadomienia

Powiadomienie w najbardziej podstawowej i skompresowanej formie, zwanej też zwiniętą, zawiera ikonę, tytuł i niewielką ilość tekstu. Z tego sekcji dowiesz się, jak utworzyć powiadomienie, które użytkownik może kliknąć, aby uruchomić aktywność w aplikacji.

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

Więcej informacji o poszczególnych częściach powiadomienia znajdziesz w artykule Anatomia powiadomienia.

Deklarowanie uprawnienia w czasie działania

Android 13 (poziom interfejsu API 33) i nowsze wersje obsługują uprawnienie do wyświetlania powiadomień z aplikacji, które nie są objęte wyjątkiem (w tym usługi na pierwszym planie).

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

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

Więcej informacji o uprawnieniach czasu działania znajdziesz w artykule Uprawnienia czasu działania powiadomień.

Ustawianie treści powiadomienia

Aby rozpocząć, skonfiguruj treść i kanał powiadomienia za pomocą obiektu NotificationCompat.Builder. Ten przykład pokazuje, jak utworzyć powiadomienie z tymi elementami:

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

  • Tytuł ustawiony przez setContentTitle().

  • Treść główna, ustawiona przez setContentText().

  • Priorytet powiadomienia ustawiony przez setPriority(). Priorytet określa, jak uciążliwe jest powiadomienie na Androidzie 7.1 i starszych. W przypadku Androida 8.0 lub nowszego zamiast tego ustaw ważność kanału zgodnie z opisem 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 do zapewnienia zgodności z Androidem 8.0 (poziom interfejsu API 26) i nowszymi wersjami, ale jest ignorowane przez starsze wersje.

Domyślnie tekst powiadomienia jest obcinany, aby zmieścić się na jednym wierszu. Możesz wyświetlać dodatkowe informacje, tworząc powiadomienie rozwijane.

Rysunek 2. Zwinięty i rozwinięty widok powiadomienia z możliwością rozwinięcia.

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 ustawianie jego ważności

Aby wysłać powiadomienie na Androidzie w wersji 8.0 lub nowszej, musisz zarejestrować kanał powiadomień aplikacji w systemie, przekazując instancję 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. Funkcję tę można bezpiecznie wywoływać wielokrotnie, ponieważ utworzenie istniejącego kanału powiadomień nie powoduje żadnej operacji.

Konstruktor NotificationChannel wymaga parametru importance, który jest jedną z konstant z klasy NotificationManager. Ten parametr określa, jak przerywać użytkownikowi wyświetlanie powiadomień należących do tego kanału. Aby obsługiwać Androida 7.1 i starsze wersje, ustaw priorytet na setPriority(), tak jak w poprzednim przykładzie.

Chociaż musisz ustawić ważność lub priorytet powiadomienia zgodnie z przykładem poniżej, 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 zawsze może zmienić poziom ważności danego kanału.

Więcej informacji o tym, co oznaczają poszczególne poziomy, znajdziesz w artykule Poziomy ważności powiadomień.

Ustawianie działania po kliknięciu powiadomienia

Każde powiadomienie musi reagować na kliknięcie, zwykle otwierając w aplikacji odpowiednią aktywność. Aby to zrobić, określ intencję treści zdefiniowaną za pomocą obiektu PendingIntent i prześlij ją do setContentIntent().

Ten fragment kodu pokazuje, jak utworzyć podstawowy zamiar, który otwiera aktywność, 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 go użyć w zależności od typu aktywności, którą chcesz rozpocząć. Może to być jedna z tych czynności:

  • Aktywność, która istnieje wyłącznie w celu odpowiedzi na powiadomienie. Użytkownik nie przechodzi do tego działania podczas normalnego korzystania z aplikacji, dlatego rozpoczyna ono nowe zadanie, zamiast być dodawane do istniejącego zbioru zadań i elementów. To jest rodzaj zamiaru utworzonego w poprzednim przykładzie.

  • Aktywność, która występuje w standardowym przebiegu aplikacji. W tym przypadku uruchomienie aktywności tworzy stos wsteczny, aby zachować oczekiwania użytkownika dotyczące przycisków Wstecz i Wróć.

Więcej informacji o różnych sposobach konfigurowania intencji powiadomienia znajdziesz w artykule Rozpoczynanie aktywności z powiadomienia.

Wyświetlanie powiadomienia

Aby wyświetlić powiadomienie, wywołaj funkcję NotificationManagerCompat.notify(), podając unikalny identyfikator powiadomienia i wynik funkcji 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.

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

Dodaj przyciski poleceń

Powiadomienie może zawierać maksymalnie 3 przyciski akcji, które umożliwiają użytkownikowi szybką reakcję, np. odłożenie przypomnienia na później lub odpowiedź na wiadomość tekstową. Nie mogą one jednak powielać czynności wykonanej po kliknięciu powiadomienia przez użytkownika.

Rysunek 3. Powiadomienie z wyłączonym przyciskiem działania

Aby dodać przycisk polecenia, przekaż PendingIntent do metody addAction(). Jest to podobne do konfigurowania domyślnego działania powiadomienia po jego kliknięciu, ale z tym wyjątkiem, że zamiast uruchamiania aktywności możesz wykonać inne czynności, takie jak uruchomienie zadania BroadcastReceiver w tle, aby działanie nie przerywało działania już otwartej aplikacji.

Na przykład ten kod pokazuje, jak wysłać transmisję do konkretnego odbiorcy:

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 BroadcastReceiver do wykonywania pracy w tle znajdziesz w artykule Omówienie transmisji na żywo.

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 działania bezpośredniej odpowiedzi

Akcja bezpośredniej odpowiedzi, wprowadzona w Androidzie 7.0 (interfejs API na poziomie 24), umożliwia użytkownikom wpisywanie tekstu bezpośrednio w powiadomieniu. Tekst jest następnie wysyłany do aplikacji bez otwierania aktywności. Możesz na przykład użyć akcji bezpośredniej odpowiedzi, aby umożliwić użytkownikom odpowiadanie na wiadomości tekstowe lub aktualizowanie list zadań bezpośrednio w powiadomieniu.

Rysunek 4. Kliknięcie przycisku „Odpowiedz” powoduje otwarcie pola tekstowego.

Działanie odpowiedzi bezpośredniej pojawia się jako dodatkowy przycisk w powiadomieniu, który otwiera pole tekstowe. 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 powiadomienia, które obsługuje odpowiedź bezpośrednią:

  1. Utwórz instancję RemoteInput.Builder , którą możesz dodać do działania powiadomienia. Konstruktor tej klasy akceptuje ciąg znaków, którego system używa jako klucza do danych wejściowych tekstowych. Aplikacja później używa 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 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ą elementu 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);
      

Gdy użytkownik wywoła działanie powiadomienia, system poprosi go o wpisanie odpowiedzi, jak pokazano 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 są używane). Jest to konieczne, aby ukryć interfejs bezpośredniej odpowiedzi i potwierdzić użytkownikowi, że jego odpowiedź została odebrana i poprawnie 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);

Podczas pracy z tym nowym powiadomieniem użyj kontekstu przekazanego do metody onReceive() odbiorcy.

Dodaj odpowiedź na dole powiadomienia, wywołując funkcję setRemoteInputHistory(). Jeśli jednak tworzysz aplikację do obsługi wiadomości, utwórz powiadomienie w formie wiadomości i dodaj nową wiadomość do rozmowy.

Więcej wskazówek dotyczących powiadomień z aplikacji do obsługi wiadomości znajdziesz w sekcji sprawdzonych metod dotyczących aplikacji do obsługi wiadomości.

Dodawanie paska postępu

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

Rysunek 5. Pasek postępu podczas operacji.

Jeśli w dowolnym momencie możesz oszacować, jak dużo operacji zostało już wykonane, użyj formy „determinate” wskaźnika (jak pokazano na rysunku 5) przez wywołanie funkcji setProgress(max, progress, false). Pierwszym parametrem jest wartość „complete”, np. 100. Po drugie, w jakim stopniu. Ostatni wskazuje, że jest to określony pasek 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 zostawić pasek postępu, aby pokazać, że operacja została zakończona, lub usunąć go. W obu przypadkach zaktualizuj tekst powiadomienia, aby pokazać, że operacja została zakończona. Aby usunąć pasek postępu, wywołaj funkcję 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). W efekcie otrzymujemy wskaźnik o tym samym stylu co poprzedni pasek postępu, ale w tym przypadku jest to ciągła animacja, która nie wskazuje zakończenia. Animacja postępu trwa, dopóki nie wywołasz setProgress(0, 0, false), a następnie nie zaktualizujesz powiadomienia, aby usunąć wskaźnik aktywności.

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

Ustawianie kategorii ogólnej

Android używa wstępnie zdefiniowanych kategorii systemowych do określania, czy użytkownik ma zostać powiadomiony o danym zdarzeniu, gdy włączy tryb Nie przeszkadzać.

Jeśli powiadomienie należy do jednej z kategorii powiadomień zdefiniowanych w NotificationCompat, np. CATEGORY_ALARM, CATEGORY_REMINDER, CATEGORY_EVENT lub CATEGORY_CALL, oświadcz to, przekazują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 używa tych informacji o kategorii powiadomienia, aby podejmować decyzje dotyczące wyświetlania powiadomienia, gdy urządzenie jest w trybie Nie przeszkadzać. Nie musisz jednak ustawiać kategorii ogólnosystemowej. Zrób to tylko wtedy, gdy Twoje powiadomienia pasują do jednej z kategorii zdefiniowanych w sekwencji NotificationCompat.

Wyświetlanie pilnego komunikatu

Aplikacja może wyświetlać pilne komunikaty, takie jak połączenie przychodzące lub dzwonek alarmu. W takich sytuacjach możesz powiązać z powiadomieniem intencję pełnoekranową.

Gdy użytkownik wywoła powiadomienie, zobaczy jedną z tych opcji, zależnie od stanu blokady urządzenia:

  • Jeśli urządzenie użytkownika jest zablokowane, na ekranie blokady pojawi się aktywność w trybie pełnoekranowym.
  • Jeśli urządzenie użytkownika jest odblokowane, powiadomienie wyświetla się w rozwiniętej formie, która zawiera opcje obsługi lub odrzucenia 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 blokady ekranu

Aby określić poziom szczegółowości powiadomienia na ekranie blokady, wywołaj funkcję setVisibility() i wskaż jedną z tych wartości:

  • VISIBILITY_PUBLIC: na ekranie blokady wyświetla się pełna treść powiadomienia.

  • VISIBILITY_SECRET: żadne powiadomienie nie jest wyświetlane na ekranie blokady.

  • VISIBILITY_PRIVATE: na ekranie blokady wyświetlane są tylko podstawowe informacje, takie jak ikona powiadomienia i tytuł treści. Nie wyświetla się pełna treść powiadomienia.

Po ustawieniu opcji VISIBILITY_PRIVATE możesz też podać alternatywną wersję treści powiadomienia, która ukrywa określone szczegóły. Aplikacja do obsługi SMS-ów może na przykład wyświetlić powiadomienie „Masz 3 nowe wiadomości tekstowe”, ale ukryć treść wiadomości i nazwy nadawców. 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 ma zawsze pełną kontrolę nad tym, czy jego powiadomienia są widoczne na ekranie blokady, i może je zarządzać na podstawie kanałów powiadomień aplikacji.

Aktualizowanie powiadomienia

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

Opcjonalnie możesz wywołać funkcję setOnlyAlertOnce(), aby powiadomienie przerywał użytkownikowi tylko przy pierwszym wyświetleniu (a nie przy kolejnych aktualizacjach) – za pomocą dźwięku, wibracji lub wizualnych wskazówek.

Usuwanie powiadomienia

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

  • Użytkownik odrzuca 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ń.
  • Gdy podczas tworzenia powiadomienia ustawisz limit czasu za pomocą parametru setTimeoutAfter(), upłynie określony czas trwania. W razie potrzeby możesz anulować powiadomienie przed upływem określonego czasu oczekiwania.

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

Podczas tworzenia powiadomień w aplikacjach do obsługi wiadomości i czatu weź pod uwagę sprawdzone metody wymienione tutaj.

Używaj MessagingStyle

Począwszy od Androida 7.0 (interfejs API na poziomie 24) Android udostępnia szablon stylu powiadomienia przeznaczony specjalnie do treści wiadomości. Za pomocą klasy NotificationCompat.MessagingStyle możesz zmienić kilka etykiet wyświetlanych w powiadomieniu, w tym tytuł rozmowy, dodatkowe wiadomości i 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.

Podczas korzystania z NotificationCompat.MessagingStyle:

  • Wybierz opcję Zadzwoń MessagingStyle.setConversationTitle(), aby ustawić tytuł czatu grupowego z więcej niż 2 osobami. Dobrym tytułem rozmowy może być nazwa czatu grupowego lub, jeśli nie ma nazwy, lista uczestników rozmowy. Bez tego wiadomość może zostać uznana za należącą do rozmowy jeden na jednego z nadawcą ostatniej wiadomości w rozmowie.
  • Aby dołączyć wiadomości multimedialne, takie jak obrazy, użyj metody MessagingStyle.setData(). Obsługiwane są typy MIME wzoru image/*.

Używaj odpowiedzi bezpośredniej

Odpowiedź bezpośrednia umożliwia użytkownikowi odpowiadanie w tekście wiadomości.

  • Gdy użytkownik odpowie za pomocą działania wbudowanego, użyj MessagingStyle.addMessage(), aby zaktualizować powiadomienie MessagingStyle. Nie wycofuj ani nie anuluj powiadomienia. Nie anulowanie powiadomienia umożliwia użytkownikowi wysyłanie wielu odpowiedzi na powiadomienie.
  • Aby zapewnić zgodność odpowiedzi w wątku z Wear OS, wywołaj funkcję Action.WearableExtender.setHintDisplayInlineAction(true).
  • Aby dodać kontekst do rozmowy z użytkownikiem, dodaj do powiadomienia wcześniejsze wiadomości.addHistoricMessage()

Włączanie Inteligentnej odpowiedzi

  • Aby włączyć Inteligentną odpowiedź, wywołaj setAllowGeneratedResponses(true) przy odpowiedzi. Dzięki temu odpowiedzi w ramach inteligentnej odpowiedzi są dostępne dla użytkowników, gdy powiadomienie jest przekierowywane na urządzenie z Wear OS. Odpowiedzi inteligentnych odpowiedzi są generowane przez model systemów uczących się działający w trybie online na podstawie kontekstu udostępnionego przez NotificationCompat.MessagingStylepowiadomienie. Do generowania odpowiedzi nie są przesyłane żadne dane.

Dodawanie metadanych powiadomienia