鸿蒙 Flutter 多引擎场景开发指导
欢迎大家加入开源鸿蒙跨平台开发者社区:https://openharmonycrossplatform.csdn.net/
在鸿蒙 Flutter 应用中,多引擎指同时存在多个 Flutter 引擎实例,每个引擎可绑定不同的 Dart 入口(entrypoint),实现多页面/多业务隔离、独立生命周期与路由。适用于多 Tab、多业务模块、或需与原生页面混合导航的复杂场景。
本文介绍从创建工程、Flutter 端路由配置到 ArkTS 端多引擎创建与集成的完整流程。
一、前置条件
- 已完成 Flutter OH 环境搭建
- 已安装 DevEco Studio
- 了解 Flutter 基本路由与 ArkTS 页面跳转
二、创建 Flutter 应用
在目标目录执行:
bash
flutter create demo
cd demo
确保工程已包含 ohos 平台(若无则执行 flutter create --platforms ohos .)。
三、Flutter 端:多页面与路由配置
1. 创建多个 Dart 页面与入口
为每个「引擎」准备独立页面及可选独立入口(entrypoint)。例如:
lib/main.dart:主入口,定义路由表lib/page1/main.dart:页面 1 的入口(可选独立 entrypoint)lib/page2/main.dart:页面 2 的入口(可选独立 entrypoint)
每个子页面可为独立 runApp(...) 的 mini-app,或在主入口中通过路由统一管理。
2. 在 lib/main.dart 中定义路由
主入口中注册多页面路由,供 ArkTS 通过 pushRoute 跳转:
dart
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '多引擎集成',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/',
routes: <String, WidgetBuilder>{
'/': (context) => HomePage(),
'/page1': (context) => const page1.MyApp(),
'/page2': (context) => const page2.MyApp(),
},
);
}
}
路由名(如 /page1、/page2)需与 ArkTS 端 FlutterEngineCache 的 key 及 pushRoute 参数一致。
四、ArkTS 端:多引擎创建与缓存
1. 使用 FlutterEngineGroup + FlutterEngineCache
在 ArkTS 中创建 FlutterEngineGroup ,为每个业务入口创建独立 FlutterEngine ,并用 FlutterEngineCache 按 key 缓存,便于后续页面按 key 取用。
示例:entry/src/main/ets/pages/Index.ets
typescript
import { router } from '@kit.ArkUI';
import common from '@ohos.app.ability.common';
import { FlutterEngineCache, FlutterEngineGroup } from '@ohos/flutter_ohos';
let storage = LocalStorage.getShared();
const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS';
@Entry(storage)
@Component
struct Index {
private context = getContext(this) as common.UIAbilityContext;
private flutterEngineGroup?: FlutterEngineGroup;
@LocalStorageLink('viewId') viewId: string = "";
async aboutToAppear(): Promise<void> {
await this.createAndCacheEngine();
}
private async createAndCacheEngine(): Promise<void> {
this.flutterEngineGroup = new FlutterEngineGroup();
interface EngineConfig {
key: string;
entrypoint: string;
}
const engineConfigs: EngineConfig[] = [
{ key: "/page1", entrypoint: "lib/page1/main.dart" },
{ key: "/page2", entrypoint: "lib/page2/main.dart" },
];
for (const config of engineConfigs) {
if (!FlutterEngineCache.getInstance().contains(config.key)) {
try {
let flutterEngine = await this.flutterEngineGroup!.createEngine(
getContext(this) as common.UIAbilityContext,
{ entrypoint: config.entrypoint }
);
await flutterEngine.init(getContext(this), null, false);
FlutterEngineCache.getInstance().put(config.key, flutterEngine);
} catch (error) {
console.error(`create engine failed: ${config.key}`, error);
}
}
}
}
build() {
Stack() {
Column() {
Button('跳转Page1')
.onClick(() => {
try {
FlutterEngineCache.getInstance().get('/page1')?.getNavigationChannel()?.pushRoute('/page1');
router.pushUrl({ url: 'pages/Flutter', params: { route: '/page1' } });
} catch (err) {
console.error('push page1 failed', err);
}
});
Button('跳转Page2')
.onClick(() => {
try {
FlutterEngineCache.getInstance().get('/page2')?.getNavigationChannel()?.pushRoute('/page2');
router.pushUrl({ url: 'pages/Flutter', params: { route: '/page2' } });
} catch (err) {
console.error('push page2 failed', err);
}
});
}
}
.width('100%')
.height('100%')
.align(Alignment.Center);
}
onBackPress(): boolean {
this.context.eventHub.emit(EVENT_BACK_PRESS);
return true;
}
}
要点:
- key :与 Flutter 路由名一致(如
/page1),用于缓存与取回引擎。 - entrypoint :对应 Dart 入口(如
lib/page1/main.dart),若使用单入口多路由则可与主入口一致,仅 key 区分。 - createEngine :若当前 SDK 支持传入
entrypoint,可传{ entrypoint: config.entrypoint };若不支持则传null,引擎使用默认入口,仅通过后续pushRoute区分页面。
2. 新建 Flutter 容器页并挂载缓存引擎
在 entry/src/main/ets/pages 下新建 Flutter.ets ,作为承载 Flutter 页面的容器:从路由参数中读取 route,用其作为 cached_engine_id 从缓存中取引擎并挂载到 FlutterView。
entry/src/main/ets/pages/Flutter.ets 示例:
typescript
import router from '@ohos.router';
import { FlutterPage } from '@ohos/flutter_ohos';
import { FlutterView } from '@ohos/flutter_ohos/src/main/ets/view/FlutterView';
import FlutterEntry from '@ohos/flutter_ohos/src/main/ets/embedding/ohos/FlutterEntry';
import MyFlutterEntry from '../entryability/MyFlutterEntry';
@Entry
@Component
struct FlutterPageContainer {
private flutterEntry: FlutterEntry | null = null;
private flutterView: FlutterView | undefined = undefined;
aboutToAppear(): void {
const context = getContext(this) as common.UIAbilityContext;
const params = router.getParams() as Record<string, Object>;
params["should_attach_engine_to_ability"] = true;
const routeName = params["route"] as string;
params["cached_engine_id"] = routeName;
this.flutterEntry = new MyFlutterEntry(context, params);
this.flutterEntry!.aboutToAppear();
this.flutterView = this.flutterEntry!.getFlutterView();
}
aboutToDisappear(): void {
this.flutterEntry?.aboutToDisappear();
}
onPageShow(): void {
this.flutterEntry?.onPageShow();
}
onPageHide(): void {
this.flutterEntry?.onPageHide();
}
build() {
Stack() {
if (this.flutterView) {
FlutterPage({ viewId: this.flutterView.getId() });
}
}
}
onBackPress(): boolean {
return this.flutterEntry?.onBackPress() ?? false;
}
}
说明:
- route :由 Index 页
router.pushUrl({ url: 'pages/Flutter', params: { route: '/page1' } })传入,与引擎 key 一致。 - cached_engine_id :设为同一
route,使 FlutterEntry 从FlutterEngineCache中取出对应引擎并挂载。 - MyFlutterEntry:需在工程中实现,用于根据 params 创建/获取 Flutter 容器并绑定缓存引擎;若无现成实现,可参考官方示例或 SDK 中的 FlutterEntry 用法。
五、流程小结与注意点
| 步骤 | 位置 | 要点 |
|---|---|---|
| 1 | Flutter | 多页面 + 路由名(如 /page1、/page2)与 ArkTS 端 key 一致 |
| 2 | ArkTS Index | FlutterEngineGroup 创建多引擎,按 key + entrypoint 配置并放入 FlutterEngineCache |
| 3 | ArkTS Index | 跳转前对对应 key 的引擎 getNavigationChannel()?.pushRoute(route),再 router.pushUrl 到 Flutter.ets 并传 params: { route } |
| 4 | ArkTS Flutter.ets | 用 params.route 作为 cached_engine_id,从缓存挂载引擎并展示 FlutterPage |
注意:
- 引擎数量与内存占用正相关,按业务需要创建,避免过多引擎常驻。
- 若 SDK 的
createEngine支持传入entrypoint,建议显式传入,与 Flutter 侧入口一致。 - 路由名、Cache key、
cached_engine_id、pushRoute参数需保持一致,否则会取错引擎或无法显示正确页面。 - 官方示例或 SDK 升级可能导致 API 略有差异(如
createEngine参数、FlutterEntry 构造),请以当前使用的 Flutter OH 版本文档为准。
六、参考
以上示例展示了多引擎从 Flutter 路由到 ArkTS 创建、缓存与页面挂载的完整实现方式,可按项目需要增删引擎与路由。