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
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
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ą.
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
Kliknij na ikonie i rozciągnij w dół. System wyświetli listę ostatnich powiadomień.
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)
.. o takiej postaci
Kliknij w Otwórz. Akcja z powiadomienia otworzy aplikację Google Maps
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.
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.
Po kliknięciu w tak zwanego ptaszka, powiadomienie się rozwinie do pełnego wymiaru.
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)
}
}
}