Claude Code Plugins

Community-maintained marketplace

Feedback

android-notification-builder

@dengineproblem/agents-monorepo
0
0

Эксперт Android notifications. Используй для push notifications, channels и notification patterns.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

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