做这个项目是因为公司要在 OpenHarmony 设备上跑电子合同签署流程,设备端手写签名、后台验真、全部通过 API 集成打通。设备选了 RK3568 开发板,UI 框架定了 Flutter,团队里没人同时熟这三样东西,所有坑都是现踩的。这篇记录写给准备在 OpenHarmony 上做 Flutter 应用、并且要对接合同/签署类后端的团队,尤其是和一样第一次接触 OpenHarmony 真机开发的人。下文从架构选型讲到环境搭建、API 契约设计、签署链路实现,再到真机调试里几个最折磨人的报错,全部是按实际项目顺序讲的,可以直接照着排查。
1. 项目背景与技术选型:电子合同在 OpenHarmony 端到底缺什么
1.1 电子合同不是“签字上传”那么简单
很多人第一反应是:电子合同不就是用户点一下“同意”、画个签名、图片传上去吗?真做起来远不是这么回事。
一个最小可用的电子合同系统,移动端至少要承担四项职责:
- 合同生命周期管理:合同从草稿、待签、部分签署、全部签署到归档、作废,每一步都有状态流转。UI 只是展示状态,真正的状态机必须和服务端保持一致。
- 签署方身份可信:签合同的人是谁、以什么角色签、签的是哪一版内容,都要有记录。多数业务场景还会要求先做身份认证,比如短信验证码、身份证 OCR、人脸核身。
- 签名动作留痕:手写签名不是画个图就行,要记录谁在什么时间、什么设备上、对哪个哈希值签了名。这个哈希值关联着合同原文,合同正文一旦被改,验签就能看出来。
- 时间与事件的不可否认性:要么接入第三方时间戳服务,要么用哈希链把每次操作串起来,否则签字记录事后可以被推翻。
所以移动端的技术栈必须同时解决“交互体验”和“数据可信”两个问题。我们用 Flutter 来做 UI,核心原因是跨端一致性。同样的签字交互、合同展示、状态回执在 Android、OpenHarmony 以及后续可能上线的其他设备上都要保持一样,Flutter 的渲染引擎正好能保证这一点。服务端则是一套标准 REST 接口,合同中心、签署中心、验签中心分开部署,移动端不直接碰数据库,所有动作都通过 API 完成。
1.2 Flutter 适配 OpenHarmony 的现状与坑点
在项目启动前,我先确认了 OpenHarmony 上 Flutter 的可用程度。OpenHarmony 官方 SIG 下有 flutter_flutter 仓库,基于上游 Flutter 做 OpenHarmony 适配。基础 UI、手势、动画、Canvas 绘制这些核心能力都能正常使用,做手写签名依赖的 GestureDetector 和 CustomPainter 没有遇到兼容问题。
但有几个明显的差异点,必须提前知道:
- 插件生态没跟上。Flutter 社区常见的 camera、permission_handler、device_info 插件,在 OpenHarmony 侧要么没有原生实现,要么版本很旧。我们需要自己写平台通道,或者基于官方通道做二次封装。
- 构建链和 Android 不完全一样。OpenHarmony 工程由 DevEco Studio 管理,构建工具是 hvigor。虽然 Flutter 桥接层会尽量兼容,但遇到 Gradle 相关的报错还是需要手动处理,后面会详细讲。
- 系统能力接口不同。比如读取设备序列号、获取系统版本、申请存储权限,OpenHarmony 的 API 和 Android 不通用。我们统一封装了一个
OhosBridge通道,把原生能力暴露给 Flutter 层,Flutter 侧只调用 Dart 方法。
这些差异不致命,但每个都会消耗时间。如果团队之前只做过 Android 的 Flutter 开发,一定要提前留出至少一周的适配缓冲。
1.3 整体架构:三层拆开来看
我们这个项目的架构,表面上是一个 Flutter App,实际拆开来看是三段:
Flutter UI 层:负责合同列表、签署详情、手写签名、结果回调展示。这一层的原则是只管展示和交互,不管数据从哪来,所有数据都通过 Repository 层去拿。
平台通道层:用 MethodChannel 把 OpenHarmony 原生能力桥接出来,比如读取设备序列号、获取系统版本、调用系统打印、处理证书相关操作。Flutter 侧定义好接口,OpenHarmony 侧实现具体逻辑。
API 数据层:用 dio 做网络请求,统一处理 Token 注入、验签、超时重试。请求走 HTTPS,响应统一封装成 ApiResponse<T>,对合同这类核心数据还会做二次校验。
这个三层结构的好处是:换后端、换设备能力,都只改一层,不影响其他层。后面几次需求调整,都是改 API 层或者加一个通道方法,Flutter 页面几乎不用动。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境搭建:RK3568 设备树选择、Flutter 分支与 DevEco 工程集成
2.1 RK3568 设备树:同芯片不同板卡的差异
先回答很多人问的问题:OpenHarmony 的 RK3568 设备树那么多,到底咋选?
Kernel 编译产物里会有一堆 .dtb 文件,名字类似 rockchip_rk3568_xxx.dtb,每一个对应一块开发板或者一种外设组合。选错的结果是:要么板子起不来,要么屏幕不亮、触摸失灵、网口不通。
我的选择思路按优先级来:
- 看板卡品牌和型号。OpenHarmony 官方支持的 RK3568 开发板有润和、九联、触觉、飞凌等,厂商一般会提供对应的 device/board 目录或者补丁。优先找和手上板卡一模一样的 dtb。
- 看内核配置和 dtb 列表。在源码根目录执行内核编译命令后,用
make dtbs或者查看.config里的相关配置,能确认当前编译出来的 dtb 清单。对照板卡型号挑选最匹配的。 - 看屏幕和触摸控制器型号。在开机日志里搜
panel、touch、lcd关键词,能定位到对应的 dts 节点。如果当前 dtb 启动后没有触摸,多半是触摸 IC 的 I2C 地址或者复位脚不对,要自己在 dts 里改。 - 没有完全匹配的,选接近的基础型号,然后改 dts。我手上这块板子的双网口和 HDMI 输出与官方默认 dtb 有差异,最后是在官方板卡的 dts 基础上,把网口 phy 的寄存器配置和 HDMI 输出参数改过来的。
一句话总结:设备树不是拍脑袋选的。先确认板子和屏幕,再看 dts 里的节点名和寄存器地址,两相对上再去编译。如果启动日志有 Unsupported board 字样,基本就是 dtb 型号选错了。
2.2 配置 Flutter for OpenHarmony SDK
OpenHarmony 版 Flutter SDK 不是从 flutter.dev 官网下载的,而是使用 gitee 上的 flutter_flutter 仓库。我们当时用的是 3.7 适配版本,对应 OpenHarmony 的某一 API 版本。
安装步骤大致这样:
- 克隆 flutter_flutter 仓库,切换到 openharmony 分支。
- 把
bin目录加入 PATH,配置FLUTTER_ROOT环境变量。 - 执行
flutter doctor,确认 Dart、Flutter 组件可用。 - 执行
flutter precache,拉取 OpenHarmony 平台相关 artifacts。
这里有个容易忽略的坑:如果机器上之前装过官方 Flutter,一定要注意 PATH 里到底指向哪个 flutter。我当时就是 PATH 里官方 Flutter 在前面,命令确实能跑,但构建产物是 Android 的,集成 OpenHarmony 工程时报了一堆看不懂的错误。确认当前 flutter 版本的命令是:
bash复制which flutter
flutter --version
flutter --version 输出里应该能看到 openharmony 相关字样。如果看不到,说明 PATH 指错了。多个 Flutter 共存时,建议用 fvm 做版本管理,或者在项目里锁死 SDK 版本。我没锁版本,后面升级依赖时踩了不少兼容坑。
2.3 Flutter 模块接入 OpenHarmony 工程
Flutter 工程和 OpenHarmony 工程的集成方式,和 Android 的 Flutter module 模式很类似,但细节有差异。我们采用的方案是:
- OpenHarmony 工程由 DevEco Studio 创建,App 壳工程是 OpenHarmony 的。
- Flutter 模块放在工程下单独的目录,里面是完整 Flutter 项目结构。
- 通过
hvigorfile和build-profile.json5做集成,让 OpenHarmony 构建时把 Flutter 的 so 库和资源打进去。
需要注意几个点:
local.properties里的flutter.root必须指向 OpenHarmony 版 Flutter SDK 路径。- 依赖上优先用 OpenHarmony 侧的 ohpm 仓库做原生依赖,纯 Dart 依赖放在
pubspec.yaml。 - 首次构建会拉 Flutter engine 产物,网络状况不好时很容易失败,建议先手动把对应架构的产物下载好放到缓存目录。
集成完成后的验证方法是:先跑一个空 Flutter 页面,能在 OpenHarmony 真机上显示 Hello Flutter,再开始加业务。不要一上来就接所有模块,否则出了问题,真的不知道是 Flutter 问题还是 OpenHarmony 工程问题。
3. 电子合同 API 契约与核心数据模型设计
3.1 合同、签署方、签署记录三张核心表
开始写代码之前,我先把 API 契约定死了。后端是同事负责,前端是我这边,如果各自定义字段,联调必然鸡飞狗跳。核心数据模型是三张表:
合同表(contract)
json复制{
"contract_id": "CT20250101001",
"title": "设备采购框架协议",
"template_id": "TPL_001",
"status": "PENDING",
"created_by": "U001",
"created_at": "2025-01-01T10:00:00+
