1. 项目背景与整体设计
再说一次最近的实战主题:用 Flutter for OpenHarmony 做一款剧本杀组队 App。市面上剧本杀组队的需求其实非常集中,玩家要找人、要选本、要确认场次和人数。我先把需求最重、交互最密集的“剧本库列表”做完,核心就是让玩家在一屏幕里快速浏览几十上百个剧本,再通过搜索、筛选和分页找到合适的本。这篇文章把我整个实现过程,从环境搭建、数据层、列表 UI、交互到 OpenHarmony 真机适配,全部拆开讲一遍。
这个标题里真正有门槛的不是“剧本库列表”本身,而是“Flutter for OpenHarmony”这层组合。Flutter 在 Android、iOS、Web、桌面上的生态已经很成熟,但在 OpenHarmony 设备上跑 Flutter 仍然是一个典型的移植适配场景,SDK 要用专门的 fork 版本,工程约束和权限配置也跟普通 Flutter 工程不一样。把这些前置问题解决干净之后,列表实现的价值才能完全释放出来。
1.1 为什么用 Flutter for OpenHarmony 做剧本杀组队App
先聊选型。剧本杀组队 App 的使用场景很特殊,它不像工具类 App 那样追求极致的系统交互,而是强依赖信息展示、卡片列表、图片封面、评分标签,以及后续的聊天、组队、支付。这种业务形态对 UI 的开发效率要求远高于对系统底层能力的依赖。
如果用纯 OpenHarmony 原生开发(ArkTS 加 ArkUI),当然可以做到很好的体验,但问题是两个:第一,团队里如果原本是 Flutter 团队,重新学 ArkTS 的开发成本不低;第二,后续 App 大概率要同时上 Android、iOS 以及 OpenHarmony 生态设备,维护三套原生代码对一个小团队来说太重了。
Flutter for OpenHarmony 解决的就是这个痛点。它是 OpenHarmony 社区维护的 Flutter 适配版本,核心的渲染能力、Widget 体系、Dart 语言生态都保留了,开发层面几乎跟标准 Flutter 一致。我用 Flutter 写一套业务代码,可以同时覆盖 Android、iOS、OpenHarmony 三个平台。实测做剧本库列表这种以列表、卡片、图片为主的页面,代码复用率能到百分之九十以上,只有少量需要平台通道的地方要单独处理。
1.2 剧本库列表到底要做什么
很多人一听到“剧本库列表”,第一反应就是“ListView.builder 加几个商品卡片”,实际上剧本杀业务对列表的要求比普通商城列表更细。在剧本杀组队场景里,玩家选本时脑子里通常带着几个条件:这个本是什么类型(情感、硬核、欢乐、恐怖、机制),适合几个人玩,玩多久,难度怎么样,评分高不高。
所以剧本库列表的核心职责可以拆成这么几块:
| 功能点 | 具体说明 |
|---|---|
| 剧本卡片展示 | 封面、标题、类型标签、人数范围、游戏时长、难度、评分 |
| 文本搜索 | 按剧本名称或简介关键词检索 |
| 类型筛选 | 按情感、硬核、欢乐、恐怖、机制等标签过滤 |
| 下拉刷新 | 重新拉取最新剧本数据 |
| 上拉加载更多 | 分页机制,避免一次性渲染大量数据 |
| 空状态/错误状态 | 搜索无结果、网络异常时的兜底界面 |
| 跳转详情 | 点击卡片进入剧本详情页 |
这些需求分开看不难,但组合在一起对状态管理和列表性能就有要求了。尤其是搜索和筛选同时生效时,页面的数据源就不再是“一次性拉全量”,而是多个条件叠加后经过内存过滤,再加上分页语义。我在设计时就明确了一点:数据层一定要跟 UI 层解耦,列表页不直接操作数据源集合,而是通过 Repository 层拿到结果,否则后面加接口联调时会改得很痛苦。
1.3 技术选型与状态管理取舍
状态管理我这次没有直接上 Bloc 或者 Riverpod,而是先用 Flutter 自带的 StatefulWidget 加 setState。理由很直接:剧本库列表页的状态管理其实是“单页面状态”,只有数据列表、当前页码、有没有更多数据、加载状态、搜索关键词、筛选条件这几项。setState 完全能撑起来,而且对这个阶段的代码来说最好理解。
当然,这不代表项目里就不引入状态管理框架。组队 App 后续一旦扩展到用户登录态、组队房间实时状态、消息未读数这些跨页面共享的数据,setState 就会显得很吃力。正确的做法是先把列表页做成“单页自治”的形态,等数据流复杂了再平滑迁移到 Riverpod,而不是一上来就为所有页面套上重型框架。
列表本身选择 ListView.builder,这是生成大量同构列表项的标准方案。它只渲染可视区域内的 item,不会一次性把所有剧本卡片都 build 出来。配合后续要讲的 itemExtent 和 const 优化,在 OpenHarmony 中低端设备上也能保持流畅滑动。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与工程搭建
2.1 Flutter for OpenHarmony SDK 下载与配置
Flutter for OpenHarmony 不能直接用官方 flutter.dev 下载的 SDK,要用 OpenHarmony 社区维护的适配版本。我用的方式是直接拉取 ohos 分支的 flutter_flutter 仓库,把它单独放到一个目录,比如 D:\ohos-flutter\flutter,然后用这个 SDK 作为项目的基础工具链。
这里有一个特别容易踩坑的点:机器上如果同时装有官方 Flutter SDK 和 OpenHarmony 适配版 Flutter SDK,很容易出现命令行用的还是旧版本的情况。我的解决方法是做环境隔离,单独开一个终端窗口,在这个窗口里先执行:
bash复制set PATH=D:\ohos-flutter\flutter\bin;%PATH%
flutter --version
确认版本号是适配版之后再继续。另外 OpenHarmony 构建还需要 DevEco Studio 的 SDK 环境变量,一般要指定 DEVECO_SDK_HOME 指向 DevEco Studio 的 SDK 目录,这一步在官方适配文档里有明确说明。
配置完成后运行 flutter doctor,如果环境正常,会看到本地的 Flutter、Dart 和 DevEco 相关的字段都识别到位。实际开发时我建议大家把“适配版 SDK 的 flutter”和“DevEco 的 hvigor”这两条链路都搭配好,因为它们分别负责 Dart 侧编译和鸿蒙应用的打包。
2.2 创建支持 ohos 的 Flutter 工程
环境就绪后,创建工程我推荐用 flutter create 命令直接生成,但要在 --platforms 参数里带上 ohos。命令如下:
bash复制flutter create --template app --platforms ohos,android,ios script_game_app
生成出来的工程目录跟标准 Flutter 工程相比,会多出一个 ohos 目录,这是 OpenHarmony 应用的宿主工程。lib 目录下的 Dart 代码和普通 Flutter 工程完全一样,真正的差异都在 ohos 目录里,包括 entry/src/main/module.json5、entry/src/main/ets 这些鸿蒙侧的配置与入口代码。
我的习惯是创建完工程后,先用 DevEco Studio 打开 ohos 目录,跑一次空工程到模拟器或者真机上,确认整套链路是通的。这一步很重要,因为很多问题出在 SDK 版本、构建工具链的匹配上,跟业务代码没有关系。空工程能跑通,后面加列表代码出问题时就很好定位。
如果需要在 Android 和 OpenHarmony 之间切换运行,直接用同一个 Flutter 工程从 IDE 里选择不同设备即可。实际调试中我在 Android 上开发列表 UI,在 Ohos 真机上做最终验证,效率会高很多。
2.3 权限配置与产物构建
剧本库列表如果用的是网络图片和真实的 API,就必须在鸿蒙侧配置网络权限。OpenHarmony 应用默认是断网的,在 ohos/entry/src/main/module.json5 的 requestPermissions 里要显式声明:
json5复制{
"module": {
"name": "entry",
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
如果只是用本地 asset 图片,这个权限可以不配,但为了后续接口联调,我建议从一开始就加上。
构建和安装也有固定的流程。调试阶段用 flutter build hap --debug,产物会在 build/ohos 目录下生成 HAP 包。安装到真机用 hdc 命令:
bash复制hdc install build/ohos/apps/.../entry-default-signed.hap
真机调试还需要在 DevEco 里完成签名配置。调试签名可以自动生成,但不要把 Debug 签名用于 Release 包,发布到应用市场前需要申请正式的签名证书,这块每个版
