9. Локальные уведомления (AppsKitSDKLocalNotificationManager)
AKS предоставляет небольшой набор инструментов для локальных уведомлений: очередь, конструктор уведомлений и абстрактный BroadcastReceiver. С их помощью можно показывать собственные локальные уведомления. AKS не регистрирует ресивер в своём манифесте и не настраивает расписание — и то и другое нужно сделать самостоятельно.
9.1 Манифест
Создайте подкласс AppsKitSDKLocalNotificationBroadCastReceiver (см. §9.2) и объявите его как <receiver> внутри того же элемента <application> из §2:
<application
android:name=".YourApplication">
<receiver
android:name=".YourNotificationReceiver"
android:exported="false" />
</application>Если ваше приложение нацелено на Android 13+ (API 33), также добавьте разрешение на отправку уведомлений, запрашиваемое во время выполнения. В манифесте AKS оно не объявлено, поэтому при слиянии манифестов автоматически не добавится:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />POST_NOTIFICATIONS — это разрешение, запрашиваемое во время выполнения, поэтому перед отправкой уведомлений нужно получить его у пользователя (например, через ActivityResultContracts.RequestPermission()).
9.2 Добавление уведомления в очередь
Создайте подкласс AppsKitSDKLocalNotificationBroadCastReceiver и реализуйте checkNotifications(). Этот метод вызывается при каждом срабатывании ресивера и позволяет определить, пора ли показывать уведомление:
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:
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, поэтому вызывать его нужно внутри подкласса, а не из приведённого выше кода:
class YourNotificationReceiver : AppsKitSDKLocalNotificationBroadCastReceiver() {
fun intervalMillis(): Long = getTimeIntervalInMilliSeconds()
override fun checkNotifications() { /* ... */ }
}При включённом режиме Doze или оптимизации энергопотребления
AlarmManager.setRepeatingне гарантирует точное время срабатывания. Если требуется надёжное срабатывание в режиме ожидания, при каждом срабатывании планируйте следующий вызов черезsetExactAndAllowWhileIdleлибо используйтеPeriodicWorkRequestизWorkManager(минимальный интервал — 15 минут). AKS не требует какого-либо из этих вариантов — выбирайте подходящий для вашего приложения. Также учтите: запланированные вызовы не сохраняются после перезагрузки устройства, если вы не регистрируете их заново самостоятельно (например, в ресивереBOOT_COMPLETED).
9.4 Прямой показ уведомления (без очереди)
Чтобы отправить уведомление немедленно, без описанной выше схемы с очередью и ресивером:
// 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+ запросите это разрешение во время выполнения самостоятельно, иначе вызов может не показать уведомление без сообщения об ошибке.