android-notification-builder
Эксперт Android notifications. Используй для push notifications, channels и notification patterns.
When & Why to Use This Skill
The Android Notification Builder Expert is a specialized Claude skill designed to streamline the development of robust notification systems for Android applications. It provides production-ready Kotlin code snippets for implementing Notification Channels (API 26+), NotificationCompat.Builder, and advanced notification patterns. By focusing on modern best practices, security, and user experience, this skill helps developers efficiently manage push notifications, interactive actions, and Firebase Cloud Messaging (FCM) integrations.
Use Cases
- Implementing and managing Notification Channels to categorize app alerts by priority and user preference.
- Creating rich, expandable notifications using BigTextStyle, BigPictureStyle, and InboxStyle for enhanced user engagement.
- Adding interactive elements like 'Reply' and 'Archive' action buttons directly within notifications using RemoteInput.
- Displaying real-time progress for background tasks or downloads using determinate and indeterminate progress bars.
- Integrating Firebase Cloud Messaging (FCM) to handle remote data payloads and display consistent push notifications.
- Optimizing notification performance and security, including visibility settings for the lock screen and efficient bitmap scaling.
| name | android-notification-builder |
|---|---|
| description | Эксперт Android notifications. Используй для push notifications, channels и notification patterns. |
Android Notification Builder Expert
Эксперт по реализации уведомлений Android с использованием NotificationCompat.Builder и notification channels.
Notification Channels (API 26+)
class NotificationHelper(private val context: Context) {
companion object {
const val CHANNEL_ID_MESSAGES = "messages"
const val CHANNEL_ID_UPDATES = "updates"
const val CHANNEL_ID_PROMOTIONS = "promotions"
}
fun createNotificationChannels() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val messagesChannel = NotificationChannel(
CHANNEL_ID_MESSAGES,
"Сообщения",
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "Уведомления о новых сообщениях"
enableLights(true)
lightColor = Color.BLUE
enableVibration(true)
vibrationPattern = longArrayOf(0, 250, 250, 250)
}
val updatesChannel = NotificationChannel(
CHANNEL_ID_UPDATES,
"Обновления",
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "Системные обновления"
}
val notificationManager = context.getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannels(
listOf(messagesChannel, updatesChannel)
)
}
}
}
Базовое уведомление
fun showBasicNotification(title: String, message: String) {
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(
context, 0, intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val notification = NotificationCompat.Builder(context, CHANNEL_ID_MESSAGES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notification)
}
Расширяемые уведомления
Big Text Style
fun showExpandableTextNotification(title: String, shortText: String, longText: String) {
val bigTextStyle = NotificationCompat.BigTextStyle()
.bigText(longText)
.setBigContentTitle(title)
.setSummaryText("Подробности")
val notification = NotificationCompat.Builder(context, CHANNEL_ID_MESSAGES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(shortText)
.setStyle(bigTextStyle)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notification)
}
Big Picture Style
fun showImageNotification(title: String, message: String, bitmap: Bitmap) {
val bigPictureStyle = NotificationCompat.BigPictureStyle()
.bigPicture(bitmap)
.bigLargeIcon(null as Bitmap?)
.setBigContentTitle(title)
.setSummaryText(message)
val notification = NotificationCompat.Builder(context, CHANNEL_ID_MESSAGES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(message)
.setLargeIcon(bitmap)
.setStyle(bigPictureStyle)
.build()
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notification)
}
Inbox Style
fun showInboxNotification(title: String, messages: List<String>) {
val inboxStyle = NotificationCompat.InboxStyle()
.setBigContentTitle(title)
.setSummaryText("${messages.size} новых сообщений")
messages.take(5).forEach { message ->
inboxStyle.addLine(message)
}
val notification = NotificationCompat.Builder(context, CHANNEL_ID_MESSAGES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText("${messages.size} новых сообщений")
.setStyle(inboxStyle)
.setNumber(messages.size)
.build()
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notification)
}
Интерактивные уведомления
Action Buttons
fun showNotificationWithActions(title: String, message: String) {
// Reply action
val replyIntent = Intent(context, ReplyReceiver::class.java)
val replyPendingIntent = PendingIntent.getBroadcast(
context, 0, replyIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val remoteInput = RemoteInput.Builder("key_text_reply")
.setLabel("Ответить")
.build()
val replyAction = NotificationCompat.Action.Builder(
R.drawable.ic_reply,
"Ответить",
replyPendingIntent
).addRemoteInput(remoteInput).build()
// Archive action
val archiveIntent = Intent(context, ArchiveReceiver::class.java)
val archivePendingIntent = PendingIntent.getBroadcast(
context, 1, archiveIntent,
PendingIntent.FLAG_IMMUTABLE
)
val archiveAction = NotificationCompat.Action.Builder(
R.drawable.ic_archive,
"Архивировать",
archivePendingIntent
).build()
val notification = NotificationCompat.Builder(context, CHANNEL_ID_MESSAGES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(message)
.addAction(replyAction)
.addAction(archiveAction)
.build()
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notification)
}
Progress Notification
fun showProgressNotification(title: String, maxProgress: Int, currentProgress: Int) {
val notification = NotificationCompat.Builder(context, CHANNEL_ID_UPDATES)
.setSmallIcon(R.drawable.ic_download)
.setContentTitle(title)
.setContentText("Загрузка: $currentProgress%")
.setProgress(maxProgress, currentProgress, false)
.setOngoing(true)
.build()
NotificationManagerCompat.from(context).notify(PROGRESS_NOTIFICATION_ID, notification)
}
fun showIndeterminateProgress(title: String) {
val notification = NotificationCompat.Builder(context, CHANNEL_ID_UPDATES)
.setSmallIcon(R.drawable.ic_sync)
.setContentTitle(title)
.setContentText("Синхронизация...")
.setProgress(0, 0, true)
.setOngoing(true)
.build()
NotificationManagerCompat.from(context).notify(PROGRESS_NOTIFICATION_ID, notification)
}
fun completeProgressNotification(title: String) {
val notification = NotificationCompat.Builder(context, CHANNEL_ID_UPDATES)
.setSmallIcon(R.drawable.ic_done)
.setContentTitle(title)
.setContentText("Загрузка завершена")
.setProgress(0, 0, false)
.build()
NotificationManagerCompat.from(context).notify(PROGRESS_NOTIFICATION_ID, notification)
}
Grouped Notifications
fun showGroupedNotifications(messages: List<Message>) {
val GROUP_KEY = "com.example.MESSAGE_GROUP"
// Individual notifications
messages.forEachIndexed { index, message ->
val notification = NotificationCompat.Builder(context, CHANNEL_ID_MESSAGES)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle(message.sender)
.setContentText(message.text)
.setGroup(GROUP_KEY)
.build()
NotificationManagerCompat.from(context).notify(index, notification)
}
// Summary notification
val summaryNotification = NotificationCompat.Builder(context, CHANNEL_ID_MESSAGES)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle("${messages.size} новых сообщений")
.setStyle(NotificationCompat.InboxStyle()
.setBigContentTitle("${messages.size} новых сообщений")
.setSummaryText("Сообщения"))
.setGroup(GROUP_KEY)
.setGroupSummary(true)
.build()
NotificationManagerCompat.from(context).notify(SUMMARY_ID, summaryNotification)
}
FCM Integration
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
remoteMessage.notification?.let { notification ->
showNotification(
notification.title ?: "Уведомление",
notification.body ?: ""
)
}
remoteMessage.data.isNotEmpty().let {
handleDataMessage(remoteMessage.data)
}
}
override fun onNewToken(token: String) {
sendTokenToServer(token)
}
private fun showNotification(title: String, body: String) {
val notification = NotificationCompat.Builder(this, CHANNEL_ID_MESSAGES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(body)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(this).notify(
System.currentTimeMillis().toInt(),
notification
)
}
}
Лучшие практики
Безопасность
// Скрытие контента на lock screen
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
.setPublicVersion(publicNotification)
// Безопасные PendingIntent
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
Производительность
// Оптимизация bitmap
fun scaleBitmap(bitmap: Bitmap, maxSize: Int = 256): Bitmap {
val ratio = minOf(
maxSize.toFloat() / bitmap.width,
maxSize.toFloat() / bitmap.height
)
return Bitmap.createScaledBitmap(
bitmap,
(bitmap.width * ratio).toInt(),
(bitmap.height * ratio).toInt(),
true
)
}
Пользовательский опыт
- Используйте соответствующие importance levels
- Группируйте связанные уведомления
- Добавляйте действия для быстрого реагирования
- Обеспечьте accessibility через content descriptions
- Тестируйте на разных версиях Android