我开发了 Traverba——一款完全在手机本地运行的实时翻译应用,无需任何云端 API。它支持语音识别、108 种语言互译、92 种文字的摄像头 OCR、屏幕翻译悬浮窗、文件转录,以及支持最多 7 人通过蓝牙连接的离线群聊。
整个应用由 Flutter 构建,繁重的计算任务则交由原生平台代码承担。以下是这款应用的功能介绍、我选择 Flutter 的原因,以及将其同时发布到 iOS 和 Android 时遇到的最大挑战。
应用功能
Traverba 拥有五大核心功能,全部可在离线状态下使用:
实时语音翻译 — 用一种语言说话,在另一种语言中听到并看到翻译结果。提供三种模式:应用内翻译、悬浮系统音频捕获(可翻译来自 Zoom/Teams/Meet 的音频),以及悬浮麦克风。支持自动朗读目标语言译文。
摄像头翻译 — 将摄像头对准菜单、路牌、表格或文档即可翻译。内置两种 OCR 引擎:Basic 模式(ML Kit)适合快速识别,Professional 模式(PaddleOCR)适用于中日韩、阿拉伯文、西里尔文、梵文等复杂文字。支持 92 种语言。应用会将图像中的外文直接替换为译文显示。
屏幕翻译 — 悬浮窗覆盖层,可翻译任意应用中的文字。无论是看动漫、读韩语新闻、玩日语游戏,还是收到微信消息,点击悬浮按钮即可原位翻译,无需切换应用。
文件转录 — 导入音频或视频文件(mp3、m4a、wav、mp4),获取带时间戳的源文本与译文双栏对照转录稿。
离线群聊 — 最多 7 人通过蓝牙 mesh 连接。每个人用自己的语言发言,所有消息实时翻译成每位参与者的语言。无需联网,无需服务器,每部手机独立完成语音识别和翻译。
所有功能均在手机处理器本地运行。无需 API 密钥,无服务器成本,数据不离开设备。
为什么选择 Flutter
在项目初期,我评估了 Flutter、React Native 以及完全原生(独立的 Swift + Kotlin 代码库)这三种方案。
单一代码库的跨平台能力是硬性要求。 对于一位独立开发者来说,维护两套如此复杂的原生代码库并不现实。Dart UI 层——设置界面、聊天气泡、转录视图、引导tour、下载面板、语言选择器——大约占整体代码量的 60%。写两遍意味着项目周期直接翻倍。
Flutter 的平台通道机制让原生集成变得切实可行。 繁重的 AI 计算(ASR 推理、LLM 翻译、OCR、蓝牙 mesh、悬浮覆盖层)通过平台通道和方法通道在原生 Swift/Kotlin 中运行。Flutter 并不试图成为 AI 运行时,它是连接原生引擎的 UI 与编排层。
性能足够好。 对于这类应用,Flutter 的主要顾虑是开销——在 ASR → 翻译 → TTS 的链式调用中,每一毫秒都很重要。实际上,繁重的计算发生在原生代码中,Flutter 层增加的延迟可以忽略不计。Dart 层负责状态管理、路由和 UI 更新,这些它都做得很好。
热重载大幅提升了 UI 迭代效率。 面对五个独立功能模块(语音、摄像头、屏幕、文件、群聊),每个模块又有多种状态和模式,无需重新构建即可迭代 UI 的能力显著提升了开发效率。
架构:Flutter 作为编排层
应用遵循清晰的职责划分:
Flutter/Dart 层负责:
- 全部 UI(Material 3,手机与平板的自适应布局)
- 状态管理与功能路由
- 语言/地区选择与用户偏好设置
- 可选模型的下载管理
- 积分机制与订阅权限控制
- 新手引导 tour
原生层负责(通过平台通道):
- ASR 推理(sherpa-onnx / whisper.cpp)
- LLM 翻译(设备端 Gemma 运行时)
- 传统 ML 翻译(ONNX NMT 模型)
- 摄像头 OCR(ML Kit + PaddleOCR)
- 文字转语音
- 群聊蓝牙 mesh
- 悬浮覆盖层(屏幕翻译 + 系统音频捕获)
- 内存预算管理与模型加载/卸载
两层之间通过一组具有明确契约的平台通道连接。Dart 侧发送指令("为粤语启动 ASR"、"将这段文字从日语翻译成英语"、"捕获屏幕并进行 OCR"),原生侧异步返回结果。
三个 ASR 模型,自动路由
没有哪一个语音识别模型能对所有语言都表现出色。与其接受某些语言质量不佳的现实,应用内置了三个专项模型:
- Parakeet 英语优化,随应用预置,无需下载即可立即使用英语 ASR。
- Whisper.cpp 广泛的多语言覆盖,支持 30 多种语言。
- Qwen3-ASR 中日韩优化,专门支持粤语。
当用户选择源语言时,Dart 路由层会自动选取最优模型并通知原生侧激活对应引擎,用户无需感知或管理模型选择。
难点在于内存管理。这些模型的内存占用从 500MB 到 1.9GB 不等,同时加载三个会导致大多数手机崩溃。一个用 Dart 编写的内存预算规划器(通过查询原生内存统计)追踪已加载的模型,并在需要加载新模型时卸载最久未使用的模型。后端偏好存储会记录每台具体设备上哪种计算后端(NPU、GPU、CPU)可以正常运行,后续启动时跳过失败的后端。
两级翻译,覆盖 108 种语言
翻译通过两条路径进行:
第一级 — 传统 NMT 模型(61 种语言): 速度快、内存占用低,对资源丰富的语言对质量良好。ONNX 模型通过 sherpa-onnx 在两个平台上运行。
第二级 — 设备端 Gemma LLM(额外 47 种语言): 对于没有专属 NMT 模型的语言(约鲁巴语、阿姆哈拉语、老挝语、缅甸语等),量化后的 Gemma 2B 模型在本地完成翻译。速度比第一级慢,但将覆盖范围延伸到了传统模型支持薄弱的语言。
Dart 层根据语言对自动决定使用哪一级,用户看到的是统一的体验。
摄像头 OCR:双引擎,92 种语言
摄像头翻译提供两个引擎供用户选择:
Basic 模式 使用 Google ML Kit 的设备端文字识别。速度快,对拉丁文、西里尔文和中日韩文字效果良好,适合实时取景器使用。
Professional 模式 使用设备端运行的 PaddleOCR。对复杂版面、混合文字、弯曲文本和低对比度场景精度更高。由于计算量较大,每次使用消耗 5 枚积分。
有一个教训是踩坑得来的:iOS 默认只内置拉丁文 OCR 脚本模型。中日韩、梵文和阿拉伯文需要在 Podfile 中显式添加对应脚本的 pod。失败完全无声无息——ML Kit 对不支持的文字返回空结果,不报任何错误。如果你在 iOS 上用 ML Kit 构建多语言 OCR,务必检查你的 Podfile。
悬浮覆盖层:原生实现,而非 Flutter
屏幕翻译和系统音频功能以原生覆盖层的形式运行,在 Flutter 渲染层之外。Android 上是用 Kotlin 编写的系统悬浮窗服务,iOS 上使用 Swift 的屏幕捕获 API。
这些覆盖层通过平台通道与 Flutter 翻译引擎通信。架构难点在于生命周期管理——覆盖层必须在主 Flutter Activity 可能已进入后台时保持存活。
一个关键教训:在 iOS 上,原生桥接实例必须被强引用(使用 static 或由单例持有)。如果桥接是一个没有任何强引用持有的实例变量,ARC 会将其回收,所有处理器闭包都会悄然变成空操作。我曾因桥接被回收导致下载进度条卡在 0% 而排查了好几天。没有崩溃,没有报错,只是悄无声息地失效。
蓝牙群聊
离线群聊使用蓝牙 mesh 协议。每部手机同时充当接收者和中继节点,消息广播给所有已连接设备。每台设备独立运行自己的 ASR 和翻译——没有"主机"或"服务器"手机。
Flutter 负责聊天 UI、消息状态和参与者管理。蓝牙协议栈完全在原生层实现(iOS 使用 CoreBluetooth,Android 使用蓝牙 API),通过平台通道桥接。
整条管道的延迟(语音 → ASR → 翻译 → 广播 → 显示)约为 1 秒。Dart UI 采用乐观显示策略(发送后立即显示"翻译中..."),使对话体验保持流畅。
数据指标
- 支持语言: 108 种(61 种 ML + 47 种 AI)
- ASR 语言: 30 种设备端语音识别
- OCR 语言: 92 种摄像头文字识别
- 应用基础大小: 约 150MB + 可下载模型
- 支持平台: iOS + Android,单一 Flutter 代码库
- Dart/Flutter 代码: 约占整体代码库的 60%(UI、状态、路由、业务逻辑)
- 原生代码: 约占 40%(ASR、LLM、OCR、蓝牙、覆盖层、内存管理)
- 团队规模: 1 人
Flutter 在这个项目中做对了什么
单一代码库应对复杂 UI。 五个功能模块、各自多种模式、下载面板、新手引导 tour、自适应布局——只写一遍而不是两遍,是独立开发者能够成功发布的关键所在。
平台通道设计良好。 Dart 与原生代码之间的桥接干净、文档完善、可靠稳定。对于一款繁重计算在原生侧、用户体验在 Flutter 侧的应用,这正是最合适的架构。
热重载加速迭代。 调整布局、测试状态、打磨交互流程——热重载将数百次 UI 改动的迭代时间从分钟级压缩到秒级。
生态系统已经成熟。 状态管理(Riverpod)、导航、本地化(117 个地区)、自适应设计——Flutter 生态对这些需求都有生产级的解决方案。
难点所在
内存压力是 Flutter 的盲区。 Flutter 没有暴露细粒度的内存控制能力。当你在 Flutter 引擎旁边同时加载多个原生 ML 模型时,需要在原生层管理内存并将相关信息透传给 Dart。Flutter 没有内置 API 来查询"我的应用使用了多少 RAM"或"当前系统内存压力如何"。
原生覆盖层的生命周期管理。 在 Flutter 渲染层之外运行的悬浮覆盖层架构上相当复杂。Flutter Activity 可能在覆盖层仍然活跃时进入后台。保持桥接存活、管理状态同步、处理平台特定的生命周期事件,需要大量 Flutter 无法抽象的原生代码。
iOS 构建复杂度。 CocoaPods 与 ML Kit 脚本 pod、权限配置(同时加载 ASR + LLM 所需的 increased-memory-limit)、App Tracking Transparency 时序、代码签名——iOS 构建管道涉及许多 Flutter 工具链无法完全管理的环节。
立即体验
Traverba 在两个平台均免费提供。语音、摄像头、屏幕翻译和文本翻译全部免费且无限制使用。高级版($1.99/月)解锁群聊、文件转录和会议摘要功能。
现已上线 Google Play 和 App Store。了解更多请访问 traverba.com。
欢迎就架构设计、Flutter 与原生集成模式或设备端 AI 相关话题提问交流。