Android- Local Bildirim Gönderme (Send Notification)

Kerem Türker
Nov 1 · 8 min read

Bildirim, Android’in kullanıcıya hatırlatıcıları, diğer kullanıcıların iletişimlerini veya zamanında uygulamanızdan gelen diğer bilgileri sağlamak için uygulamanızın kullanıcı arayüzü dışında gösterdiği mesajdır. Kullanıcılar, bildirime dokunarak uygulamanızı açabilir veya bir işlemi doğrudan bildirimden gerçekleştirebilirler. — Google doküman

Bildirimlerin Genel Yapısı

Bildirimler genel olarak 6 ana yapıdan oluşur, bunlar;

1- Küçük simge: Bu kısım gereklidir. Genellikle uygulama simgesi olarak kullanılır.

2- Uygulama adı: Bu bilgi sistem tarafından sağlanır.

3- Zaman bilgisi: Bu bilgi sistem tarafından sağlanır ancak isteğe bağlı olarak gizlenebilir.

4- Büyük simge: Bu kısım isteğe bağlıdır. (genellikle yalnızca kişi fotoğrafları için kullanılır; uygulamanızın simgesi için kullanmayın)

5- Başlık: Bu kısım isteğe bağlıdır.

6- Metin: Bu kısım isteğe bağlıdır.

Bildirim Oluşturma

İlk olarak bildirimleri yönetmek için NotificationManager sınıfından bir nesne oluşturuyoruz.

var notificationManager: NotificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

Bir sonraki aşama için ise Android 8.0'dan itibaren tüm bildirimler için NotificationChannel sınıfını kullanarak bir bildirim kanalı oluşturulması gereklidir. Bu yüzden kod buloğu SDK koşuluna bağlanmalıdır. Ve her kanal için sistemin bildirimleri sınırlandırabilmesi için önem derecesi belirtilmesi gerekiyor.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

val kanalid = "com.keremturker.sendnotification"
val
aciklama = "Test notification"
val
onemderecesi = NotificationManager.IMPORTANCE_DEFAULT


var notificationChannel =
NotificationChannel(kanalid, aciklama, onemderecesi)
notificationManager.createNotificationChannel(notificationChannel)
}

Önem dereceleri hakkında detaylı bilgi almak için burayı inceleyebilirsiniz.

Daha sonra bildirim içeriğini düzenlemek için Notification.Builder sınıfından nesne oluşturuyoruz.

var builder = Notification.Builder(this)

Şimdi sıra bildirim içeriğini düzenlemeye geldi, bunun için aşağıdaki metotları kullanabiliriz.

  • .setContentTitle(…) = Bildirim başlığı
  • .setContentText(…)= Bildirim içeriği
  • .setSmallIcon(…) = Küçük simge
  • .setLargeIcon(…) = Büyük simge
  • .setPriority(…) = Bildirimin önem derecesini belirtir.

Not: setPriority() fonksiyonu yalnızca Android 7.1 ve altındaki sürümlerde kullanılır. Android 8.0 ve üzeri sürümlerde ise bildirim kanalının önem derecesinin düzenlenmesi gerekmektedir.

  • .setStyle(…) = Varsayılan olarak bildirimler tek satır olarak gözükmektedir. Bildirim içeriğinin tamamının gözükmesini istiyorsanız setStyle() fonksiyonu ile bir şablon ekleyerek genişletilmiş bir bildirim gösterebilirsiniz. (Yazının ileri ki kısımlarında genişletilmiş bildirim hakkında daha detaylı bilgi vereceğim.)
  • .setVisibility(…) = Bildirimin, kilit ekranında gösterilecek ayrıntı seviyesini belirler. 3 farklı değer alır, bunlar;

a- Notification.VISIBILITY_PUBLIC = Bildirim içeriği tamamen gözükür.

b- Notification.VISIBILITY_SECRET = Bildirim hiçbir şekilde gösterilmez.

c- Notification.VISIBILITY_PRIVATE = Bildirimin başlığı ve ikonu gibi temel bilgileri gösterilir fakat bildirim içeriği gizlenir.

  • .setCategory(…) = Android’de kullanıcı, cihazın rahatsız etme modunu etkinleştirdiği zaman bazı kategorilerdeki bildirimler kullanıcıya gösterilmemektedir. Bu yüzden bildirime uygun kategorinin seçilmesi gerekir. (CATEGORY_ALARM,CATEGORY_REMINDER,CATEGORY_EVENT,CATEGORY_CALL,CATEGORY_MESSAGE) gibi değerler alır.
  • setShowWhen(…) = Bildirim zamanının gösterilmesini sağlar, varsayılan değeri false’dur.
  • setOnlyAlertOnce(…) = Arka arkaya gelen aynı id’ye sahip bildirimleri teker teker ekranda göstermeden sadece titreşim veya ses çalmasını sağlar.
  • setOngoing(…) = Bildirimin kullanıcı tarafından kaldırılamamasını sağlar. (Örn: Bir uygulama indirirken çıkan bildirimler) Varsayılan değeri false’dur. Fonksiyonun değeri false yapılana kadar bildirim ekrandan kaldırılamaz.

Bildirime Tıklama

Bildirimlere tıklanıldığı zaman uygulama içerisinde bildirime karşılık gelen activitynin açılması gerekir. Bu işlemi gerçekleştirmek için ilk olarak Intent nesnesi oluşturup hangi activitynin açılacağını belirtiyoruz.

val intent = Intent(this, MainActivity::class.java)

Daha sonra PendingIntent nesnesini oluşturuyoruz.

val pendingIntent =
PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)

Son olarak PendingIntent nesnesini Notification.Builder’a tanımlıyoruz.

builder = Notification.Builder(this, channelId)
.setContentIntent(pendingIntent)

Bir eksiğimiz daha var, bildirime tıkladık ve belirlediğimiz activity de açıldı ama tıkladığımız bildirim hâlâ duruyor. Bildirime tıklanıldığı zaman bildirimin kaldırılması için setAutoCancel(…) fonksiyonunu kullanıyoruz.

builder = Notification.Builder(this, channelId)
.setContentIntent(pendingIntent)
.setAutoCancel(true)

Bildirim İşlem Butonları

Kullanıcının uygulama içerisine girmeden işlem yapabilmesini sağlar. (Örn. WhatsApp’tan gelen mesajı bildirimdeki “Okundu olarak işaretle” butonuna tıklayıp bildirim ekranında mesajı okundu olarak işaretlenmesi)

Bildirim üzerinden işlem yapabilmek için Notification.Builder’a addAction() fonksiyonunu tanımlıyoruz. Fonksiyon parametre olarak PendingIntent nesnesi almaktadır.İşlemler arka planda gerçekleşeceği için servisleri kullanmamız gerekmektedir. Bu yüzden BroadcastReceiver sınıfından extend ettiğimiz NotificationReceiver sınıfımızı oluşturuyoruz ve onReceive metodunu override ediyoruz. onReceive metodu NotificationReceiver sınıfı çağrıldığında yapılacak işlemlerin yazıldığı metottur.

İlk olarak NotificationReceiver sınıfımızı oluşturuyoruz ve onReceive metodunu override ediyoruz.

class NotificationReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context, "Okundu olarak işaretlendi.", Toast.LENGTH_SHORT).show()
}
}

Ardından NotificationReceiver sınıfına ait intent nesnesi ve bu intent nesnesini kullanacağımız PendingIntent nesnesini oluşturuyoruz.

val broadcastIntent = Intent(this, NotificationReceiver::class.java)
val actionIntent = PendingIntent.getBroadcast(
this,
0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT
)

Daha sonra PendingIntent nesnesini Notification.Builder’a tanımlıyoruz.

builder = Notification.Builder(this, channelId)
.setContentTitle("Bildirim Başlığı")
.setContentText(resources.getString(R.string.lorem))
.addAction(R.drawable.large, "Okundu olarak işaretle", actionIntent)

Son olarak NotificationReceiver sınıfını kullanabilmek için receiver’ı AndroidManifest.xml dosyasındaki application tag’leri arasına tanımlıyoruz.

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="Bildirim Gönder"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
>
// ----<receiver android:name=".NotificationReceiver" />
</application>

Ve bildirim işlem butonu kullanılmaya hazırdır.

Bildirim İşlem Butonu Örneği

Ek özellik olarak yazını rengini değiştirmek için .setColor(…) fonksiyonunu kullanabiliriz. Notification.Builder’a fonksiyonu tanımlayıp yazı rengi değiştirilebilir.

builder = Notification.Builder(this, channelId)
.setContentTitle("Bildirim Başlığı")
.setContentText(resources.getString(R.string.lorem))
.addAction(R.drawable.large, "Okundu olarak işaretle", actionIntent)
.setColor(Color.RED)

İşlem butonları hakkında daha detaylı bilgi almak için bu dokümanı inceleyebilirsiniz.

Yanıtlanabilir Bildirim

Kullanıcının bildirim üzerinde, uygulamaya giriş yapmadan işlem yapabilmesini sağlar. Örneğin, WhatsApp uygulamasından gelen mesajın bildirim ekranından yanıtlanabilmesi. Bu özellik Android 7.0’dan sonra gelmiştir. Bu yüzden kod buloğu SDK koşuluna bağlanmalıdır.

İlk olarak bildirimimizi oluşturuyoruz.

builder = Notification.Builder(this, channelId)
.setContentTitle("Kerem Türker")
.setContentText("Merhaba, iyi günler.")
.setShowWhen(true)
.setCategory(Notification.CATEGORY_MESSAGE)
.setSmallIcon(R.drawable.ic_message_black_24dp)

Yanıtlanabilir bildirim oluşturmak için ise RemoteInput.Builder sınıfından nesnemizi oluşturuyoruz. Bu sınıf , kullanıcıya bilgi vermek açısından bir etikete ve kullanıcının girdiği veriyi işleyebilmek için bir anahtar kelimeye ihtiyaç duymaktadır.

val NOTIFICATION_REPLY = "REPLY"var remoteInput = RemoteInput.Builder(NOTIFICATION_REPLY).setLabel("Yanıtla").build()

Bildirim üzerinde gerçekleşen işlemler arka planda gerçekleşeceği için BroadcastReceiver sınıfından extend edeceğimiz bir sınıfa ihtiyacımız var.

class DirectReplyReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val remoteInput = RemoteInput.getResultsFromIntent(intent) //Kullanıcı veri girmişse
if (remoteInput != null) {
//Anahtar kelime ile kullanıcının girmiş olduğu texti alıyoruz.
val text = remoteInput.getCharSequence(MainActivity.NOTIFICATION_REPLY)
// Girilen texti ekrana yazdır
Toast.makeText(context, text, Toast.LENGTH_LONG).show()
// İşlem tamamlandığında Bildirimin kapatılmasını sağlar
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(MainActivity.NOTIFICATION_ID)
}
}
}

NotificationReceiver sınıfını kullanabilmek için receiver’ı AndroidManifest.xml dosyasındaki application tag’leri arasına tanımlıyoruz.

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="Mesajlar"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
>
// ----<receiver android:name=".DirectReplyReceiver" /></application>

Daha sonra DirectReplyReceiver sınıfına ait intent nesnesi ve bu intent nesnesini kullanacağımız PendingIntent nesnesini oluşturuyoruz.

var replyIntent = Intent(this, DirectReplyReceiver::class.java)var replyPendingIntent =
PendingIntent.getBroadcast(this, 0, replyIntent, PendingIntent.FLAG_ONE_SHOT)

Ardından oluşturduğumuz PendingIntent ve RemoteInput nesnesini Notification.Builder’a tanımlamak için Notification.Action nesnesini oluşturuyoruz.

var action = Notification.Action.Builder(
R.drawable.ic_message_black_24dp,
"Yanıtla",
replyPendingIntent
).addRemoteInput(remoteInput).build()

Action nesnesi 3 adet parametre almaktadır.

  • Icon = Yanıtlama butonuna ait iconu temsil eder.
  • Title = Yanıtlama butonuna ait texti temsil eder.
  • PendingIntent = İşlemlerin arka planda yapılabilmesi için kullanacağımız intent nesnesidir.

Veri aktarımını sağlamak için ise .addRemoteInput(…) fonksiyonunu kullanarak remoteInput nesnemizi action nesnesine ekliyoruz.

En son olarak yapılan tüm işlemleri bildirime tanımlamak için .addAction(…) fonksiyonunu kullanıyoruz.

builder = Notification.Builder(this)//---builder.addAction(action)
Yanıtlanabilir Bildirim Örneği

Genişletilebilir Bildirim

Bildirimler, varsayılan olarak tek satır olarak gözükmektedir ve her zaman kullanıcıya göstermek istediğimiz içerik bu kadar kısa olmayabilir.Kullanıcıya daha fazla bilgi sağlamak için Android tarafından sağlanan çeşitli şablonlardan birini kullanabiliriz. Bunlardan ilki BigTextStyle şablonudur.

  • BigTextStyle

İçerik metni yerine daha uzun bir metinin ekranda gösterilmesi sağlar.İlk olarak standart bir bildirim oluşturuyoruz.

builder = Notification.Builder(this, channelId)

.setContentTitle("Bildirim Başlığı")
.setContentText(resources.getString(R.string.lorem))

Ardından BigTextStyle şablonumuzu oluşturuyoruz.

var bigTextStyle = Notification.BigTextStyle()
.bigText(resources.getString(R.string.lorem))
.setBigContentTitle("Big title")
.setSummaryText("Summary TEXT")

Notification.BigTextStyle sınıfına ait 3 adet fonksiyon bulunmaktadır.

.bigText(…) = Genişletilmiş bildirimin içeriği.

.setBilContentTitle(…) = Genişletilmiş bildirimin başlığı.

.setSummaryText(…) = Kısaca içerik özeti diyebiliriz. Kullanım örneği olarak Gmail uygulamasında gelen mail bildiriminde kullanıcının mail adresinin gösterildiği kısmı verebiliriz.

Daha sonra şablonu Notification.Buildera uygulamak için setStyle() fonksiyonunu kullanıyoruz.

builder = Notification.Builder(this, channelId)

.setContentTitle("Bildirim Başlığı")
.setContentText(resources.getString(R.string.lorem))
.setStyle(
bigTextStyle
)
BigTextStyle Örneği
  • BigPictureStyle

Yazıdan ziyade görselin ön planda olduğu bildirimler için kullanılır. Örnek olarak kampanya bildirimlerini gösterebiliriz.

İlk olarak bildirimde gösterilecek görseli Bitmap’e çeviriyoruz.

val bitmap = BitmapFactory.decodeResource(
resources,
R.drawable.large
)

Ardından , bildirim küçültüldüğünde görselin de küçültülmesi için Notification.Builder’a setLargeIcon() fonksiyonu ile tanımlıyoruz.

Daha sonra şablonumuzu oluşturuyoruz.

var bigPictureStyle = Notification.BigPictureStyle()
.bigPicture(bitmap)
.bigLargeIcon(bitmapNull)
.setBigContentTitle("Bildirim Başlığı")
.setSummaryText("Summary Text")

Notification.BigPictureStyle sınıfına ait 4 adet fonksiyon bulunmaktadır.

.setBigContentTitle(…) = Bildirim genişletildiğinde gösterilecek başlık. (Zorunlu değildir. Değer verilmediği taktirde Notification.Builder’daki Content Title değeri gösterilir.)

.setSummaryText(…) = Bildirim genişletildiğinde gösterilecek içerik bilgisidir. (Zorunlu değildir. Değer verilmediği taktirde Notification.Builder’daki Content Text değeri gösterilir.)

.bigPicture(…) = Bildirim genişletildiğinde gösterilecek olarak görsel.

.bigLargeIcon(…) = Bildirim genişletildiğinde Notification.Builder’daki LargeIcon alanında gösterilecek görsel. Parametre olarak Bitmap nesnesi alır. Görsel açıdan güzel gözükmesi adına genellikle bildirim genişletildiğinde görselin ekrandan kaybolması istenir. Bunun için null değere sahip Bitmap nesnesi kullanılabilir.

Bunun için null değere sahip Bitmap nesnesi oluşturup fonksiyona parametre olarak veriyoruz.

val bitmapNull: Bitmap? = nullvar bigPictureStyle = Notification.BigPictureStyle()
.bigLargeIcon(bitmapNull)
BigPictureStyle Örneği

Genişletilebilir bildirim hakkında daha detaylı bilgi almak için bu dokümanı inceleyebilirsiniz.

ProgressBar Bildirim

Bildirim üzerinde, devam eden işlemin durumunu kullanıcıya animasyonlu bir şekilde gösterebiliriz.

İlk olarak bildirimimizi oluşturuyoruz. Progressbarın bildirimde gözükmesi için setProgress(…) fonksiyonunu kullanıyoruz.

builder = Notification.Builder(this, channelId)
.setContentTitle("Resim indir")
.setContentText("İndirme devam ediyor")
.setShowWhen(true)
.setOnlyAlertOnce(true)
.setProgress(100, 0, false)
.setCategory(Notification.CATEGORY_PROGRESS)
.setSmallIcon(R.drawable.ic_arrow_downward_black_24dp)
.setOngoing(true)

.setProgress(…) fonksiyonu 3 adet parametre almaktadır. İlk parametre, progressbarın bitiş değeridir. İkincisi, işlemin o an ne kadarının tamamlandığını gösterir. Sonuncusu ise, işlem devam ederken progressbarın sürekli tekrar eden bir animasyon şeklinde olup olmayacağının ayarının yapılması içindir.

İşlem sonunda, işlemin tamamlandığını kullanıcıya bildirmek için progressbarın bitiş değeri ile tamamlanan değerin eşit olması gerekir.

builder.setProgress(100, 100, false)

Progressbarı kaldırmak için ise, bitiş değerine ve tamamlanan değere 0 verilmesi gerekmektedir.

builder.setProgress(0, 0, false)
ProgressBar Bildirim Örneği

Not: Bir dosyayı gerçekten indirmeniz gerekiyorsa DownloadManager kullanmalısınız çünkü ilerlemeyi takip etmek için kendi bildirimini kullanır.

Özelleştirilmiş Bildirim

Peki, ben standartların dışına çıkmayı severim, bildirim tasarımını keyfime göre tasarlamak istiyorum diyorsanız bu da mümkündür.

İlk olarak bildirim tasarımımızı yapıyoruz. Bunun için res->layout klasörünün altına tasarımımızı yapacağımız notification_layout.xml dosyamızı oluşturuyoruz.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>

<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:textStyle="bold"
/>

<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
/>

<ImageView

android:id="@+id/img_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
/>

</LinearLayout>

Daha sonra RemoteViews sınıfından nesne üretip bildirim tasarımı için oluşturduğumuz layoutu nesnemize tanımlıyoruz.

val contentView = RemoteViews(context.packageName, R.layout.notification_layout)

Layoutumuzu tanımladık sıra bildirimin içeriğini doldurmaya geldi. Textview’ın içeriğini doldurmak için setTextViewText(…) fonksiyonunu kullanıyoruz. İlk parametre olarak view’in id’sini giriyoruz, ikinci parametre olarak ise view’da gösterilecek veriyi giriyoruz.Aynı şekilde Imageview’ın içeriğini doldurmak için setImageViewResource(…) fonksiyonunu kullanıyoruz.

contentView.setTextViewText(R.id.tv_title, "Özelleştirilmiş Başlık")
contentView.setTextViewText(R.id.tv_content, "Özelleştirilmiş İçerik")
contentView.setImageViewResource(R.id.img_content, R.drawable.large)

Peki özelleştirilmiş bildirimdeki nesnelerin tıklanma olayını nasıl kontrol edeceğiz ?

Bunun için contentView nesnemize ait setOnClickPendingIntent(…) fonksiyonunu kullanmalıyız. Fonksiyon 2 adet parametre almaktadır. İlk parametre olarak view’ın id’sini giriyoruz, ikinci olarak pendingIntent nesnesi giriyoruz. Yine işlem arka planda gerçekleşeceği için BroadcastReceiver sınıfından extend edilmiş CustomNotificationReceiver sınıfını oluşturuyoruz.

class CustomNotificationReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {

Toast.makeText(context, "Click Custom Notification", Toast.LENGTH_LONG).show()

}
}

CustomNotificationReceiver sınıfını kullanabilmek için receiver’ı AndroidManifest.xml dosyasındaki application tag’leri arasına tanımlıyoruz.

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="Mesajlar"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
>
// ----<receiver android:name=".CustomNotificationReceiver" /></application>

Daha sonra CustomNotificationReceiver sınıfına ait intent nesnesi ve bu intent nesnesini kullanacağımız PendingIntent nesnesini oluşturuyoruz.

val broadcastIntent = Intent(this, CustomNotificationReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
this,
0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT
)

Ve son olarak pendingIntent nesnesini contentView’e tanımlıyoruz.

contentView.setOnClickPendingIntent(R.id.tv_title, pendingIntent)
Özelleştirilmiş Bildirim Örneği

Örnek projeye buradan ulaşabilirsiniz.

Kaynak;

    Kerem Türker

    Written by

    #andDev

    Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
    Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
    Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade