我做了一个不会偷看你账单的记账 App
前言
你有没有遇到过这样的困扰?
- 打开记账 App,首页推荐的不是记账功能,而是贷款广告
- 刚在 App 里记录了一笔大额消费,第二天就收到理财产品推送
- 想导出自己的账单数据,却发现只能导出 PDF,无法进一步分析
- 担心记账软件倒闭,多年的财务数据付之东流
作为一个程序员,我对这些问题深感不安。于是,我决定自己动手,做一个真正把数据所有权还给用户的记账应用。
这就是**蜜蜂记账(BeeCount)**的由来。
为什么要自己做记账 App?
市面上记账软件的问题
我调研了市面上主流的记账软件,发现它们普遍存在以下问题:
1. 隐私问题
大多数记账 App 会将你的数据上传到他们的服务器。表面上是为了"云同步",但你的消费习惯、收入水平、资产状况等敏感信息,都被完整地存储在第三方服务器上。
更糟糕的是,很多 App 的隐私政策中明确写着"可能会将数据用于商业分析"或"与合作伙伴共享"。你的财务隐私,实际上已经不再属于你。
2. 广告和推销
免费的记账 App 需要盈利,最常见的方式就是广告和金融产品推销:
- 开屏广告、横幅广告
- 贷款产品推荐
- 理财产品推销
- 信用卡办理引导
有些 App 甚至会根据你的消费数据,"精准推送"贷款广告。这不仅影响使用体验,更让人担心数据被滥用。
3. 功能锁定
很多记账 App 采用"免费增值"模式,核心功能需要付费订阅:
- 多账本管理需要会员
- 数据导出需要会员
- 云同步需要会员
- 图表分析需要会员
一旦停止订阅,功能立刻降级,甚至无法导出历史数据。
4. 数据不可控
当你把数据托管给第三方服务时,你就失去了对数据的完全控制:
- 无法自由选择存储位置
- 无法自由迁移到其他服务
- 服务商倒闭后数据可能丢失
- 无法审计数据的使用情况
理想的记账软件应该是什么样的?
基于这些问题,我列出了理想记账软件的特征:
✅ 数据主权:数据完全由用户掌控,可以选择存储位置 ✅ 隐私保护:开发者无法访问用户数据 ✅ 完全免费:所有功能免费使用,无广告 ✅ 开源透明:代码公开,可审计 ✅ 功能完整:不阉割核心功能 ✅ 自由迁移:支持标准格式导入导出
市面上没有同时满足这些条件的产品,所以我决定自己做一个。
技术选型和架构设计
为什么选择 Flutter?
跨平台是必须的。我希望这个 App 能同时支持 iOS 和 Android,而不是分别开发两个版本。
在对比了 React Native、Flutter、Kotlin Multiplatform 后,我选择了 Flutter:
- 性能优秀:编译为原生代码,接近原生性能
- UI 一致性:自绘引擎保证跨平台 UI 完全一致
- 开发效率:热重载极大提升开发效率
- 生态成熟:包管理、状态管理等工具链完善
数据存储:本地优先 + 可选云同步
本地存储使用 SQLite(通过 Drift ORM):
- 离线优先,无需网络即可使用
- 数据完全存储在设备本地
- 查询性能优秀
- 支持事务和完整性约束
云同步是可选的,而且是自建云服务:
我支持了两种方案:
方案 1:Supabase(推荐新手)
Supabase 是开源的 Firebase 替代品,提供:
- 数据库(PostgreSQL)
- 身份认证
- 对象存储
- 实时订阅
关键是,用户可以使用自己的 Supabase 项目,数据存储在用户自己的 Supabase 实例中,而不是我的服务器。
Supabase 提供免费套餐,对于个人记账完全够用。
方案 2:WebDAV(推荐 NAS 用户)
WebDAV 是一个开放的文件共享协议,支持:
- Synology、QNAP、UGREEN 等 NAS
- Nextcloud、ownCloud 等私有云
- 坚果云等支持 WebDAV 的网盘
用户可以将数据同步到自己的 NAS 或私有云,数据完全本地化。
这两种方案的共同点是:数据存储在用户自己控制的服务器或云平台上,我作为开发者无法访问。
状态管理:Riverpod
Flutter 的状态管理方案很多,我选择了 Riverpod:
- 类型安全,编译时检查
- 依赖注入简洁优雅
- 支持异步状态管理
- 可测试性强
数据导入导出:CSV + 智能识别
为了让用户能够自由迁移数据,我实现了完整的 CSV 导入导出功能。
特别是导入功能,我做了很多优化:
- 智能列映射:自动识别"日期""金额""分类"等常见列名
- 支持多语言:识别中文、英文等不同语言的列名
- 支持支付宝/微信账单:可以直接导入支付宝和微信导出的账单(CSV/XLSX 格式)
- 预览和确认:导入前可以预览数据,调整映射关系
核心功能实现
多账本管理
很多人有多个账本的需求:
- 个人账本
- 家庭账本
- 工作账本
- 投资账本
蜜蜂记账支持创建多个账本,每个账本独立记录,互不干扰。
在底部导航栏有一个专门的"账本"标签,可以快速切换账本。
分类管理
内置了常用的收入和支出分类,同时支持:
- 自定义分类
- 自定义分类图标(Emoji)
- 分类排序
- 分类隐藏/显示
特别地,我实现了分类迁移功能:当你想删除一个分类时,可以选择将该分类下的所有记录迁移到另一个分类,避免数据丢失。
图表分析
实现了多维度的数据分析:
- 月度报表:收入、支出、结余的月度趋势
- 分类统计:各分类的支出占比
- 排行榜:支出金额最多的分类
- 时间筛选:按年、月、全部时间查看
图表使用 fl_chart 库实现,支持交互和动画。
搜索功能
支持全文搜索,可以按:
- 交易描述
- 金额
- 分类
- 日期范围
搜索结果按时间倒序排列。
主题定制
内置了多种主题颜色,用户可以根据喜好选择。
主题系统基于 Material Design 3,自动适配亮色和暗色模式。
国际化支持
为了让更多人使用,我实现了完整的国际化(i18n)支持。
目前支持 9 种语言:
- 简体中文
- 繁体中文
- English
- 日本語
- 한국어
- Español
- Français
- Deutsch
- Português
国际化不仅包括 UI 文本翻译,还包括:
- 日期格式本地化:不同地区的日期格式不同
- 数字格式本地化:千分位分隔符、小数点符号
- 分类名称映射:导入 CSV 时自动识别不同语言的分类名
如果你想贡献新的语言翻译,欢迎提交 Pull Request!
云同步实现细节
云同步是最复杂的部分,我采用了以下设计:
数据模型
每条记录都有以下元数据:
id:唯一标识符(UUID)createdAt:创建时间updatedAt:最后修改时间deletedAt:删除时间(软删除)
同步策略
采用时间戳为基础的增量同步:
- 上传:将本地
updatedAt晚于上次同步时间的记录上传到云端 - 下载:将云端
updatedAt晚于本地记录的数据下载到本地 - 冲突解决:如果同一条记录本地和云端都被修改,以
updatedAt较新的为准
软删除
为了支持多设备同步,删除操作不会真正删除数据,而是:
- 设置
deletedAt字段 - 同步到其他设备
- 其他设备收到后也标记为删除
这样可以避免"在 A 设备删除,同步后又从 B 设备恢复"的问题。
真正的物理删除由用户手动触发("清理已删除数据"功能)。
Supabase 实现
Supabase 提供了完整的后端能力:
- Realtime:实时数据订阅,一个设备修改后其他设备立即更新
- Row Level Security:行级安全策略,确保用户只能访问自己的数据
- Auth:内置身份认证,支持邮箱、OAuth 等多种方式
WebDAV 实现
WebDAV 相对简单:
- 数据以 JSON 格式存储为文件
- 定期轮询检查文件是否有更新
- 使用文件锁避免并发冲突
隐私和安全
数据加密
- 本地数据:存储在 SQLite 数据库中,受操作系统保护
- 传输加密:使用 HTTPS/TLS 加密传输
- 云端存储:由用户自己的 Supabase 或 WebDAV 服务负责
如果用户需要更高的安全性,可以:
- 启用设备的全盘加密
- 使用加密的 WebDAV 服务
- 设置 App 密码锁(计划中)
权限最小化
App 只请求必要的权限:
- 存储权限:用于导入/导出 CSV 文件
- 网络权限:用于云同步(可选)
不需要:
- ❌ 通讯录权限
- ❌ 相机权限
- ❌ 位置权限
- ❌ 电话权限
开源可审计
代码完全开源在 GitHub 上,任何人都可以审计:
- 检查是否有隐藏的数据上传
- 检查是否有安全漏洞
- 贡献代码改进
开发过程中的挑战
1. CSV 解析和智能识别
CSV 格式看似简单,实际上有很多坑:
- 字符编码问题(UTF-8、GBK、GB2312)
- 引号和转义处理
- 多行字段
- 不同的分隔符(逗号、制表符)
支付宝和微信导出的 CSV 格式也各不相同:
支付宝:
- 前 25 行是元信息,第 25 行才是表头
- 列名:
交易时间、商品说明、收/支、金额
微信:
- 前 16 行是元信息
- 列名:
交易时间、交易类型、收/支、金额 - 支持 XLSX 格式
为了支持这些格式,我实现了:
- 智能检测表头位置(扫描前 30 行)
- 灵活的列名匹配(支持多个同义词)
- 用户手动选择账单类型(通用/支付宝/微信)
2. 跨平台 UI 一致性
Flutter 的自绘引擎保证了基本的 UI 一致性,但仍有一些平台差异需要处理:
- 状态栏和导航栏:iOS 和 Android 的高度和样式不同
- 日期选择器:iOS 和 Android 的原生选择器样式完全不同
- 权限请求:iOS 和 Android 的权限模型不同
最终我使用了 SafeArea 和条件编译来处理这些差异。
3. 数据库迁移
随着功能迭代,数据库 schema 需要升级。我使用 Drift 的 migration 功能:
@DriftDatabase
(...)
class
AppDatabase
extends
_
$
AppDatabase
{
@override
int
get
schemaVersion =>
3
;
@override
MigrationStrategy
get
migration => MigrationStrategy(
onUpgrade: (m, from, to)
async
{
if
(from ==
1
) {
await
m.addColumn(transactions, transactions.cloudId);
}
if
(from <=
2
) {
await
m.addColumn(transactions, transactions.deletedAt);
}
},
);
}
每次升级都要确保旧版本用户的数据能够平滑迁移。
4. iOS 发布
Android 可以直接分发 APK,但 iOS 必须通过 App Store 或 TestFlight。
这需要:
- Apple Developer 账号($99/年)
- 代码签名:证书、Provisioning Profile
- 自动化构建:GitHub Actions 自动签名和上传
为了让社区用户能用上 iOS 版本,我在 V2EX 发起了筹款,目标 $99(Apple 开发者账号年费)。
令人感动的是,不到一天时间,目标就达成了(实际筹集 ¥732)。感谢所有支持者!
iOS 版本预计 5-7 天后通过 TestFlight 发布。
开源和社区
为什么选择开源?
- 透明性:用户可以审计代码,确认没有隐私问题
- 可持续性:即使我不再维护,社区也可以 fork 继续开发
- 协作:接受社区贡献,功能迭代更快
- 学习:其他开发者可以学习和参考代码
开源协议:MIT
我选择了 MIT 协议,这是最宽松的开源协议之一:
- ✅ 可以商业使用
- ✅ 可以修改和分发
- ✅ 可以私有使用
- ✅ 可以闭源修改版本
唯一的要求是保留原始的版权声明。
社区参与
项目在 GitHub 上开源:https://github.com/TNT-Likely/BeeCount
目前已有 140+ Stars,欢迎:
- 🐛 提交 Bug 报告
- ✨ 提交功能建议
- 💻 贡献代码
- 🌍 贡献翻译
- 📖 改进文档
未来计划
短期计划(1-2 个月)
- ✅ iOS 版本发布(TestFlight 和 App Store)
- ⏳ iPad 适配优化
- ⏳ 桌面小组件(iOS/Android)
- ⏳ 预算功能
- ⏳ 定期交易(重复记账)
中期计划(3-6 个月)
- 📊 更多图表类型(饼图、趋势图)
- 🔔 提醒功能(账单提醒、预算超支提醒)
- 📸 发票扫描(OCR 识别金额)
- 🎨 更多主题和自定义选项
- 🍎 Apple Watch 版本
- 💬 Siri 快捷指令
长期计划(6 个月以上)
- 🌐 Web 版本(使用 Flutter Web)
- 💻 桌面版本(Windows、macOS、Linux)
- 🤝 家庭账本共享
- 📈 投资组合管理
- 🔄 更多云服务支持(AWS S3、Google Drive、Dropbox)
总结
做蜜蜂记账的初衷很简单:我想要一个不会偷看我账单的记账软件。
在这个数据即金钱的时代,隐私变得越来越珍贵。大多数免费软件都在用你的数据变现,而我希望做一个例外。
蜜蜂记账的核心理念是:
- 🔒 数据主权:你的数据,你做主
- 🆓 完全免费:所有功能永久免费
- 🔓 开源透明:代码公开,可审计
- 🛡️ 隐私优先:开发者无法访问你的数据
如果你也在寻找这样一款记账软件,不妨试试蜜蜂记账。
如果你是开发者,欢迎阅读源码,参与贡献。
让我们一起,把数据所有权还给用户。
相关链接
- GitHub 仓库: https://github.com/TNT-Likely/BeeCount
- 下载地址: https://github.com/TNT-Likely/BeeCount/releases/latest
- V2EX 讨论: https://www.v2ex.com/t/1168480
- 使用文档: GitHub README
关于作者
一名关注隐私和开源的独立开发者,相信技术应该服务于人,而不是控制人。
如果你喜欢这个项目,欢迎在 GitHub 给个 Star ⭐️
