Powiadomienia
Powiadomienie (notification) jest wiadomością, którą wysyłamy z bieżącej aplikacji. Ta wiadomość jest wyświetlana przez system Android poza interfejsem użytkownika aplikacji, z której została wysłana. Po wysłaniu, powiadomienie najpierw wyświetla się jako mała ikona w obszarze powiadomień. Użytkownik będzie mógł zobaczyć szczegóły dotyczące tego powiadomienia przez rozwinięcie szuflady powiadomień.
Aplikacja, która wykorzystuje system powiadomień musi mieć ustawiony dostęp do tej funkcji. Dostęp przydzielany jest w pliku manifestu
Wskazówka:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
Powiadomienia (notyfikacje) występują w różnych formach ? jako ikona na pasku statusu, szczegółowa wiadomość w panelu notyfikacji, czy odznaka na ikonie aplikacji.
NotificationCompat
NotificationCompat to klasa dostarczająca metod do pracy z powiadomieniami. Pozwala wygodnie definiować elementy powiadomienia. Podstawowe powiadomienie wymaga przygotowania trzech elementów:
- małej ikony (wywołani metody setSmallIcon())
- tytułu powiadomienia (wywołani metody setContentTitle())
- treść powiadomienia (wywołanie metody setContentText())
Wskazówka:
val nota = NotificationCompat.Builder(this,idKanalu)
.setContentTitle("UWAGA!")
.setContentText("Przyszła nowa wiadomość")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
Istnieje możliwość użycia grupy opcji dodatkowych, które nie są wymagane.
NotificationManager
NotificationManager klasa pośrednicząca przy wysyłaniu powiadomienia. Przed wyświetleniem powiadomienia pobierana jest referencja (odwołanie) do klasy za pomocą funkcji getSystemService ( String ). Przed wyświetleniem powiadomienia należy przypisać indeks powiadomienia.
Wskazówka:
val notificationManager=
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val id = 1
notificationManager.notify(id,nota)
Rola kanałów
W systemie Android 8.0 (poziom API 26) i nowszych wszystkie powiadomienia muszą być powiązane z kanałem, w przeciwnym razie powiadomienia nie będą wyświetlane.
- Kanały są zbiorami powiązanych powiadomień.
- Każdy kanał może mieć własny sposób powiadamiania, np. ustawianie ważności powiadomienia, dźwięku i trybu wibracji.
- Ponieważ powiadomienia są pogrupowane według kanałów, użytkownik ma teraz większą kontrolę nad tymi powiadomieniami i może zmienić zachowanie każdego kanału na ekranie ustawień powiadomień aplikacji.
Więcej o tworzeniu kanałów czytaj
Kanał powiadomień należy tworzyć przed użyciem dowolnego powiadomienia, które z tym kanałem będą powiązane. Przykład podstawowych instrukcji tworzących kanał.
Wskazówka:
//Rób kanał dla API 26+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val nazwa = "Kanał powiadomień"
val przeznaczenie = "Testowy kanał powiadomień"
val waznoscZnaczenia = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(idKanalu, nazwa, waznoscZnaczenia).apply {
description = przeznaczenie
}
// rejestruj kanał w systemie
val notificationManager: NotificationManager =
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
Układ głównej aktywności
Układ tworzonej aktywności jest bardzo prosty. Składa się z kilku kontrolek typu Button umieszczonych jedna pod drugą. Patrz zrzut ekranu
![Android Studio tworzenie powiadomień](./android/g/android-powiadomienia-11.webp)
Kolejne klawisze będą służyć do wysłania czterech wersji powiadomień
Jak utworzyć kanał powiadomień?
Piszemy funkcję tworzącą prosty kanał powiadomień dla naszej aplikacji. Korzystamy z informacji podanych powyżej. Przykładowy kod wygląda jak poniżej.
Wskazówka:
private fun robKanal() {
//Rób kanał dla API 26+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val nazwa = "Kanał powiadomień"
val przeznaczenie = "Testowy kanał powiadomień"
val waznoscZnaczenia = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(idKanalu, nazwa, waznoscZnaczenia).apply {
description = przeznaczenie
}
// rejestruj kanał w systemie
val notificationManager: NotificationManager =
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
W kodzie głównej klasy projektu dodajemy identyfikator kanału, a w metodzie onCreate() wywołujemy funkcję tworzącą kanał
Wskazówka:
class MainActivity : AppCompatActivity() {
//unikalny idetyfikator kanału
val idKanalu="kanal_1"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
robKanal()
}
Powiadomienia proste
Przypisanie ikony ułatwia standardowy zasób ikon systemu Androida
![Android Studio ikona powiadomienia](./android/g/android-powiadomienia-1.webp)
Możesz skorzystać z narzędzia New/Image Asset, które pozwala zaimportować do projektu dowolne pliki graficzne. Dla ikon najlepsze są pliki z grafiką wektorową.
![Android Studio NotificationCompat.Builder](./android/g/android-powiadomienia-2.webp)
Przykładowy kod funkcji prostego powiadomienia
Wskazówka:
fun PowiadomienieProste(){
val nota = NotificationCompat.Builder(this,idKanalu)
.setContentTitle("UWAGA!")
.setContentText("Przyszła nowa wiadomość")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
val notificationManager=
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val id = 1
notificationManager.notify(id,nota)
}
Utworzoną funkcję wywołujemy w zdarzeniu kliknięcia w pierwszej kontrolce typu Button
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
robKanal()
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
PowiadomienieProste()
}
}
Po wybraniu klawisza w górnym pasku pojawi się ikona powiadomienia. Patrz poniższy obraz
![Android Studio simple NotificationCompat.Builder](./android/g/android-powiadomienia-3.webp)
Kliknij na ikonie i rozciągnij w dół. System wyświetli listę ostatnich powiadomień.
![Android Studio Notification](./android/g/android-powiadomienia-4.webp)
Powiadomienia z akcją
Ten rodzaj powiadomień umożliwia wykonanie dodatkowych funkcji niekoniecznie związanych z bieżącą aplikacją. Powiadomienie z akcją oprócz tytułu, treści zawiera przycisk akcji. W tym przykładzie przy pomocy powiadomienia uruchomimy inną aplikację, którą będzie Google Maps.
Kolejno zostaną wykonane takie kroki
- Krok 1: Przygotowanie innej intencji (tu Google Maps)
- Krok 2: Utworzenie referencji (odwołania) do utworzonej intencji, która będzie wykonana w późniejszym czasie (PendingIntent.getActivity)
- Krok 3: Utworzenie akcji (NotificationCompat.Action.Builder)
- Krok 4: Utworzenie powiadomienia (NotificationCompat.Builder)
- Krok 5: Dodanie akcji do powiadomienia (addAction)
- Krok 6: Utworzenie przez referencję menadżera powiadomień
- Krok 7: Wyświetlenie powiadomienia
Kod funkcji tworzącej powiadomienie z akcją. Akcja to otwarcie aplikacji Google Maps, której intencję przygotowano z godnie zasadami podanymi w temacie Uruchomienie innej aplikacji
Wskazówka:
fun powiadomienie_z_Akcja(){
val celMapaGoogle= Uri.parse("geo:50.0135833,20.9174879")
val intencja= Intent(Intent.ACTION_VIEW, celMapaGoogle)
intencja.setPackage("com.google.android.apps.maps")
val pIntent=PendingIntent.getActivity(this,
0, intencja,PendingIntent.FLAG_UPDATE_CURRENT)
val akcja=NotificationCompat.Action.Builder(
android.R.drawable.sym_action_chat,
"Otwórz", pIntent)
.build();
val nota = NotificationCompat.Builder(this,idKanalu)
.setContentTitle("UWAGA!")
.setContentText("W podanej lokalizacji doszło do niesamowitego wydarzenia:)")
.setSmallIcon(R.drawable.ic_powiadomienie_akcja)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.addAction(akcja)
.build()
val notificationManager=
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val id = 2
notificationManager.notify(id,nota)
}
Utworzoną funkcję wywołamy w zdarzenie kliknięcia w drugą kontrolkę Button
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
robKanal()
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
PowiadomienieProste()
}
val bt2=findViewById<Button>(R.id.button2)
bt2.setOnClickListener {
powiadomienie_z_Akcja()
}
}
Skompiluj program i sprawdź działanie. Prawidłowo działająca aplikacja przy wysłaniu drugiego powiadomienia- patrz ikona powiadomienia (na poniższym rysunku)
![Android Studio Notification](./android/g/android-powiadomienia-5.webp)
.. o takiej postaci
![Android Studio Notification](./android/g/android-powiadomienia-6.webp)
Kliknij w Otwórz. Akcja z powiadomienia otworzy aplikację Google Maps
![Android Studio Notification addAction](./android/g/android-powiadomienia-7.webp)
Powiadomienie z większą ilością treści
W powyższym przykładzie można zauważyć, że nie cała treść powiadomienia jest pokazywana. Aby to zmienić, należy przypisać styl z większa ilością treści do tworzonego powiadomienia.
setStyle(NotificationCompat.BigTextStyle().bigText(tresc))Skorzystamy z poprzedniego kodu, który nieznacznie zmodyfikujemy.
Wskazówka:
fun powiadomienie_z_Akcja_dluga_tresc(){
val celMapaGoogle= Uri.parse("geo:50.0135833,20.9174879")
val intencja= Intent(Intent.ACTION_VIEW, celMapaGoogle)
intencja.setPackage("com.google.android.apps.maps")
val pIntent=PendingIntent.getActivity(this,
0, intencja,PendingIntent.FLAG_UPDATE_CURRENT)
val akcja=NotificationCompat.Action.Builder(
android.R.drawable.sym_action_chat,
"Otwórz", pIntent)
.build();
val tresc="W podanej lokalizacji doszło do niesamowitego wydarzenia." +
"Nieznani goście we wskazanym miejscu zamówili bardzo duże ilości jedzenia." +
"Nie płacąc rachunku rozdali potrzebującym"
val nota = NotificationCompat.Builder(this,idKanalu)
.setContentTitle("UWAGA!")
.setStyle(NotificationCompat.BigTextStyle().bigText(tresc))
.setSmallIcon(R.drawable.ic_powiadomienie_akcja)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.addAction(akcja)
.build()
val notificationManager=
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val id = 2
notificationManager.notify(id,nota)
}
Nowe powiadomienie wywołamy po kliknięciu w kolejną kontrolkę typu Button
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
robKanal()
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
PowiadomienieProste()
}
val bt2=findViewById<Button>(R.id.button2)
bt2.setOnClickListener {
powiadomienie_z_Akcja()
}
val bt3=findViewById<Button>(R.id.button3)
bt3.setOnClickListener {
powiadomienie_z_Akcja_dluga_tresc()
}
}
Efektem działania jest poniższa ilustracja.
![Android Studio Notification addAction](./android/g/android-powiadomienia-8.webp)
Powiadomienie z dużą ilustracją
Innym przykładem wykorzystania stylu powiadomienia jest zastosowanie powiadomienia z dużym obrazem. Jeżeli obraz umieszczony jest w zasobach projektu, to po pobraniu należy go przekonwertować na bitmapę (obiekt klasy Bitmap)
Wskazówka:
//konwertuj obraz z zasobów na bitmapę
val obraz:Bitmap = BitmapFactory.decodeResource(
applicationContext.resources,R.drawable.anglia_holandia_1664_67
)
Użycie stylu z dużym obrazem wymaga jego użycia BigPictureStyle() patrz poniższy kod
Wskazówka:
fun Powiadomienie_z_Obrazem(){
//konwertuj obraz z asobów na bitmapę
val obraz:Bitmap = BitmapFactory.decodeResource(
applicationContext.resources,R.drawable.anglia_holandia_1664_67
)
val nota = NotificationCompat.Builder(this,idKanalu)
.setContentTitle("UWAGA!")
.setContentText("Przyszła nowa wiadomość")
.setSmallIcon(R.drawable.powiadomienie)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setLargeIcon(obraz)
.setStyle(NotificationCompat.BigPictureStyle()
.bigPicture(obraz)
)
.build()
val notificationManager=
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val id = 1
notificationManager.notify(id,nota)
}
Praktycznie jest to powielenie wcześniejszych rozwiązań. Utworzona funkcję wywołamy w zdarzeniu kliknięcia w kolejnej kontrolce Button. Patrz bt4
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
robKanal()
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
PowiadomienieProste()
}
val bt2=findViewById<Button>(R.id.button2)
bt2.setOnClickListener {
powiadomienie_z_Akcja()
}
val bt3=findViewById<Button>(R.id.button3)
bt3.setOnClickListener {
powiadomienie_z_Akcja_dluga_tresc()
}
val bt4=findViewById<Button>(R.id.button4)
bt4.setOnClickListener {
Powiadomienie_z_Obrazem()
}
}
Po uruchomieniu aplikacji, wysłaniu tego typu powiadomienia zobaczymy monit z powiadomieniem wraz z ikoną przesłanego obrazu.
![Android Studio Notification BigPictureStyle](./android/g/android-powiadomienia-9.webp)
Po kliknięciu w tak zwanego ptaszka, powiadomienie się rozwinie do pełnego wymiaru.
![Android Studio Notification BigPictureStyle](./android/g/android-powiadomienia-10.webp)
Zagadnienie powiadomień w środowisku Android jest bardzo obszerne. Tu pokazałem podstawowe rodzaje powiadomień, a w zasadzie ich szablony.
Pełny kod rozwiązania
Wskazówka:
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat
import android.net.Uri
import android.widget.RemoteViews
class MainActivity : AppCompatActivity() {
//unikalny idetyfikator kanału
val idKanalu="kanal_1"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
robKanal()
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
PowiadomienieProste()
}
val bt2=findViewById<Button>(R.id.button2)
bt2.setOnClickListener {
powiadomienie_z_Akcja()
}
val bt3=findViewById<Button>(R.id.button3)
bt3.setOnClickListener {
powiadomienie_z_Akcja_dluga_tresc()
}
val bt4=findViewById<Button>(R.id.button4)
bt4.setOnClickListener {
Powiadomienie_z_Obrazem()
}
}
fun PowiadomienieProste(){
val nota = NotificationCompat.Builder(this,idKanalu)
.setContentTitle("UWAGA!")
.setContentText("Przyszła nowa wiadomość")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
val notificationManager=
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val id = 1
notificationManager.notify(id,nota)
}
fun powiadomienie_z_Akcja(){
val celMapaGoogle= Uri.parse("geo:50.0135833,20.9174879")
val intencja= Intent(Intent.ACTION_VIEW, celMapaGoogle)
intencja.setPackage("com.google.android.apps.maps")
val pIntent=PendingIntent.getActivity(this,
0, intencja,PendingIntent.FLAG_UPDATE_CURRENT)
val akcja=NotificationCompat.Action.Builder(
android.R.drawable.sym_action_chat,
"Otwórz", pIntent)
.build();
val nota = NotificationCompat.Builder(this,idKanalu)
.setContentTitle("UWAGA!")
.setContentText("W podanej lokalizacji doszło do niesamowitego wydarzenia:)")
.setSmallIcon(R.drawable.ic_powiadomienie_akcja)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.addAction(akcja)
.build()
val notificationManager=
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val id = 2
notificationManager.notify(id,nota)
}
fun powiadomienie_z_Akcja_dluga_tresc(){
val celMapaGoogle= Uri.parse("geo:50.0135833,20.9174879")
val intencja= Intent(Intent.ACTION_VIEW, celMapaGoogle)
intencja.setPackage("com.google.android.apps.maps")
val pIntent=PendingIntent.getActivity(this,
0, intencja,PendingIntent.FLAG_UPDATE_CURRENT)
val akcja=NotificationCompat.Action.Builder(
android.R.drawable.sym_action_chat,
"Otwórz", pIntent)
.build();
val tresc="W podanej lokalizacji doszło do niesamowitego wydarzenia." +
"Nieznani goście we wskazanym miejscu zamówili bardzo duże ilości jedzenia." +
"Nie płacąc rachunku rozdali potrzebującym"
val nota = NotificationCompat.Builder(this,idKanalu)
.setContentTitle("UWAGA!")
.setStyle(NotificationCompat.BigTextStyle().bigText(tresc))
.setSmallIcon(R.drawable.ic_powiadomienie_akcja)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.addAction(akcja)
.build()
val notificationManager=
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val id = 2
notificationManager.notify(id,nota)
}
fun Powiadomienie_z_Obrazem(){
//konwertuj obraz z asobów na bitmapę
val obraz:Bitmap = BitmapFactory.decodeResource(
applicationContext.resources,R.drawable.anglia_holandia_1664_67
)
val nota = NotificationCompat.Builder(this,idKanalu)
.setContentTitle("UWAGA!")
.setContentText("Przyszła nowa wiadomość")
.setSmallIcon(R.drawable.powiadomienie)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setLargeIcon(obraz)
.setStyle(NotificationCompat.BigPictureStyle()
.bigPicture(obraz)
)
.build()
val notificationManager=
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val id = 1
notificationManager.notify(id,nota)
}
private fun robKanal() {
//Rób kanał dla API 26+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val nazwa = "Kanał powiadomień"
val przeznaczenie = "Testowy kanał powiadomień"
val waznoscZnaczenia = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(idKanalu, nazwa, waznoscZnaczenia).apply {
description = przeznaczenie
}
// rejestruj kanał w sytsemie
val notificationManager: NotificationManager =
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
}