Apps Kit SDK logoApps Kit SDK
Документация · AppsKitSDK (AKS) — Руководство по интеграции для Android

9. Локальные уведомления (AppsKitSDKLocalNotificationManager)

AKS включает небольшой набор инструментов для локальных уведомлений: очередь, сборщик уведомлений и абстрактный BroadcastReceiver. С их помощью можно показывать собственные локальные уведомления. AKS не регистрирует ресивер в своём манифесте и не настраивает расписание — и то и другое нужно сделать самостоятельно.

9.1 Манифест

Создайте подкласс AppsKitSDKLocalNotificationBroadCastReceiver (пример в §9.2) и объявите его как <receiver> внутри того же элемента <application>, что и в §2, чтобы при слиянии манифестов он попал в этот элемент:

xml
<application
    android:name=".YourApplication">

    <receiver
        android:name=".YourNotificationReceiver"
        android:exported="false" />

</application>

Если ваше приложение нацелено на Android 13+ (API 33), также добавьте разрешение на отправку уведомлений, запрашиваемое во время выполнения. В манифесте AKS оно не объявлено, поэтому при слиянии манифестов автоматически не добавится:

xml
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

POST_NOTIFICATIONS — разрешение, запрашиваемое во время выполнения. Поэтому, прежде чем уведомления начнут отображаться, его нужно запросить у пользователя (например, через ActivityResultContracts.RequestPermission()).

9.2 Добавление уведомления в очередь

Создайте подкласс AppsKitSDKLocalNotificationBroadCastReceiver и реализуйте checkNotifications(). Этот метод вызывается при каждом срабатывании ресивера: в нём вы определяете, пора ли показывать уведомление.

kotlin
class YourNotificationReceiver : AppsKitSDKLocalNotificationBroadCastReceiver() {

    override fun checkNotifications() {
        addNotificationInQueue(
            NotificationModel(
                id = "daily_reminder",                      // dedup key — a second add with the same id is ignored
                title = "Come back!",
                description = "You have unfinished items waiting.",
                icon = R.drawable.ic_notification,
                notificationId = 1001,                       // the actual Android notification ID passed to notify()
                targetScreen = "com.yourapp.MainActivity"    // fully-qualified Activity class opened on tap
            )
        )
    }
}

Сразу после завершения checkNotifications() метод onReceive автоматически вызывает AppsKitSDKLocalNotificationManager.showNotification(context): он извлекает из очереди самый старый объект NotificationModel и отображает уведомление. При таком сценарии вызывать showNotification самостоятельно не нужно — достаточно добавить уведомление в очередь внутри checkNotifications().

При показе через очередь наличие разрешения POST_NOTIFICATIONS на Android 13+ проверяется автоматически. Если разрешение не выдано, показ пропускается без ошибки, но с записью в лог. Поэтому сначала запросите разрешение, как описано в §9.1.

9.3 Настройка расписания

AKS не регистрирует этот ресивер и не запускает его по расписанию — вы сами определяете, когда вызывается onReceive, обычно с помощью AlarmManager:

kotlin
val intent = Intent(context, YourNotificationReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
    context, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)

val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setRepeating(
    AlarmManager.RTC_WAKEUP,
    System.currentTimeMillis() + intervalMs,
    intervalMs,
    pendingIntent
)

Для intervalMs можно задать фиксированный интервал в коде или использовать значение из удалённой конфигурации на портале AKS (HOURS_TO_MAKE_NOTIFICATION; если не задано, по умолчанию используется 2 часа). Это значение доступно через getTimeIntervalInMilliSeconds() в базовом классе ресивера. Однако метод имеет модификатор protected, поэтому вызывать его нужно внутри подкласса, а не из кода выше:

kotlin
class YourNotificationReceiver : AppsKitSDKLocalNotificationBroadCastReceiver() {
    fun intervalMillis(): Long = getTimeIntervalInMilliSeconds()
    override fun checkNotifications() { /* ... */ }
}

AlarmManager.setRepeating не гарантирует точное время срабатывания в режиме Doze и при оптимизации энергопотребления. Если нужно надёжное срабатывание во время простоя устройства, при каждом срабатывании планируйте следующее через setExactAndAllowWhileIdle либо используйте PeriodicWorkRequest из WorkManager (минимальный интервал — 15 минут). AKS не навязывает ни один из вариантов — выбирайте подходящий для вашего приложения. Также учтите: запланированные срабатывания не сохраняются после перезагрузки устройства, если вы не зарегистрируете их заново самостоятельно (например, в ресивере BOOT_COMPLETED).

9.4 Прямой показ уведомления (без очереди)

Чтобы показать уведомление сразу, без описанного выше механизма очереди и ресивера:

kotlin
// Tapping opens the Activity at classPath
AppsKitSDKLocalNotificationManager.showNotification(
    context = this,
    id = 2001,
    classPath = "com.yourapp.MainActivity",
    channelId = "general",
    title = "New message",
    message = "You've got a new message waiting.",
    notificationIcon = R.drawable.ic_notification
)

// Or pass a fully-built Intent instead of a class path
AppsKitSDKLocalNotificationManager.showNotification(
    context = this,
    id = 2002,
    intent = Intent(this, MainActivity::class.java).putExtra("from", "notification"),
    channelId = "general",
    title = "New message",
    message = "Tap to view details.",
    notificationIcon = R.drawable.ic_notification
)

Обе перегрузки автоматически создают канал уведомлений, если он ещё не существует. В отличие от показа через очередь в §9.2, ни одна из них не проверяет POST_NOTIFICATIONS. На Android 13+ запросите разрешение во время выполнения самостоятельно, иначе вызов может не показать уведомление и не сообщить об ошибке.