开工之前,先聊聊这套系统到底在解决什么问题
这两年做跨端应用,我最大的感受是“跨端”二字的含金量正在被重新定义。以前说跨端,基本就是一套 Flutter 代码跑 iOS 和 Android,顶多再兼顾一下 Web。但从去年开始,OpenHarmony 的设备量明显起来了,尤其是行业定制设备——工业平板、车载终端、维修门店的工位看板,很多都换成了基于 OpenHarmony 的方案。我们接到的车辆维修管理系统需求里,客户点名要求“一套代码,既要跑在原来的 Android 平板上,也要跑在 OpenHarmony 的 RK3568 工控机上”,这才是真正的跨端挑战。
这个项目里最有代表性、也最适合拿出来拆解的就是通知公告模块。原因很简单:它是维修管理系统里最高频、最容易被感知的功能——技师开工要看公告、接单要看派工通知、管理层下发制度要看推送。同时它又是典型的“数据展示 + 实时同步 + 多端适配”场景,正好能把 Flutter 的跨端能力、OpenHarmony 的平台特性、本地数据库与后端同步的常见矛盾全部串起来。
这篇文章我就以通知公告模块为切入点,完整复盘一下这套 Flutter × OpenHarmony 跨端车辆维修管理系统从设计到落地的过程。适合正在做 Flutter 跨端项目、准备适配 OpenHarmony、或者对“本地数据库 + 后端同步”方案感兴趣的开发者参考。我会把模块设计思路、数据库选型、同步协议、UI 实现、OpenHarmony 适配细节和踩坑记录都写清楚,尽量做到拿来就能用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
1. 整体架构与设计思路拆解
1.1 为什么是 Flutter + OpenHarmony,而不是别的组合
先回答一个很多人会问的问题:既然要适配 OpenHarmony,为什么不直接用 ArkUI 原生开发,非要绕一圈用 Flutter?
我的回答是:看你的存量代码和团队结构。我们团队从三年前就开始用 Flutter 做业务,维修管理系统里已经有大量成熟的 Flutter 业务组件、工具库和状态管理方案,如果全部用 ArkUI 重写,成本不是一个数量级的。而 Flutter 官方对 OpenHarmony 的适配已经比较成熟,Flutter 3.7 之后,社区维护的 flutter_flutter 分支可以跑在 OpenHarmony 3.2 及以上版本,核心的渲染引擎、Dart 运行时、Platform Channel 机制都能正常工作。这意味着我们只需要处理平台相关的桥接层,业务层代码几乎零改动。
从实际效果看,Flutter 的 Skia 渲染引擎在 RK3568 这类中低端芯片上表现也可接受。公告列表的滚动、图片懒加载、页面转场这些常规操作都能保持流畅,不会出现明显的掉帧。相比 ArkUI 的声明式开发,我们的团队迁移成本更低,开发效率更高。
1.2 通知公告模块的边界划分与功能定位
在开始写代码之前,我们花了很大精力做模块边界划分。通知公告模块看起来简单,但如果没有清晰的定义,很容易在后期被各种需求“加料”加到失控。
我们的做法是把这个模块拆成四个子功能域:
- 公告列表:分页展示、分类筛选(维修规范、安全通知、排班调整、客户提醒)、关键字搜索。
- 公告详情:富文本渲染、附件下载、阅读状态标记。
- 消息中心:与公告不同,消息是面向单个用户的,比如“您有一条新派工单”“您负责的工位设备需要保养”,展示维度是“与我相关”。
- 系统通知:强提醒类内容,比如版本升级、系统维护、紧急安全通知,支持推送和弹窗。
这四块的共性在于都是“服务端产生内容 → 客户端拉取/接收 → 本地存储 → 用户阅读/操作”,所以我们统一抽象了一套数据模型和存储方案。差异在于消息的个性化属性更重,公告的系统属性更重,体现在数据库表设计和同步策略上会有所不同。
1.3 技术选型的核心考量:离线优先还是在线优先
做维修管理系统,有一个场景必须考虑:维修车间的网络环境并不总是稳定的。地沟、烤漆房、车间角落,很多工位的位置信号不好,如果系统设计成“必须联网才能看公告”,一旦网络抖动,技师连今天的安全早会内容都看不到,这就很尴尬。
所以我们决定采用“离线优先”(Offline-First)的策略:
- 客户端内置本地数据库,作为公告和消息的“第一数据源”。
- 进入模块时,先展示本地缓存的数据,用户无感知等待。
- 后台静默同步,与服务端比对增量数据,有新公告就拉取,有阅读状态变更就上报。
- 网络不可用时,降级为纯本地模式,用户仍然可以浏览已缓存的公告,阅读操作也会记录在本地,待网络恢复后自动补交。
这个设计直接决定了后续的数据库选型和同步协议设计。它和普通 CMS 的公告系统最大的区别在于:我们不是简单地从接口拉数据展示,而是要做“本地库 + 远程库”的数据对账。
2. 本地数据层设计:内嵌数据库的选型与表结构
2.1 Flutter 内嵌数据库选型:sqflite 还是 drift 还是 Hive
数据层是通知公告模块的地基。Flutter 生态里常见的本地数据库方案我基本都试过,这里做一个对比:
- sqflite:老牌方案,基于 SQLite,SQL 语法完整,和 Android 原生开发的习惯一致。但在 OpenHarmony 上有兼容性问题,需要依赖社区适配包,且不支持跨 isolate 访问,复杂查询容易卡 UI。
- drift:基于 sqflite 的封装,提供类型安全的查询 API 和迁移工具,开发体验好很多,但底层还是依赖 sqflite,OpenHarmony 上同样存在适配问题。
- Hive:纯 Dart 实现的 NoSQL 数据库,读写速度极快,但只支持简单的 key-value 和对象存储,不适合做复杂的列表筛选和条件查询。公告模块有分类筛选、分页、排序这类需求,Hive 用起来会非常别扭。
- OpenHarmony 自带的 RelationalStore:这是 OpenHarmony 为应用提供的原生关系型数据库 API,基于 SQLite,支持复杂的 SQL 查询,性能稳定。Flutter 通过 Platform Channel 调用 RelationalStore 是一个完全可行的路径。
我们最终的选择是:Android 和 iOS 平台用 sqflite,OpenHarmony 平台用 RelationalStore,然后用一个统一的抽象层把两者的差异封装起来。为什么不用纯 Dart 方案?因为公告数据量不大,但查询模式复杂,SQL 关系型数据库在语义上最合适;为什么不做单一数据库?因为 Flutter 官方在 OpenHarmony 上的 sqflite 适配还不够完善,与其在兼容层上耗费精力,不如直接对接 RelationalStore 原生能力。
2.2 公告与消息的数据表设计
数据库表设计我直接放出最终版本,这是经过几个版本迭代后比较稳定的结构。
公告表(notice_tb):
| 字段 | 类型 | 说明 |
|---|---|---|
| id | TEXT | 公告 ID,服务端 UUID,主键 |
| title | TEXT | 公告标题 |
| content | TEXT | 公告内容,富文本 JSON 或 HTML |
| category | INTEGER | 分类:1维修规范,2安全通知,3排班调整,4客户提醒 |
| priority | INTEGER | 优先级:0普通,1重要,2紧急 |
| publisher | TEXT | 发布 |
