鸿蒙 EntryAbility 里怎么把 Flutter 引擎、插件注册和启动参数串起来
适合谁看
-
正在读
EntryAbility.ets的开发者 -
想理解鸿蒙 Flutter 启动链的人
-
已经接入插件,但还没理清冷启动参数的人
问题背景
很多开发者第一次看 EntryAbility 时,会把它误认为只是"应用启动入口"。但在真实项目里,它通常至少还承担三件额外事情:
-
配置 Flutter 引擎
-
注册原生插件
-
承接系统传入参数
如果不先把这三层分清,后面看插件和入口时会很乱。
项目中的真实场景
食界探味当前的 EntryAbility.ets 完整代码:
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { AbilityConstant, Want } from '@kit.AbilityKit';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
import SpeechRecognitionPlugin from '../plugins/SpeechRecognitionPlugin';
import TextToSpeechPlugin from '../plugins/TextToSpeechPlugin';
import IntentNavigationPlugin from '../plugins/IntentNavigationPlugin';
import AntiPeepProtectionPlugin from '../plugins/AntiPeepProtectionPlugin';
import window from '@ohos.window';
export default class EntryAbility extends FlutterAbility {
configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
flutterEngine.getPlugins()?.add(new SpeechRecognitionPlugin())
flutterEngine.getPlugins()?.add(new TextToSpeechPlugin())
flutterEngine.getPlugins()?.add(new IntentNavigationPlugin())
flutterEngine.getPlugins()?.add(new AntiPeepProtectionPlugin())
}
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onCreate(want, launchParam)
const pageId = want.parameters?.['pageId'] as string;
const dishId = want.parameters?.['dishId'] as string;
if (pageId) {
IntentNavigationPlugin.setPendingNavigation(pageId, dishId);
}
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onNewWant(want, launchParam)
const pageId = want.parameters?.['pageId'] as string;
const dishId = want.parameters?.['dishId'] as string;
if (pageId) {
const plugin = IntentNavigationPlugin.getInstance();
if (plugin) {
plugin.navigateToPage(pageId, dishId);
} else {
IntentNavigationPlugin.setPendingNavigation(pageId, dishId);
}
}
}
onWindowStageCreate(windowStage: window.WindowStage): void {
super.onWindowStageCreate(windowStage)
windowStage.getMainWindow().then((mainWindow: window.Window) => {
mainWindow.setWindowLayoutFullScreen(true)
mainWindow.setWindowSystemBarEnable([])
}).catch((err: Error) => {
console.error(`Failed to enable immersive window: ${JSON.stringify(err)}`)
})
}
}
核心实现
一、EntryAbility 的 4 个生命周期方法
|
方法 |
触发时机 |
职责 |
|---|---|---|
|
|
Flutter 引擎配置时 |
注册插件 |
|
|
应用冷启动时 |
承接冷启动参数 |
|
|
应用运行中收到新 Intent 时 |
承接运行期入口 |
|
|
窗口创建时 |
初始化窗口环境 |
二、configureFlutterEngine——把"能力前提"先准备好
configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
flutterEngine.getPlugins()?.add(new SpeechRecognitionPlugin())
flutterEngine.getPlugins()?.add(new TextToSpeechPlugin())
flutterEngine.getPlugins()?.add(new IntentNavigationPlugin())
flutterEngine.getPlugins()?.add(new AntiPeepProtectionPlugin())
}
这个阶段做了两件事:
1. 生态插件自动注册
GeneratedPluginRegistrant.registerWith(flutterEngine)
GeneratedPluginRegistrant 会自动注册 pubspec.yaml 中声明的 Flutter 插件。
2. 项目自定义插件手动注册
flutterEngine.getPlugins()?.add(new SpeechRecognitionPlugin())
flutterEngine.getPlugins()?.add(new TextToSpeechPlugin())
flutterEngine.getPlugins()?.add(new IntentNavigationPlugin())
flutterEngine.getPlugins()?.add(new AntiPeepProtectionPlugin())
这 4 个插件是食界探味自己写的鸿蒙原生插件,需要手动 add 进去。
为什么要手动注册:
|
插件 |
通道名 |
作用 |
|---|---|---|
|
|
|
语音识别 |
|
|
|
TTS |
|
|
|
Intent 导航 |
|
|
|
防窥保护 |
如果漏注册会怎样:
漏注册 SpeechRecognitionPlugin
→ Flutter 调用 SpeechRecognitionChannel.startListening()
→ MissingPluginException
→ 语音识别静默失效
漏注册 IntentNavigationPlugin
→ Flutter 调用 IntentNavigationChannel.init()
→ 通道不存在
→ 系统入口跳转全部失效
三、onCreate——承接"冷启动参数"
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onCreate(want, launchParam)
const pageId = want.parameters?.['pageId'] as string;
const dishId = want.parameters?.['dishId'] as string;
if (pageId) {
IntentNavigationPlugin.setPendingNavigation(pageId, dishId);
}
}
冷启动时,系统通过 want.parameters 传入启动参数。onCreate 读取这些参数后,调用 setPendingNavigation 暂存。
为什么不能在 onCreate 里直接写页面跳转:
|
原因 |
说明 |
|---|---|
|
Flutter 引擎未 ready |
|
|
GoRouter 未初始化 |
路由系统还没准备好 |
|
插件实例未创建 |
|
所以只能先暂存为 pending,等 Flutter 初始化后消费。
pending 机制的工作原理:
onCreate(want)
→ 提取 pageId, dishId
→ IntentNavigationPlugin.setPendingNavigation(pageId, dishId)
→ pendingNavigation = { pageId, dishId }
Flutter 初始化后
→ IntentNavigationChannel.init()
→ _consumePending()
→ invokeMethod('consumePendingNavigation')
→ 拿到 { pageId, dishId }
→ _navigate() → 路由跳转
四、onNewWant——承接"运行中的新入口请求"
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onNewWant(want, launchParam)
const pageId = want.parameters?.['pageId'] as string;
const dishId = want.parameters?.['dishId'] as string;
if (pageId) {
const plugin = IntentNavigationPlugin.getInstance();
if (plugin) {
plugin.navigateToPage(pageId, dishId);
} else {
IntentNavigationPlugin.setPendingNavigation(pageId, dishId);
}
}
}
onNewWant 处理的是"应用已存活时再次收到入口请求"的场景。
和 onCreate 的区别:
|
方法 |
场景 |
处理方式 |
|---|---|---|
|
|
冷启动 |
只能暂存 pending |
|
|
热启动 |
先尝试直接推送,失败则暂存 |
为什么 onNewWant 可以尝试直接推送:
应用已在后台运行
→ Flutter 引擎已经创建
→ IntentNavigationPlugin 已经注册
→ getInstance() 可能返回实例
→ 可以尝试 navigateToPage()
但仍然需要 fallback 到 pending,因为 Flutter 可能还没完全恢复。
五、onWindowStageCreate——把"显示环境"先收好
onWindowStageCreate(windowStage: window.WindowStage): void {
super.onWindowStageCreate(windowStage)
windowStage.getMainWindow().then((mainWindow: window.Window) => {
mainWindow.setWindowLayoutFullScreen(true)
mainWindow.setWindowSystemBarEnable([])
}).catch((err: Error) => {
console.error(`Failed to enable immersive window: ${JSON.stringify(err)}`)
})
}
这段代码设置了全屏布局和隐藏系统栏。虽然不是插件注册和参数传递本身,但它说明了一件很重要的事:
EntryAbility 不是单纯的"启动回调集合",它也是 Flutter 容器运行环境的第一层配置点。
六、完整的启动链时序图
鸿蒙系统启动应用
│
▼
EntryAbility.onCreate(want)
├─ 读取 pageId, dishId
├─ IntentNavigationPlugin.setPendingNavigation(pageId, dishId)
│
▼
EntryAbility.configureFlutterEngine(flutterEngine)
├─ GeneratedPluginRegistrant.registerWith(flutterEngine)
├─ flutterEngine.getPlugins()?.add(SpeechRecognitionPlugin)
├─ flutterEngine.getPlugins()?.add(TextToSpeechPlugin)
├─ flutterEngine.getPlugins()?.add(IntentNavigationPlugin)
├─ flutterEngine.getPlugins()?.add(AntiPeepProtectionPlugin)
│
▼
EntryAbility.onWindowStageCreate(windowStage)
├─ setWindowLayoutFullScreen(true)
├─ setWindowSystemBarEnable([])
│
▼
Flutter 引擎启动
│
▼
intent_navigation_channel.dart.init(router)
├─ 监听 onIntentNavigation
├─ _consumePending()
│ → 拿到 { pageId, dishId }
│ → _navigate() → 路由跳转
│
▼
用户进入目标页面
七、"谁接、谁转、谁消费"的分工图
EntryAbility(接)
├─ 接住 Want 参数(pageId, dishId)
├─ 注册所有插件
├─ 初始化窗口环境
│
▼
IntentNavigationPlugin(转)
├─ 路由判断:channel 可用 → 推送
├─ 路由判断:channel 不可用 → 暂存 pending
│
▼
intent_navigation_channel.dart(消费)
├─ 监听实时推送
├─ _consumePending() 消费暂存
├─ pageId → Flutter 路由映射
│
▼
GoRouter(跳转)
└─ _router.go('/search') / _router.push('/dish/$dishId')
关键原则:EntryAbility 只接和转,Flutter 路由留给 Flutter 侧消费。
关键代码位置
|
文件 |
作用 |
|---|---|
|
|
鸿蒙启动链核心 |
|
|
pending 缓存 + 推送 |
|
|
Flutter 路由消费 |
常见坑
-
把插件注册逻辑分散到多个地方 — 应该集中在
configureFlutterEngine -
冷启动参数没有先缓存 —
onCreate必须调用setPendingNavigation -
只处理
onCreate,不处理onNewWant— 运行期入口会丢失 -
只把
EntryAbility当成启动页,不把它当成系统入口汇合点 — 它是启动链、插件链、入口链的汇合点 -
在
EntryAbility里直接写死 Flutter 路由字符串 — 路由应该留给 Flutter 侧 -
只看启动成功,不检查插件链和参数链是否真的打通 — 需要验证完整链路
-
onWindowStageCreate没有处理异常 — 窗口初始化失败会导致显示异常
可复用模板
EntryAbility 生命周期模板
export default class EntryAbility extends FlutterAbility {
configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
// 手动注册自定义插件
flutterEngine.getPlugins()?.add(new YourPlugin())
}
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onCreate(want, launchParam)
// 承接冷启动参数
const pageId = want.parameters?.['pageId'] as string;
if (pageId) {
YourPlugin.setPendingNavigation(pageId);
}
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onNewWant(want, launchParam)
// 承接运行期入口
const pageId = want.parameters?.['pageId'] as string;
if (pageId) {
const plugin = YourPlugin.getInstance();
if (plugin) {
plugin.navigateToPage(pageId);
} else {
YourPlugin.setPendingNavigation(pageId);
}
}
}
onWindowStageCreate(windowStage: window.WindowStage): void {
super.onWindowStageCreate(windowStage)
// 初始化窗口环境
windowStage.getMainWindow().then((mainWindow) => {
mainWindow.setWindowLayoutFullScreen(true);
mainWindow.setWindowSystemBarEnable([]);
});
}
}
启动链检查清单
EntryAbility 检查:
□ configureFlutterEngine 是否注册了所有插件?
□ onCreate 是否读取了 want 参数?
□ onCreate 是否调用了 setPendingNavigation?
□ onNewWant 是否处理了运行期入口?
□ onNewWant 是否有 plugin null 的 fallback?
□ onWindowStageCreate 是否初始化了窗口?
□ 所有异常是否都 catch 了?
分工模板
EntryAbility(接 + 转)
├─ 注册插件
├─ 接住 Want 参数
├─ 暂存 pending
└─ 初始化窗口
IntentNavigationPlugin(桥接)
├─ 判断 channel 是否可用
├─ 可用 → 推送
└─ 不可用 → 暂存
Flutter 侧(消费)
├─ init() 监听实时推送
├─ _consumePending() 消费暂存
└─ pageId → 路由跳转
本篇总结
EntryAbility 在鸿蒙 Flutter 项目里是启动链、插件链和入口链的汇合点。它同时承担 4 个职责:
-
配置 Flutter 引擎 —
configureFlutterEngine注册所有插件 -
承接冷启动参数 —
onCreate读取 want 并暂存 pending -
承接运行期入口 —
onNewWant尝试推送或暂存 -
初始化窗口环境 —
onWindowStageCreate设置全屏和状态栏
先把这一个文件看懂,后面的插件注册和系统直达就会清楚很多。对多入口项目来说,它绝不是一个可以忽略的外围文件。
更多推荐


所有评论(0)