Initial Android notification forwarder

This commit is contained in:
2026-07-06 18:57:40 +08:00
commit 93c4ed9b5b
47 changed files with 3252 additions and 0 deletions
@@ -0,0 +1,64 @@
package com.a2i.forwarder.service
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import com.a2i.forwarder.A2iApp
import com.a2i.forwarder.core.BarkClient
import com.a2i.forwarder.core.ForwardLog
import com.a2i.forwarder.core.NotificationProcessor
import com.a2i.forwarder.core.PendingPush
import com.a2i.forwarder.core.RetryWorker
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.util.UUID
class NotifyListenerService : NotificationListenerService() {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val processor by lazy { NotificationProcessor(applicationContext) }
private val json = Json { encodeDefaults = true; ignoreUnknownKeys = true }
override fun onListenerConnected() {
super.onListenerConnected()
RetryWorker.schedule(applicationContext)
}
override fun onNotificationPosted(sbn: StatusBarNotification?) {
val posted = sbn ?: return
if (posted.packageName == packageName) return
scope.launch { handle(posted) }
}
private suspend fun handle(sbn: StatusBarNotification) {
val app = A2iApp.instance
val now = System.currentTimeMillis()
val d = processor.process(sbn)
val msg = d.message
if (msg == null) {
app.logStore.addLog(ForwardLog(now, sbn.packageName, d.appLabel, "", "", "filtered", d.reason))
return
}
val server = app.settings.currentServer.value
if (server == null || server.deviceKey.isBlank()) {
app.logStore.addLog(ForwardLog(now, sbn.packageName, d.appLabel, msg.title, msg.body, "failed", "未配置 Bark key"))
return
}
val result = BarkClient(server).push(msg)
if (result.isSuccess) {
app.logStore.addLog(ForwardLog(now, sbn.packageName, d.appLabel, msg.title, msg.body, "sent", ""))
} else {
val reason = result.exceptionOrNull()?.message ?: "错误"
app.logStore.addLog(ForwardLog(now, sbn.packageName, d.appLabel, msg.title, msg.body, "failed", reason))
app.logStore.addPending(
PendingPush(UUID.randomUUID().toString(), now, server.id, json.encodeToString(msg))
)
}
}
}