一个跑在 Android 16 上的本地记账 App,付完钱自动帮你记一笔。
Kotlin · Jetpack Compose · Room · 纯本地存储 · 无需服务器 · 无需 root
记账这件事真正的门槛不是"记",而是**"坚持记"**。手动记账 App 死于第三天——付完钱要掏手机、点开 App、输金额、选分类,太麻烦了。
这个 App 的做法是:你正常用微信/支付宝付款,它自己把流水记下来。 支付完成几秒后,一条带「自动」标签的记录就出现在列表里,金额、商户、收支方向都填好了。
数据全程存在你手机本地的 SQLite 里,不联网、不上传、不需要注册账号。
| 首页 · 月度流水 | 记一笔 | 自动记账设置 |
|---|---|---|
![]() |
![]() |
![]() |
| 保存后回到列表 | 通知使用权已授权 |
|---|---|
![]() |
![]() |
截图摄于 vivo V2452A(Android 16,API 36,1260×2800)。
- 月度视图:顶部左右箭头切月,汇总卡显示本月收入 / 支出 / 结余
- 按日分组:今天 / 昨天 / 具体日期,每天带当日收支小计
- 记一笔:支出 / 收入分段切换 → 自定义数字键盘 → 分类九宫格 → 备注 → 日期 → 保存
- 编辑与删除:点列表项进编辑页改任意字段;列表长按或编辑页垃圾桶删除,均有二次确认
- 监听微信支付、支付宝的支付通知,自动解析金额、方向、商户并入库
- 三个开关:总开关 + 微信 + 支付宝,可单独关掉某一个
- 按通知 key 去重:同一条通知重复推送只记一次
- 商户关键词推断分类:美团→餐饮、滴滴→交通、京东→购物,猜不到落「其他」,随时可改
- 记账后提醒(可选):弹一条系统通知,点进去直接改这笔
- 列表里带「自动」标签,一眼区分手动录入和自动抓取
- 金额全程用 Long「分」 存储,只在展示时格式化,没有浮点误差
- 数据库 Room v2,带 1→2 迁移脚本(自动记账字段为增量升级,老数据不丢)
- 解析逻辑有 10 个 JUnit 单元测试覆盖金额/方向/商户的边界情况
前往 Releases 页面下载 APK:
| 文件 | 大小 | 说明 |
|---|---|---|
ledger-v1.1.0-release.apk |
11 MB | 正式签名包,装这个(zipalign + v2/v3 签名) |
ledger-v1.1.0-debug.apk |
17 MB | 调试包,仅开发用 |
安装方式:
adb install -r ledger-v1.1.0-release.apk或直接把 APK 传到手机点开安装(Android 16 需给文件管理器授权「允许来自此来源的应用」)。
先说清楚约束:微信和支付宝都没有开放个人账单 API,第三方 App 拿不到交易记录。Android 上唯一不用 root 的路径是 NotificationListenerService——系统把通知文本转交给本 App,App 做解析。
流程:
微信/支付宝推送通知
↓
系统 NotificationListenerService 回调
↓
PaymentNotificationParser 正则抠金额 + 判方向 + 抽商户
↓
AutoCategoryRules 商户关键词 → 分类
↓
Room 插入(notifKey 唯一索引,重复自动忽略)
↓
LedgerNotifier 可选提醒 → 点通知进编辑页
| 项 | 规则 |
|---|---|
| 金额 | ¥12.50 / 12.50元 / 付款12.50 三种模式按优先级匹配,BigDecimal 精确转分 |
| 收支方向 | 命中 退款 / 收款 / 收钱 / 入账 / 转入 → 收入,否则支出 |
| 分类 | 商户关键词表匹配,未命中落「其他」 |
| 去重 | 同一 StatusBarNotification.key 只记一次(IGNORE 插入策略) |
| 兜底 | 来源关键词和金额必须同时命中才入库——宁可漏记,绝不记错 |
⚠️ 一个踩过的坑:方向判断词里不能放「支付」,因为「支付宝」三个字本身包含它,会让所有支付宝通知都被误判为支出。这条已写进单元测试锁住。
- 首页右上角 ⚙ → 自动记账
- 点「去系统设置授权」,在系统页给记账本打开通知使用权(Android 不允许 App 自己开)
- 打开「启用自动记账」,按需勾选微信 / 支付宝
- 想要提醒就再给一下通知权限(Android 13+)
也可以用 adb 一条命令授权:
adb shell cmd notification allow_listener com.qaq.ledger/com.qaq.ledger.autotrack.LedgerNotificationListener必须用完整组件名,短写法 com.qaq.ledger/.autotrack... 在部分 ROM 上会静默失败。
- JDK 21
- Android SDK:API 36(Android 16) + Build-Tools 36.0.0
- Android Studio Narwhal 2025.1 或更新(可选,命令行也能出包)
- File → Open 选择本目录
- 点 Sync Now 等依赖下载完(首次约 5–15 分钟)
- SDK Manager 勾选 Android 16(API 36) 和 Build-Tools 36
- 建一个 API 36 的 AVD(或用真机),点 ▶ Run
export ANDROID_HOME=/path/to/android-sdk
./gradlew assembleDebug # 调试包
./gradlew assembleRelease # 未签名正式包(再用 apksigner 签名)
./gradlew test # 跑解析器单元测试项目根目录的
local.properties需写入sdk.dir=<你的 SDK 路径>,Windows 下冒号要转义:sdk.dir=C\:\\Users\\you\\android-sdk。
app/src/main/java/com/qaq/ledger/
├── MainActivity.kt 唯一 Activity,enableEdgeToEdge()
├── LedgerApp.kt Application,持有依赖容器
├── autotrack/
│ ├── LedgerNotificationListener.kt NotificationListenerService 入口
│ ├── PaymentNotificationParser.kt 金额/方向/商户解析(有单测)
│ ├── AutoCategoryRules.kt 商户 → 分类关键词表
│ └── LedgerNotifier.kt 「已自动记账」提醒
├── data/
│ ├── AppContainer.kt 极简 DI(不引 Hilt)
│ ├── SettingsRepository.kt 开关持久化(SharedPreferences + StateFlow)
│ ├── db/AppDatabase.kt Room 数据库,version 2 + MIGRATION_1_2
│ ├── db/Converters.kt LocalDate ↔ epochDay
│ ├── dao/TransactionDao.kt Flow 查询
│ ├── model/ Transaction / TxType / Category / TxSource
│ └── repository/ 仓库与月度汇总逻辑
├── ui/
│ ├── LedgerNavHost.kt Navigation Compose 路由
│ ├── theme/ Material3 主题与配色
│ ├── home/ 首页 + HomeViewModel
│ ├── editor/ 记一笔 / 编辑页 + ViewModel
│ ├── settings/ 自动记账设置页
│ └── components/ 汇总卡 / 流水行 / 数字键盘 / 日期选择器
└── util/
├── Format.kt 金额与日期格式化
├── NotificationAccess.kt 通知使用权检测
└── ViewModelFactory.kt 简易 ViewModel 工厂
| 依赖 | 版本 |
|---|---|
| Gradle | 8.11.1 |
| Android Gradle Plugin | 8.9.1 |
| Kotlin | 2.1.20 |
| KSP | 2.1.20-1.0.31 |
| Compose BOM | 2025.03.01 |
| Room | 2.7.0 |
| compileSdk / targetSdk | 36 |
| minSdk | 26(Android 8.0) |
Kotlin 与 KSP 版本必须严格成对,升级 Kotlin 时务必同步改 KSP。
- 边到边显示:targetSdk ≥ 35 强制生效,已调用
enableEdgeToEdge(),键盘区加navigationBarsPadding() - 预测式返回:Manifest 中
android:enableOnBackInvokedCallback="true" - 16KB 内存页对齐:AGP 8.5+ 默认处理
- 备份规则:
res/xml/data_extraction_rules.xml限定云备份范围 - 自适应图标:矢量 drawable(minSdk 26 起可用,无需多套 PNG)
- 通知文案随微信 / 支付宝版本变化,改版后可能解析不到(此时该笔不记录,不会记错)
- 收款方向靠关键词推断,好友转账的收款通知也可能判成收入,需人工核对
- 商户名抽取是尽力而为,抽不到就写「微信支付」「支付宝」
- 国产 ROM 的电池优化会杀后台:vivo / OriginOS 需在 设置 → 电池 → 后台耗电管理 里允许后台运行,并在权限管理中允许自启动
- 首版固定浅色主题,未做深色配色
isMinifyEnabled = false,开启混淆前需补齐proguard-rules.pro
- 导出 CSV / JSON 备份与导入(优先级最高——纯本地 App 清数据就没了)
- 统计图表:分类饼图 + 趋势折线
- 月度预算与超支提醒
- 自定义分类管理(图标 / 名称 / 颜色)
- 深色主题
- 不联网,无任何网络权限
- 数据仅存于本机 SQLite(
ledger.db) - 通知文本解析完即丢弃,不留存、不上传
MIT License — 随便用、随便改。




