Apps Kit SDK logoApps Kit SDK
文档 · AppsKitSDK (AKS) — Android 集成指南

9. 本地通知 (AppsKitSDKLocalNotificationManager)

AKS 提供了一套轻量级本地通知工具,包括队列、通知构建器和抽象 BroadcastReceiver,可用于显示自定义本地通知。AKS 不会在其清单文件中注册接收器,也不会自动安排通知任务;这两项都需要你自行处理。

9.1 清单文件

继承 AppsKitSDKLocalNotificationBroadCastReceiver(参见 §9.2),并将子类声明为 <receiver>,合并到 §2 中的同一个 <application> 元素内:

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() 中将通知加入队列即可。

此队列通知流程会在 Android 13+ 上自行检查 POST_NOTIFICATIONS。如果尚未获得授权,则会静默跳过通知显示(并记录一条日志),因此请务必先按照 §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() { /* ... */ }
}

在 Doze 模式或电池优化机制下,AlarmManager.setRepeating 无法精确定时。如果需要在设备空闲时可靠触发,请改为在每次触发后使用 setExactAndAllowWhileIdle 重新安排下一次任务,或使用 WorkManager 的 PeriodicWorkRequest(最小间隔为 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+ 上,请自行请求该运行时权限,否则调用可能无法发出通知,且不会报错。