品牌与配置 - 重命名 Bean Mobile → 浮记(DriftLedger),slug 改为 drift-ledger - 所有 Config Plugin 从 app.json 动态读取 appId,替换硬编码 com.beancount.mobile - 预构建时自动从 constants.ts 同步支付包名列表到 Kotlin 端 - size-optimization 插件新增 NDK 版本强制统一(27.1.12297006) - 添加 app icon(direction_a_feather.png) Decimal 精度改造 - 全面消除 parseFloat 用于金额计算的场景,改用 string decimal 运算 - 新增 divideDecimals(除法)、toDateString(Date→YYYY-MM-DD) - negateDecimal 零值特殊处理,避免产生 "-0" - 年报/月报/预算/信用卡/汇率/图表统计等模块全部迁移 - 去重指纹用 parseDecimal 归一化金额格式 - 转账识别增加 normalizeAmount,支持不同精度格式配对(100 vs 100.00) 架构变更 - mobile.bean → main.bean:移除启动时合并迁移逻辑,直接读写 main.bean - TransactionDraft.sourceEventId → sourceEventIds(数组,支持转账双方) - 新增 buildPostings() 纯函数,从 transactionBuilder 提取复式分录构建逻辑 - 新增 csvUtils.ts(引号感知 CSV 行拆分),statements/adapters 共用 - 新增 accessibilityParser.ts:从 automationPipeline 提取微信/支付宝文本解析 - 新增 floatingBillManager.ts:悬浮窗草稿管理(LRU+超时)与排序数据构建 - 新增 txKeyStore.ts:交易级去重键持久化(原子写入+500条LRU) - ledger.ts 新增 resolveIncludes 选项,支持 include 指令递归解析 - metadataStore CRUD 用 createCrudActions 工厂消除7组实体重复代码 安全与持久化 - PIN 哈希改用带盐 SHA-256,兼容旧版无 salt 数据迁移 - storePersistence 从 persistTo 回调改为 subscribe 自动触发 - 持久化增加深比较跳过无变化写入 + 滞后重试 - 新增 flushPersistence(),App 切后台时立即刷盘 - CrashReporter 新增文件持久化(CrashFs 抽象) - settingsStore hydrate 期间跳过自动持久化(skipPersist 标志) 去重与管道 - batchDedup 改用日期索引 Map,候选查找从 O(n) 降至 O(1) - dedupAgainstHistory 按日期分组,仅扫描时间窗口内候选 - OcrProcessor 从布尔标志改为 Promise 队列,不再丢弃并发请求 - 去重缓存改用 Map<hash,timestamp> LRU,阈值超20%时批量淘汰 - 悬浮球全局开关(floatingBallEnabled) + 原生 bridge API 其他改进 - recurring 计算修复月/年溢出(1月31日+1月→2月28日,闰年2月29日) - 预算进度按 posting 分录金额求和(不再仅过滤负数金额) - recurring.ts 用 Date.parse 本地时间替代 toISOString 的 UTC 偏移 - 信用卡账单日/还款日限制不超过28,防止月份溢出 - 类别模糊匹配增加最小长度2,避免单字符误匹配 - 还款检测排除 refund 方向,避免退款被误判为还款 - WebDAV 同步增加 HTTP 日期格式解析 - Git 合并策略改为以 remote 为基础追加 local 独有行 性能优化 - commonStyles 全局 useMemo 缓存 - Button/Card 的 pressIn/pressOut 改用 useCallback - TransactionCard/AccountTreeNode 包裹 React.memo - PostingEditor 用 refs + 函数式更新避免重建 - CreditCard 页预计算账户余额 Map,避免渲染循环重复遍历 - OCR 处理器单例复用,配置变更时才重建 - getLocalAuth/getAccessibilityBridge 结果缓存 测试 - 新增 decimal/constants/channelConfig/transactionBuilder 单测 - 修复金额格式断言(-24.5→-24.50),匹配字符串精度行为 - billPipeline 新增不同格式金额配对、指纹唯一性测试 |
||
|---|---|---|
| .. | ||
| android | ||
| assets | ||
| app.plugin.js | ||
| package.json | ||
| README.md | ||
PP-OCRv5 (ONNX Runtime) Config Plugin
本插件在 expo prebuild 时注入 PP-OCRv5 本地 OCR 原生模块(plan.md 决策 4)。
引擎选用 ONNX Runtime(跨平台、微软官方、Windows 友好),替代原 NCNN 方案。
文件结构
plugins/ppocr/
├── app.plugin.js # Config Plugin 入口(prebuild 时执行)
├── android/ # Kotlin 原生实现(prebuild 时复制进原生工程)
│ ├── OcrModule.kt # React Native Bridge:ONNX Runtime 推理 + det/rec 前后处理
│ └── OcrPackage.kt # RN Package 注册(注入到 MainApplication.getPackages)
└── assets/ # ONNX 模型 + 字典(需自行下载放置)
├── ppocrv5_det.onnx # 文本检测模型
├── ppocrv5_rec.onnx # 文本识别模型(多语言,输出 18385 维)
└── ppocrv5_dict.txt # PP-OCRv5 多语言字典(18383 字符,CTC 解码用)
模型获取(一键下载)
社区已转好的 ONNX 版本(来自官方 Paddle 权重,无质量损失):
# 在项目根目录执行
mkdir -p plugins/ppocr/assets
cd plugins/ppocr/assets
# det 模型(4.8 MB)
curl -L -o ppocrv5_det.onnx https://huggingface.co/ilaylow/PP_OCRv5_mobile_onnx/resolve/main/ppocrv5_det.onnx
# rec 模型(16.6 MB)
curl -L -o ppocrv5_rec.onnx https://huggingface.co/ilaylow/PP_OCRv5_mobile_onnx/resolve/main/ppocrv5_rec.onnx
# PP-OCRv5 多语言字典(74 KB,必须与上面的 rec 模型配套)
curl -L -o ppocrv5_dict.txt https://raw.githubusercontent.com/PaddlePaddle/PaddleOCR/main/ppocr/utils/dict/ppocrv5_dict.txt
或用 HuggingFace CLI(首次下载原生模型再转 ONNX 的方式,参见历史 git log)。
⚠️ 字典必须与 rec 模型配套:ppocrv5_rec.onnx 输出 18385 维(= 18383 字符 + blank + 特殊位), 必须使用
ppocrv5_dict.txt(18383 行)。若错用旧版ppocr_keys_v1.txt(仅 6623 行), CTC 解码会把真实字符的高索引全部丢弃,只输出形如'消'青'露'仰'的单引号穿插单字符乱码。
来源说明:ilaylow/PP_OCRv5_mobile_onnx 是社区维护的 PP-OCRv5 mobile ONNX 镜像,基于官方 PaddlePaddle/PP-OCRv5_mobile_det 与 _rec 转换而来。
性能配置(参考 AutoAccounting OcrProcessor.kt)
| 优化项 | 配置 |
|---|---|
| 引擎 | ONNX Runtime Android 1.20.1 |
| 执行器 | CPU(兼容性最稳,部分设备 GPU 会崩溃) |
| 线程 | intraOp=2 / interOp=2 |
| det 图像 | 最大边 960px,短边压缩 720px |
| rec 图像 | 固定高度 48px |
| ABI | arm64-v8a(主流设备) |
使用
在 app.json 注册插件:
{
"plugins": ["./plugins/ppocr"]
}
JS 层通过 src/services/ocrBridge.ts 的 NativeOcrBridge 调用,桥接到 NativeModules.PpOcr:
recognizeText(base64)→ 返回纯文本(多行用\n连接)recognizeTextBlocks(base64)→ 返回带坐标的文本块数组[{text, x, y, width, height, confidence}]isReady()→ 模型是否加载完成
当前状态
app.plugin.js:✅ Config Plugin 逻辑(prebuild 注入 Kotlin + 模型 + gradle 依赖 + MainApplication 注册)android/OcrModule.kt:✅ ONNX Runtime 推理(det DB 后处理 + rec CTC 解码)android/OcrPackage.kt:✅ RN Package 注册assets/:需自行下载放置(见上「模型获取」),版权/体积原因不入仓库
真机构建步骤:放置模型文件 → npx expo prebuild --platform android(Config Plugin 会把 Kotlin 源码与 assets/ 下的模型/字典复制进 android/)→ npx expo run:android。
若之前已 prebuild 过且更换过字典/模型文件,务必重新执行
npx expo prebuild --clean,否则android/app/src/main/assets/下可能残留旧字典(如ppocr_keys_v1.txt),导致新代码找不到配套字典。