Notifikasi memberikan informasi singkat dan tepat waktu tentang peristiwa di aplikasi Anda saat aplikasi tidak digunakan. Dokumen ini menunjukkan cara membuat notifikasi dengan berbagai fitur. Untuk pengantar cara notifikasi muncul di Android, lihat Ringkasan notifikasi. Untuk mengetahui kode contoh yang menggunakan notifikasi, lihat contoh SociaLite di GitHub.
Kode di halaman ini menggunakan API NotificationCompat dari Library
AndroidX. API ini memungkinkan Anda menambahkan fitur yang hanya tersedia di versi Android yang lebih baru, sekaligus memberikan kompatibilitas mundur ke Android 9 (level API 28).
Namun, beberapa fitur, seperti tindakan balasan inline, menghasilkan no-op pada
versi sebelumnya.
Membuat notifikasi dasar
Notifikasi dalam bentuk yang paling dasar dan ringkas—juga dikenal sebagai bentuk yang diciutkan—menampilkan ikon, judul, dan sedikit konten teks. Bagian ini menunjukkan cara membuat notifikasi yang dapat diketuk pengguna untuk meluncurkan aktivitas di aplikasi Anda.
Gambar 1. Notifikasi dengan ikon, judul, dan beberapa teks.
Untuk mengetahui detail selengkapnya tentang setiap bagian notifikasi, baca anatomi notifikasi.
Mendeklarasikan izin runtime
Android 13 (level API 33) dan yang lebih baru mendukung izin runtime untuk memposting notifikasi yang tidak dikecualikan (termasuk layanan latar depan (FGS)) dari aplikasi.
Izin yang perlu Anda deklarasikan di file manifes aplikasi akan muncul dalam cuplikan kode berikut:
<manifest ...> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <application ...> ... </application> </manifest>
Untuk mengetahui detail selengkapnya tentang izin runtime, lihat Izin runtime notifikasi.
Menetapkan konten notifikasi
Untuk memulai, tetapkan konten dan saluran notifikasi menggunakan objek NotificationCompat.Builder. Contoh berikut menunjukkan cara
membuat notifikasi dengan hal berikut:
Ikon kecil, yang ditetapkan oleh
setSmallIcon(). Ini adalah satu-satunya konten yang terlihat oleh pengguna yang diperlukan.Judul, yang ditetapkan oleh
setContentTitle().Teks isi, yang ditetapkan oleh
setContentText().Prioritas notifikasi, yang ditetapkan oleh
setPriority(). Prioritas menentukan seberapa mengganggu notifikasi di Android 7.1 dan yang lebih lama. Untuk Android 8.0 dan yang lebih baru, tetapkan tingkat kepentingan saluran seperti yang ditunjukkan di bagian berikutnya.
val textTitle = "Title" val textContent = "Content" val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle(textTitle) .setContentText(textContent) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
Konstruktor NotificationCompat.Builder mengharuskan Anda memberikan ID
saluran. Hal ini diperlukan untuk kompatibilitas dengan Android 8.0 (level API 26) dan
yang lebih baru, tetapi diabaikan oleh versi yang lebih lama.
Secara default, konten teks notifikasi dipotong agar pas dalam satu baris. Anda dapat menampilkan informasi tambahan dengan membuat notifikasi yang dapat diluaskan.
Gambar 2. Notifikasi yang dapat diluaskan dalam bentuk yang diciutkan dan diluaskan.
Jika ingin notifikasi lebih panjang, Anda dapat mengaktifkan notifikasi yang dapat diperluas dengan menambahkan template gaya dengan setStyle(). Misalnya,
kode berikut membuat area teks yang lebih besar:
val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .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)
Untuk mengetahui informasi selengkapnya tentang gaya notifikasi besar lainnya, termasuk cara menambahkan gambar dan kontrol pemutaran media, lihat Membuat notifikasi yang dapat diperluas.
Membuat saluran dan menetapkan kepentingannya
Sebelum dapat mengirimkan notifikasi di Android 8.0 dan yang lebih baru, daftarkan
saluran notifikasi aplikasi Anda ke sistem dengan meneruskan instance
NotificationChannel ke createNotificationChannel(). Kode
berikut diblokir oleh kondisi pada versi SDK_INT:
fun createNotificationChannel(context: Context) { // 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 = context.getString(R.string.channel_name) val descriptionText = context.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 = context.getSystemService(NotificationManager::class.java) as NotificationManager notificationManager.createNotificationChannel(channel) } }
Karena Anda harus membuat saluran notifikasi sebelum memposting notifikasi di Android 8.0 dan yang lebih tinggi, jalankan kode ini saat aplikasi Anda dimulai. Memanggil berulang kali aman dilakukan karena membuat channel yang sudah ada tidak akan berpengaruh apa pun.
Konstruktor NotificationChannel memerlukan tingkat kepentingan menggunakan konstanta NotificationManager. Hal ini menentukan cara menginterupsi
pengguna. Untuk mendukung Android 7.1 dan yang lebih rendah, tetapkan juga prioritas dengan
setPriority() seperti yang ditunjukkan dalam contoh sebelumnya.
Meskipun Anda harus menetapkan tingkat kepentingan atau prioritas, sistem tidak menjamin perilaku pemberitahuan. Sistem mungkin menyesuaikannya berdasarkan faktor lain, dan pengguna selalu dapat menyesuaikan tingkat kepentingan saluran.
Untuk informasi perbedaan tingkat selengkapnya, baca tingkat kepentingan notifikasi.
Menetapkan tindakan ketuk notifikasi
Setiap notifikasi harus merespons ketukan, biasanya untuk membuka aktivitas di aplikasi
Anda yang sesuai dengan notifikasi. Untuk melakukannya, tentukan intent konten
yang ditentukan dengan objek PendingIntent dan teruskan ke
setContentIntent().
Cuplikan berikut ini menunjukkan cara membuat intent dasar untuk membuka aktivitas saat pengguna mengetuk notifikasi:
// Create an explicit intent for an Activity in your app. val intent = Intent(context, AlertDetails::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .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)
Kode ini memanggil setAutoCancel(), yang otomatis menghapus
notifikasi saat pengguna mengetuknya.
Flag intent dalam contoh sebelumnya mempertahankan pengalaman navigasi yang diharapkan pengguna setelah pengguna membuka aplikasi Anda menggunakan notifikasi. Anda mungkin ingin menggunakannya, bergantung pada jenis aktivitas yang Anda mulai, yang bisa berupa salah satu dari berikut ini:
Aktivitas yang ada khusus untuk merespons notifikasi. Tidak ada alasan bagi pengguna untuk membuka aktivitas ini selama penggunaan aplikasi normal, sehingga aktivitas memulai tugas baru, bukan ditambahkan ke tugas dan data sebelumnya yang ada di aplikasi Anda. Ini adalah jenis intent yang dibuat dalam contoh sebelumnya.
Aktivitas yang ada dalam alur aplikasi reguler aplikasi Anda. Dalam hal ini, memulai aktivitas akan membuat data sebelumnya sehingga ekspektasi pengguna untuk tombol Kembali dan Atas dipertahankan.
Menampilkan notifikasi
Agar notifikasi muncul, panggil
NotificationManagerCompat.notify(), dengan meneruskan ID unik untuk
notifikasi dan hasil NotificationCompat.Builder.build(). Hal ini ditunjukkan dalam contoh berikut:
with(NotificationManagerCompat.from(context)) { if (ActivityCompat.checkSelfPermission( context, 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(notificationId, builder.build())
Simpan ID notifikasi yang Anda teruskan ke NotificationManagerCompat.notify(),
karena Anda memerlukannya saat ingin memperbarui atau
menghapus notifikasi.
Selain itu, untuk menguji notifikasi dasar di perangkat yang berjalan di Android 13 dan yang lebih baru, aktifkan notifikasi secara manual atau buat dialog untuk meminta notifikasi.
Menambahkan tombol tindakan
Notifikasi dapat menawarkan hingga tiga tombol tindakan yang memungkinkan pengguna merespons dengan cepat, seperti menunda pengingat atau membalas pesan teks. Namun, tombol tindakan ini tidak boleh menduplikasi tindakan yang dilakukan saat pengguna mengetuk notifikasi.
Gambar 3. Notifikasi dengan satu tombol tindakan.
Untuk menambahkan tombol tindakan, teruskan PendingIntent ke metode
addAction(). Ini seperti menyiapkan tindakan ketuk default notifikasi, tetapi
bukan meluncurkan aktivitas, Anda dapat melakukan hal lain seperti memulai
BroadcastReceiver yang menjalankan tugas di latar belakang sehingga
tindakan tersebut tidak mengganggu aplikasi yang sudah terbuka.
Misalnya, kode berikut ini menunjukkan cara mengirim siaran ke penerima tertentu:
val ACTION_SNOOZE = "snooze" val snoozeIntent = Intent(context, MyBroadcastReceiver::class.java).apply { action = ACTION_SNOOZE putExtra(EXTRA_NOTIFICATION_ID, 0) } val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(context, 0, snoozeIntent, PendingIntent.FLAG_IMMUTABLE) val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .addAction(R.drawable.snooze, context.getString(R.string.snooze), snoozePendingIntent)
Untuk mengetahui informasi selengkapnya tentang cara membangun BroadcastReceiver untuk menjalankan pekerjaan
latar belakang, lihat Ringkasan siaran.
Jika Anda mencoba membuat notifikasi dengan tombol pemutaran media, seperti untuk menjeda dan melewati trek, lihat cara membuat notifikasi dengan kontrol media.
Menambahkan tindakan balasan langsung
Tindakan balasan langsung, yang diperkenalkan di Android 7.0 (level API 24), memungkinkan pengguna memasukkan teks langsung ke dalam notifikasi. Teks kemudian dikirim ke aplikasi Anda tanpa membuka aktivitas. Misalnya, Anda dapat menggunakan tindakan balasan langsung untuk memungkinkan pengguna membalas pesan teks atau memperbarui daftar tugas dari dalam notifikasi.
Gambar 4. Mengetuk tombol "Balas" akan membuka input teks.
Tindakan balasan langsung muncul sebagai tombol tambahan dalam notifikasi yang membuka input teks. Setelah pengguna selesai mengetik, sistem akan melampirkan respons teks ke intent yang Anda tentukan untuk tindakan notifikasi dan mengirimkan intent tersebut ke aplikasi Anda.
Menambahkan tombol balas
Untuk membuat tindakan notifikasi yang mendukung balasan langsung, ikuti langkah-langkah berikut:
Buat instance RemoteInput.Builder yang dapat Anda tambahkan ke tindakan notifikasi. Konstruktor class ini menerima string yang digunakan sistem sebagai kunci untuk input teks. Aplikasi Anda nantinya akan menggunakan kunci tersebut untuk mengambil teks input.
// Key for the string that's delivered in the action's intent. val replyLabel: String = context.resources.getString(R.string.reply_label) val remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run { setLabel(replyLabel) build() }
Buat PendingIntent untuk tindakan balasan.
// Build a PendingIntent for the reply action to trigger. val replyPendingIntent: PendingIntent = PendingIntent.getBroadcast(context, conversationId, getMessageReplyIntent(conversationId), PendingIntent.FLAG_MUTABLE)
Lampirkan objek RemoteInput ke tindakan menggunakan
addRemoteInput().
// Create the reply action and add the remote input. val action: NotificationCompat.Action = NotificationCompat.Action.Builder(R.drawable.reply, context.getString(R.string.reply_label), replyPendingIntent) .addRemoteInput(remoteInput) .build()
Terapkan tindakan tersebut pada notifikasi dan keluarkan notifikasinya.
// Build the notification and add the action.
val newMessageNotification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle(context.getString(R.string.title))
.setContentText(context.getString(R.string.content))
.addAction(action)
.build()
// Issue the notification.
NotificationManagerCompat.from(context).notify(notificationId, newMessageNotification)
Sistem akan meminta pengguna untuk memasukkan respons saat mereka memicu tindakan notifikasi, seperti yang ditunjukkan pada gambar 4.
Mengambil input pengguna dari balasan
Untuk menerima input pengguna dari UI balasan notifikasi, panggil
RemoteInput.getResultsFromIntent(), dengan meneruskan Intent yang diterima oleh
BroadcastReceiver Anda:
private fun getMessageText(intent: Intent): CharSequence? { return RemoteInput.getResultsFromIntent(intent)?.getCharSequence(KEY_TEXT_REPLY) }
Setelah Anda memproses teks, perbarui notifikasi dengan memanggil
NotificationManagerCompat.notify() dengan ID dan tag yang sama, jika digunakan. Hal ini
diperlukan untuk menyembunyikan UI balasan langsung dan mengonfirmasi kepada pengguna bahwa balasan mereka
diterima dan diproses dengan benar.
// Build a new notification, which informs the user that the system // handled their interaction with the previous notification. val repliedNotification = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.message) .setContentText(context.getString(R.string.replied)) .build() // Issue the new notification. NotificationManagerCompat.from(context).notify(notificationId, repliedNotification)
Mengambil data lainnya
Penanganan jenis data lainnya berfungsi serupa dengan RemoteInput. Contoh berikut
menggunakan gambar sebagai input.
val replyLabel: String = context.resources.getString(R.string.reply_label) val remoteInput: RemoteInput = RemoteInput.Builder(KEY_REPLY).run { setLabel(replyLabel) // Allow for image data types in the input. // This method can be used again to allow for other data types. setAllowDataType("image/*", true) build() }
Panggil RemoteInput#getDataResultsFromIntent dan ekstrak data yang sesuai.
class ReplyReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val dataResults = RemoteInput.getDataResultsFromIntent(intent, KEY_REPLY) val imageUri: Uri? = dataResults?.get("image/*") as? Uri if (imageUri != null) { // Extract the image context.contentResolver.openInputStream(imageUri)?.use { inputStream -> val bitmap = BitmapFactory.decodeStream(inputStream) // Display the image // ... } } } companion object { const val KEY_REPLY = "key_reply" const val KEY_TEXT_REPLY = "key_text_reply" } }
Saat menggunakan notifikasi baru ini, gunakan konteks yang diteruskan ke
metode onReceive() penerima.
Tambahkan balasan ke bagian bawah notifikasi dengan memanggil
setRemoteInputHistory(). Namun, jika Anda membuat aplikasi pesan,
buat notifikasi bergaya pesan dan tambahkan pesan baru ke
percakapan.
Untuk saran selengkapnya terkait notifikasi dari aplikasi pesan, lihat bagian tentang praktik terbaik untuk aplikasi pesan.
Menampilkan pesan penting
Aplikasi Anda mungkin perlu menampilkan pesan penting dan yang sensitif waktu, seperti panggilan telepon masuk atau alarm yang berdering. Dalam situasi ini, Anda dapat mengaitkan intent layar penuh dengan notifikasi.
Saat notifikasi dipanggil, pengguna akan melihat salah satu hal berikut, bergantung pada status kunci perangkat:
- Jika perangkat pengguna terkunci, aktivitas layar penuh muncul, menutupi layar kunci.
- Jika perangkat pengguna tidak dikunci, notifikasi muncul dalam bentuk diperluas yang mencakup opsi untuk menangani atau mengabaikan notifikasi.
Cuplikan kode berikut menunjukkan cara mengaitkan notifikasi Anda dengan intent layar penuh:
val fullScreenIntent = Intent(context, ImportantActivity::class.java) val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, fullScreenIntent, PendingIntent.FLAG_IMMUTABLE) val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setFullScreenIntent(fullScreenPendingIntent, true)
Menetapkan visibilitas layar kunci
Untuk mengontrol tingkat detail yang terlihat dalam notifikasi dari layar kunci,
panggil setVisibility() dan tentukan salah satu nilai berikut:
VISIBILITY_PUBLIC: konten lengkap notifikasi ditampilkan di layar kunci.VISIBILITY_SECRET: tidak ada bagian notifikasi yang ditampilkan di layar kunci.VISIBILITY_PRIVATE: hanya informasi dasar, seperti ikon notifikasi dan judul konten, yang ditampilkan di layar kunci. Konten lengkap notifikasi tidak ditampilkan.
Saat menyetel VISIBILITY_PRIVATE, Anda juga dapat memberikan versi alternatif
konten notifikasi yang menyembunyikan detail tertentu. Misalnya, aplikasi SMS
mungkin menampilkan notifikasi yang bertuliskan "Anda memiliki 3 pesan teks baru", tetapi
menyembunyikan konten dan pengirim pesan. Untuk memberikan notifikasi
alternatif ini, buat terlebih dahulu notifikasi alternatif dengan
NotificationCompat.Builder seperti biasa. Kemudian, lampirkan notifikasi alternatif
ke notifikasi normal dengan setPublicVersion().
Perlu diingat bahwa pengguna selalu memiliki kontrol penuh atas apakah notifikasinya terlihat di layar kunci dan dapat mengontrolnya berdasarkan saluran notifikasi aplikasi Anda.
Memperbarui notifikasi
Untuk memperbarui notifikasi setelah Anda mengeluarkannya, panggil
NotificationManagerCompat.notify() lagi, dengan meneruskan ID yang sama dengan yang Anda gunakan
sebelumnya. Jika notifikasi sebelumnya ditutup, notifikasi baru akan dibuat.
Anda dapat secara opsional memanggil setOnlyAlertOnce() agar notifikasi
menginterupsi pengguna—dengan suara, getaran, atau petunjuk visual—hanya
saat notifikasi pertama kali muncul dan bukan untuk update berikutnya.
Menghapus notifikasi
Notifikasi akan tetap terlihat hingga salah satu hal berikut terjadi:
- Pengguna menutup notifikasi.
- Pengguna mengetuk notifikasi, jika Anda memanggil
setAutoCancel()saat membuat notifikasi. - Anda memanggil
cancel()untuk ID notifikasi tertentu. Metode ini juga menghapus notifikasi berkelanjutan. - Anda memanggil
cancelAll(), yang akan menghapus semua notifikasi yang sebelumnya Anda keluarkan. - Durasi yang ditentukan berlalu, jika Anda menetapkan waktu tunggu saat membuat notifikasi, menggunakan
setTimeoutAfter(). Jika diperlukan, Anda dapat membatalkan notifikasi sebelum durasi waktu tunggu yang ditentukan berlalu.
Praktik terbaik untuk aplikasi pesan
Pertimbangkan praktik terbaik yang tercantum di sini saat membuat notifikasi untuk aplikasi pesan dan chat Anda.
Menggunakan MessagingStyle
Mulai Android 7.0 (level API 24), Android menyediakan template gaya notifikasi khusus untuk konten pesan. Dengan menggunakan
class NotificationCompat.MessagingStyle, Anda dapat mengubah beberapa
label yang ditampilkan pada notifikasi, termasuk judul percakapan,
pesan tambahan, dan tampilan konten untuk notifikasi.
Cuplikan kode berikut menunjukkan cara menyesuaikan gaya notifikasi
menggunakan class MessagingStyle.
val message1 = NotificationCompat.MessagingStyle.Message( messages[0].text, messages[0].time, messages[0].sender ) val message2 = NotificationCompat.MessagingStyle.Message( messages[1].text, messages[1].time, messages[1].sender ) notification = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setStyle( NotificationCompat.MessagingStyle(Person.Builder().setName("Me").build()) .addMessage(message1) .addMessage(message2) ) .build()
Mulai Android 9.0 (level API 28), Anda juga harus menggunakan class Person untuk mendapatkan rendering notifikasi dan avatar yang optimal.
Saat menggunakan NotificationCompat.MessagingStyle, lakukan hal berikut:
- Panggil
MessagingStyle.setConversationTitle()untuk menetapkan judul chat grup dengan lebih dari dua orang. Judul percakapan yang baik mungkin berupa nama chat grup atau, jika tidak memiliki nama, daftar peserta dalam percakapan. Tanpa ini, pesan mungkin disalahartikan sebagai percakapan pribadi dengan pengirim pesan terbaru dalam percakapan. - Gunakan metode
MessagingStyle.setData()untuk menyertakan pesan media seperti gambar. Jenis MIME dengan pola image/* didukung.
Menggunakan Balasan Langsung
Balasan Langsung memungkinkan pengguna membalas pesan secara inline.
- Setelah pengguna membalas dengan tindakan balasan inline, gunakan
MessagingStyle.addMessage()untuk mengupdate notifikasiMessagingStyle, dan jangan menarik kembali atau membatalkan notifikasi. Jika notifikasi tidak dibatalkan, pengguna dapat mengirim beberapa balasan dari notifikasi. - Agar tindakan balasan inline kompatibel dengan Wear OS, panggil
Action.WearableExtender.setHintDisplayInlineAction(true). - Gunakan
metode
addHistoricMessage()untuk memberikan konteks ke percakapan balasan langsung dengan menambahkan pesan historis ke notifikasi.
Mengaktifkan Smart Reply
- Untuk mengaktifkan Smart Reply, panggil
setAllowGeneratedResponses(true)pada tindakan balasan. Hal ini menyebabkan respons Smart Reply tersedia bagi pengguna saat notifikasi dijembatani ke perangkat Wear OS. Respons Smart Reply dihasilkan oleh model machine learning yang sepenuhnya ada di smartwatch menggunakan konteks yang disediakan oleh notifikasiNotificationCompat.MessagingStyle, dan tidak ada data yang diupload ke internet untuk menghasilkan respons.
Menambahkan metadata notifikasi
- Tetapkan metadata notifikasi untuk memberi tahu sistem cara menangani notifikasi aplikasi
saat perangkat dalam mode Jangan Ganggu. Misalnya, gunakan metode
addPerson()atausetCategory(Notification.CATEGORY_MESSAGE)untuk mengganti mode Jangan Ganggu.