
适合谁看
-
正在把 Flutter 项目接到 HarmonyOS 的开发者
-
已经看到
app/ohos/,但还没有整体结构感的人 -
想先建立工程地图,再逐个理解具体文件的人
问题背景
Flutter 项目接入鸿蒙以后,仓库不再只是:
-
lib/ -
android/ -
ios/
而是会多出一整套 app/ohos/ 结构。很多人第一次看到它时,容易出现两种误判:
-
误以为它只是 Flutter 自动生成出来的附属目录
-
误以为只要会改
module.json5就算理解了鸿蒙接入
这两种看法都不够。
因为真正决定后面能不能顺利接语音、TTS、Intent、卡片、防窥这些能力的,是你有没有先把整个工程结构理解成一个分层系统。
项目中的真实场景
食界探味当前的项目结构很适合讲这件事,因为它不是只保留一个最简壳工程,而是已经把鸿蒙项目里最典型的几层都用上了:
-
Flutter 业务代码在
app/lib/ -
HarmonyOS 壳工程在
app/ohos/ -
主入口在
app/ohos/entry/src/main/ets/entryability/EntryAbility.ets -
原生插件在
app/ohos/entry/src/main/ets/plugins/ -
卡片能力在
app/ohos/entry/src/main/ets/formability/ -
模块声明在
app/ohos/entry/src/main/module.json5
换句话说,这个项目里已经能看到一条比较完整的接入链路。
核心实现
如果把 Flutter 项目接入 HarmonyOS 之后的结构压缩成一个最小模型,我更建议先这样理解:
Flutter 业务层
↓
Flutter 平台边界层
↓
HarmonyOS 壳工程
↓
系统入口 / 原生插件 / 卡片能力
这里最重要的一点是:
app/ohos/不是来替代 Flutter 的,而是来承接 Flutter 无法直接承担的系统现实。
如果你是第一次真正读一个已经接好鸿蒙壳工程的 Flutter 项目,我建议先别急着逐个文件死读。
更稳的顺序通常是:
-
先看整体分层
-
再看
app/ohos/顶层 -
再看
entry模块 -
最后才看具体的
EntryAbility、plugins/、formability/
这样你后面读具体文件时,脑子里已经有一张"它在整条链上负责什么"的地图。
第一层:Flutter 业务层继续留在 app/lib/
接入 HarmonyOS 之后,Flutter 主体并没有消失。
像食界探味里真正面向用户的内容,依然主要集中在:
-
app/lib/features/ -
app/lib/data/ -
app/lib/core/
它们负责的是:
-
页面 UI
-
路由
-
状态管理
-
数据组织
-
业务流程
这意味着接入鸿蒙不等于"把项目改写成 ArkTS 项目",而是让 Flutter 业务层和鸿蒙系统层协同。
第二层:平台边界继续收在 app/lib/core/platform/
很多人会以为接了鸿蒙之后,所有和平台相关的东西都应该直接写进 app/ohos/。
但食界探味当前的结构恰好说明,Flutter 和 ArkTS 之间最好还有一层专门的边界层:
-
app/lib/core/platform/speech_recognition_channel.dart -
app/lib/core/platform/text_to_speech_channel.dart -
app/lib/core/platform/intent_navigation_channel.dart -
app/lib/core/platform/anti_peep_protection_channel.dart
这一层的价值是:
-
对 Flutter 页面隐藏原生细节
-
对 ArkTS 插件统一调用协议
-
让页面层不直接碰
MethodChannel的底层细节
所以从工程结构看,HarmonyOS 接入不是"Flutter 一层 + 原生一层",而是至少三层:
-
Flutter 业务层
-
Flutter 平台边界层
-
HarmonyOS 原生层
第三层:app/ohos/ 是正式的鸿蒙壳工程
真正的鸿蒙接入主体就在 app/ohos/。
这个目录里最值得先建立的认知不是"文件很多",而是"它本身就是一个正式平台层"。
在食界探味里,可以先抓住这几个位置:
-
app/ohos/build-profile.json5 -
app/ohos/oh-package.json5 -
app/ohos/entry/
其中:
-
build-profile.json5更接近构建和签名层 -
oh-package.json5更接近鸿蒙依赖层 -
entry/更接近应用模块本体
如果再结合当前工程里的真实内容看,会更容易建立感觉:
-
app/ohos/build-profile.json5已经定义了debug / profile / release -
app/ohos/oh-package.json5是鸿蒙工程级别的包与依赖入口 -
app/ohos/entry/下面再继续分模块、源码、构建目标
也就是说,app/ohos/ 不是一个"单文件配置区",而是一个正式平台工程根目录。
第三层半:先别急着进源码,先把"顶层三件套"分清
很多人第一次进鸿蒙工程时,最容易把这三类文件混在一起:
-
build-profile.json5 -
oh-package.json5 -
module.json5
但它们解决的问题其实不同:
-
build-profile.json5更像"怎么构建、怎么签名、产物怎么出" -
oh-package.json5更像"这个鸿蒙工程依赖什么包" -
module.json5更像"这个模块是什么、入口是谁、权限和扩展能力有哪些"
当前项目里,最值得先建立的习惯就是:
-
构建问题优先看
build-profile.json5 -
依赖问题优先看
oh-package.json5 -
入口、权限、扩展能力问题优先看
module.json5
一旦这三个职责混了,后面排查问题会越来越费劲。
第四层:entry 模块承接真正的鸿蒙应用入口
app/ohos/entry/ 是这个工程里最值得优先理解的地方。
因为从这里开始,你看到的已经不是抽象的"鸿蒙支持",而是具体的应用模块结构。
其中最关键的是:
-
app/ohos/entry/src/main/module.json5 -
app/ohos/entry/src/main/ets/entryability/EntryAbility.ets
module.json5 负责声明这个模块是什么、入口是什么、权限是什么、有哪些扩展能力。
EntryAbility.ets 负责接住真正的应用启动和系统参数。
这两者配合起来,才构成了 Flutter 应用在鸿蒙上的正式落点。
结合当前项目里的真实内容,可以把 module.json5 先粗读成四块:
-
mainElement: "EntryAbility":说明应用主入口是谁 -
abilities:说明主 Ability 怎么声明 -
extensionAbilities:说明除了主入口之外,还声明了哪些扩展能力 -
requestPermissions:说明这个模块需要哪些系统权限
而这份工程里你已经能看到两个非常具体的鸿蒙特征:
-
DailyRecommendFormAbility已经作为extensionAbilities声明进来了 -
MICROPHONE、DLP_GET_HIDE_STATUS这些权限已经进了requestPermissions
这两点很重要,因为它说明:
-
这不是"只会启动 Flutter 页面"的最简工程
-
而是已经开始正式承接语音、防窥、卡片这些鸿蒙能力
第五层:ArkTS 源码并不只有一个"主入口文件"
很多人最初读鸿蒙工程时,会以为:
-
有一个入口
-
有一个页面
-
然后 Flutter 自己跑
但食界探味现在的结构明显更完整。
app/ohos/entry/src/main/ets/ 下面至少已经分出几类职责不同的目录:
-
entryability/:应用主入口和系统入口承接 -
plugins/:系统能力插件实现 -
formability/:卡片能力 -
pages/:Flutter 容器页面
这四类目录本身就说明了一个事实:
Flutter 项目接入 HarmonyOS 后,不是只有一个"启动壳",而是一整套系统承接层。
如果你是第一次看 ets/,我更建议先把它理解成四个问题:
-
应用怎么启动:看
entryability/ -
系统能力怎么桥接:看
plugins/ -
卡片怎么承接:看
formability/ -
Flutter 页面怎么挂到鸿蒙容器里:看
pages/
用这四个问题去读目录,会比死记目录名更有效。
第六层:页面壳、插件壳、卡片壳分别承担不同任务
拿食界探味现有实现举例,会更容易建立结构感。
app/ohos/entry/src/main/ets/pages/Index.ets 里,核心是 FlutterPage({ viewId: this.viewId })。
它说明这一层主要负责把 Flutter 页面真正挂到鸿蒙页面容器里。
app/ohos/entry/src/main/ets/plugins/GeneratedPluginRegistrant.ets 负责注册 Flutter 插件生态里的 Ohos 插件,比如:
-
url_launcher_ohos -
shared_preferences_ohos -
sqflite -
path_provider_ohos
而 EntryAbility.ets 里又额外手动注册了食界探味自己封装的插件:
-
SpeechRecognitionPlugin -
TextToSpeechPlugin -
IntentNavigationPlugin -
AntiPeepProtectionPlugin
这说明项目里的鸿蒙接入不是单层结构,而是:
-
一层承接 Flutter 引擎
-
一层承接官方或生态插件
-
一层承接项目自定义原生能力
如果再往前推进一步,其实还可以把 EntryAbility.ets 里的职责拆得更具体:
-
configureFlutterEngine:注册 Flutter 生态插件和项目自定义插件 -
onCreate:承接冷启动参数 -
onNewWant:承接运行中的新入口请求 -
onWindowStageCreate:初始化窗口环境
这就是为什么我前面一直说,鸿蒙壳工程不是"让 Flutter 能跑就行"。
到了这个层级,它已经在正式管理:
-
Flutter 引擎
-
系统入口
-
原生能力注册
-
窗口环境
第七层:系统入口和卡片能力也是接入结构的一部分
如果只把鸿蒙接入理解成"能跑起来",那很容易忽略后面这两层:
-
app/ohos/entry/src/main/ets/entryability/InsightIntentExecutorImpl.ets -
app/ohos/entry/src/main/ets/formability/DailyRecommendFormAbility.ets
前者说明系统意图入口已经接进来了。
后者说明卡片能力已经接进来了。
这意味着在食界探味里,HarmonyOS 接入不是"应用能启动"这么简单,而是已经延伸到:
-
搜索或系统入口直达
-
卡片触达
-
系统能力插件化
这也是为什么理解工程结构必须先从整体入手,而不是只盯着一个配置文件。
到这里其实就能得到一个很重要的判断:
一个 Flutter 项目是否真的"接入了 HarmonyOS",不是看它有没有
ohos/目录,而是看它有没有把入口、插件、权限、卡片和页面容器都接成一条完整链。
当前项目已经很接近这条完整链了,所以特别适合拿来讲"完整工程结构",而不是只讲某一个能力接入。
第八层:第一次真正读这套工程时,建议按这个顺序
如果你打算把这篇文章写成能直接发的教程,那我建议一定把"阅读顺序"明确写出来。
对第一次接触鸿蒙壳工程的人来说,这比解释一堆名词更有用。
建议顺序可以直接照当前项目来:
-
先看
app/ohos/顶层,建立"这是正式平台工程"的意识 -
再看
app/ohos/build-profile.json5和app/ohos/oh-package.json5 -
再进
app/ohos/entry/,把它当成真正的应用模块去看 -
然后先读
app/ohos/entry/src/main/module.json5 -
再读
app/ohos/entry/src/main/ets/entryability/EntryAbility.ets -
最后才读
plugins/、formability/、pages/
为什么这个顺序更稳?
-
因为它先帮你建立"系统结构感"
-
再帮你建立"模块声明感"
-
最后才进具体实现
很多人之所以第一次看鸿蒙工程会慌,不是因为文件太多,而是因为顺序反了。
关键代码位置
-
app/lib/ -
app/lib/core/platform/ -
app/ohos/build-profile.json5 -
app/ohos/oh-package.json5 -
app/ohos/entry/build-profile.json5 -
app/ohos/entry/src/main/module.json5 -
app/ohos/entry/src/main/ets/entryability/EntryAbility.ets -
app/ohos/entry/src/main/ets/plugins/GeneratedPluginRegistrant.ets -
app/ohos/entry/src/main/ets/pages/Index.ets
鸿蒙侧实现
从鸿蒙侧看,这套接入结构至少分成三类职责:
-
EntryAbility承接应用主入口和系统参数 -
plugins/承接语音、TTS、Intent、防窥等原生能力 -
formability/承接卡片能力
而 module.json5 则像这一切的模块说明书,告诉系统:
-
入口是谁
-
扩展能力有哪些
-
权限需要什么
如果再结合当前项目的真实文件,你可以把鸿蒙侧接入理解成一条实际运行链:
-
build-profile.json5决定构建目标和签名产物 -
module.json5决定模块入口、权限和扩展能力 -
EntryAbility.ets决定 Flutter 引擎、插件注册和启动参数承接 -
pages/Index.ets决定 Flutter 页面如何挂进鸿蒙容器 -
plugins/决定语音、TTS、Intent、防窥等原生能力如何桥接 -
formability/决定卡片如何进入系统桌面触达链
这就是 HarmonyOS 壳工程真正有价值的地方:
它把"启动""能力""入口""卡片"全都接成了一个正式系统层。
Flutter 侧实现
从 Flutter 侧看,接入 HarmonyOS 之后最重要的不是"改很多 Dart 代码",而是把职责收清楚:
-
app/lib/继续负责页面、状态和业务 -
app/lib/core/platform/负责和 ArkTS 之间的边界 -
Flutter 页面不直接碰
Ability、Want、FormExtensionAbility这些系统概念
这也是这套工程结构能长期维护的关键。
也就是说,Flutter 侧最稳的姿势并不是:
- 一看到鸿蒙能力就去页面里直接桥接原生
而是:
-
页面和业务状态继续留在
app/lib/ -
Flutter 和 ArkTS 之间的边界继续收在
app/lib/core/platform/ -
由
app/ohos/去承接真正的系统现实
当前项目里像:
-
speech_recognition_channel.dart -
text_to_speech_channel.dart -
intent_navigation_channel.dart -
anti_peep_protection_channel.dart
就已经把这层边界收得比较清楚了。
这也是为什么我会说,这篇工程结构文必须把 Flutter 侧和鸿蒙侧一起讲,而不能只盯着 app/ohos/。
常见坑
-
把
app/ohos/当成纯自动生成目录,从而不愿意读它 -
只盯着
module.json5,不先建立整体结构感 -
把鸿蒙接入理解成"能跑起来就行",忽略了插件、入口和卡片层
-
以为 Flutter 接入鸿蒙后,业务层应该大量迁到 ArkTS
-
第一次读工程时直接扎进
plugins/,结果越看越乱 -
没分清
build-profile.json5、oh-package.json5、module.json5三者职责 -
看到
EntryAbility.ets只当作启动文件,没有意识到它还在管理引擎、插件和系统入口
可复用模板
Flutter 项目
├── lib/ # 页面、状态、业务
├── android/ # Android 壳工程
├── ios/ # iOS 壳工程
└── ohos/ # HarmonyOS 壳工程
├── build-profile.json5 # 构建与签名
├── oh-package.json5 # 鸿蒙依赖
└── entry/
└── src/main/
├── module.json5 # 模块声明
└── ets/
├── entryability/
├── plugins/
├── formability/
└── pages/
建议阅读顺序
1. 先看 app/ohos 的大结构
2. 再看 build-profile.json5 / oh-package.json5
3. 再看 entry/src/main/module.json5
4. 再看 EntryAbility
5. 最后看 plugins / formability / pages
本篇总结
Flutter 项目接入 HarmonyOS 后,真正新增的不是一个孤立目录,而是一套正式的系统承接层。
在食界探味里,这套结构已经很清楚地分成了:
-
Flutter 业务层
-
Flutter 平台边界层
-
HarmonyOS 壳工程层
-
系统入口、插件和卡片层
只要先把这张工程地图建立起来,后面再读 app/ohos/ 里的单个文件,就不会总觉得它们是零散配置了。
对第一次做鸿蒙 Flutter 接入的人来说,这比死记某个配置项更重要,因为它决定了你后面接插件、接 Intents Kit、接卡片时会不会一直迷路。