Files
gotmsg/CLAUDE.md
T

88 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 项目概述
**a2i** — 安卓通知转发到 iOS Bark。监听 Android 系统通知(短信、验证码、聊天等),通过 Bark Server 推送到 iOS 设备。iOS 端点击通知可跳转到对应 App(微信、QQ、Telegram)。
## 环境配置(本机)
环境变量需要在每次 shell 调用前显式导出:
```bash
export JAVA_HOME="D:/Dev/JDK-17"
export ANDROID_HOME="D:/Dev/Android/SDK"
```
- JDK 17: `D:\Dev\JDK-17`(项目使用 `sourceCompatibility = VERSION_17`
- Android SDK: `D:\Dev\Android\SDK`
- Gradle 8.11.1wrapper 内置)
- AGP 8.9.1 / Kotlin 2.1.0
`local.properties` 已在项目根(`sdk.dir=D:\Dev\Android\SDK`),**不要提交**。
## 构建与安装
```bash
# 编译 debug APK
export JAVA_HOME="D:/Dev/JDK-17" ANDROID_HOME="D:/Dev/Android/SDK"
./gradlew assembleDebug
# 产物位置
app/build/outputs/apk/debug/app-debug.apk
# 安装到已连接的设备
"D:/Dev/Android/SDK/platform-tools/adb.exe" install -r app/build/outputs/apk/debug/app-debug.apk
```
无 lint / 测试任务配置(项目未启用)。改完代码直接 `assembleDebug` 验证即可。
## 架构
### 核心数据流
```
NotifyListenerService (系统通知入口)
→ NotificationProcessor.process(sbn) → Decision(message, reason, code)
→ BarkClient.push(msg) → OkHttp POST
→ LogStore.addLog(...)
失败 → 加入 pending → RetryWorker (WorkManager, 15min 周期)
```
### 包结构 `com.a2i.forwarder`
| 文件 | 职责 |
|---|---|
| `A2iApp.kt` | `Application` 单例;持有全局 `appScope` 和三个 Store`settings``appRules``logStore`)。Store 都用 `MutableStateFlow`UI 通过 `collectAsState()` 订阅。 |
| `service/NotifyListenerService.kt` | `NotificationListenerService` 实现;每条通知调 `processor.process()`,过滤后推送。 |
| `core/NotificationProcessor.kt` | **核心决策点**。包含 LRU 去重缓存(5s)、脱敏检测(`*****` → 回退到 `tickerText`)、系统状态消息过滤、广告过滤、验证码提取、特殊 App 解析。返回 `Decision(message?, reason, appLabel, code)`。 |
| `core/CodeExtractor.kt` | 三段正则:关键词+数字、数字+关键词、纯数字 4-8 位。检测到全 `*****` 时直接返回 null。 |
| `core/AdFilter.kt` | 内置营销关键词 + 用户自定义关键词(`settings.adKeywords`)。 |
| `core/AppParsers.kt` | 微信/QQ/Telegram 的 `clickUrl` 映射 + 重要消息关键词(@我、验证码、通话等)。 |
| `core/BarkClient.kt` | OkHttp POST 到 `${server}/push`,超时 10/10/15s。 |
| `core/RetryWorker.kt` | WorkManager 周期任务,每 15 分钟重发 `pending` 队列中的失败消息。 |
| `core/LogStore.kt` | 最近 300 条日志 + 失败重发队列(≤100)。DataStore 持久化。 |
| `core/IconExporter.kt` | 一键导出所有已安装 App 图标到用户选择的 SAF 目录(用于部署到 iOS Bark 图床)。 |
| `store/SettingsStore.kt` | Bark 服务器列表、全局开关、广告关键词等。`MutableStateFlow` + DataStore。 |
| `store/AppRulesStore.kt` | 黑/白名单模式 + 默认黑名单(系统 App + 三星剪贴板/键盘 + GMS)。 |
| `ui/nav/AppNav.kt` | 4 个底部 Tab + 日志页。 |
| `ui/screens/*.kt` | HomeScreen(首页统计 + 版本号)、AppManageScreen、FilterScreen、SettingsScreen、LogScreen。 |
| `ui/Components.kt` | `appVersionName(context)` 工具函数用于显示版本号。 |
### 重要约定
- **Store 全局单例**:所有 Store 通过 `A2iApp.instance.xxx` 访问。**不要**在 Compose 中创建新的 Store 实例。
- **协程作用域**:跨屏调用用 `app.appScope.launch { ... }`Application 级别的 `SupervisorJob + Dispatchers.Default`)。
- **过滤流水线**(顺序很重要,在 `NotificationProcessor.process` 中):
1. 全局开关 → 2. ongoing 过滤 → 3. App 黑/白名单 → 4. 空内容/脱敏 → 5. 噪音包名 → 6. 系统状态消息 → 7. 近空内容 → 8. 广告过滤 → **9. 去重检查(5s 窗口)** → 10. 验证码提取 → 11. 特殊 App 解析 → 12. 构造 BarkMessage
- **Bark API** 字段映射在 `BarkMessage.kt``@SerialName`):`device_key`/`autoCopy`/`isArchive` 用下划线/驼峰别名,其他用蛇形。
- **版本号**`app/build.gradle.kts``versionCode`/`versionName`,运行时通过 `appVersionName(context)` 读取,首页底部居中显示 `v{version}`。改完代码记得同步递增。
### 通知监听授权
监听服务依赖 `Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS` 授权。`HomeScreen` 检测授权状态,未授权时显示跳转按钮。授权是**一次性**的,卸载后需重新授权。
### 调试日志
`NotifyListenerService.handle()` 每次都会写一条 `ForwardLog``LogStore`(无论转发/过滤/失败),可在「日志」页查看最近 300 条。失败会自动加入 `pending` 队列,由 `RetryWorker` 后续重发。