Flutter Boost在做混合开发非常实用,但官方文档的不清晰。本文将基于实战经验,帮助大家避开那些常见的坑,快速上手并高效开发。
前言:为何要写这篇手册
在开发过程中,我发现官方文档对于Flutter Boost的集成描述不够清晰,按照官方文档操作会遇到诸多问题。因此,我决定结合自己的实战经验,为大家提供一份详细且实用的集成手册,希望能帮助大家少走弯路。
一、集成问题:从源码到har包的抉择
在开发初期,我尝试通过集成源码来实现热更新等功能,但无论怎么操作,热更新始终无法实现。经过多次尝试和排查,最终只能选择以集成har包的形式进行开发。虽然这种方式不能调试,但运行效果还可以。
如何集成框架
假设你的Flutter模块名为abc_flutter
,以下是详细的集成步骤和代码示例:
- 修改
ohos_app/oh-package.json5
在ohos_app/oh-package.json5
文件中,添加以下内容:
json
{
"modelVersion": "5.0.4",
"description": "Please describe the basic information.",
"dependencies": {
"@ohos/flutter_module": "file:abc_flutter/.ohos/flutter_module",
"@ohos/flutter_ohos": "file:abc_flutter/.ohos/har/flutter.har",
"flutter_boost": "file:abc_flutter/.ohos/har/flutter_boost.har",
},
"overrides": {
"@ohos/flutter_ohos": "file:abc_flutter/.ohos/har/flutter.har",
"flutter_boost": "file:abc_flutter/.ohos/har/flutter_boost.har",
},
"devDependencies": {
"@ohos/hypium": "1.0.21",
"@ohos/hamock": "1.0.0"
}
}
注意事项
- 第三方库配置:一些flutter的第三方库也需要在这里配置,否则可能会出现编译错误。例如,
path_provider_ohos
需要添加如下配置:
json
"path_provider_ohos": "file:abc_flutter/.ohos/har/path_provider_ohos.har"
- 错误示例:如果未正确配置,可能会遇到以下错误:
javascript
1 ERROR: 00309001 ArkTS Compiler Error
Error Message: Cannot import files outside of the current module using relative paths. Import statement: './src/main/ets/io/flutter/plugins/pathprovider/PathProviderPlugin'. At file: /Users/**/.pub-cache/git/flutter_packages-35fb467533e174411a117b2a030c15d2a3a9687c/packages/path_provider/path_provider_ohos/ohos/index.ets
- 修改
ohos_app/build-profile.json5
在ohos_app/build-profile.json5
文件的modules
部分添加以下内容:
json
{
"name": "flutter_module",
"srcPath": "./szxd_flutter/.ohos/flutter_module"
}
- 执行命令
执行以下命令来构建har包:
bash
fvm flutter build har --debug
二、代码集成:Flutter与UIAbility的深度绑定
在HarmonyOS中,Flutter界面由FlutterPage
承载,而整个应用只有一个UIAbility
。我们需要在UIAbility
的生命周期中绑定Flutter,并初始化Flutter Boost。
- Flutter与UIAbility绑定
在UIAbility
的onCreate
、onDestroy
、onWindowStageCreate
和onWindowStageDestroy
生命周期函数中绑定Flutter。以下是代码示例:
typescript
export default class EntryAbility extends UIAbility implements FlutterBoostDelegate {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
FlutterManager.getInstance().pushUIAbility(this);
}
onWindowStageCreate(windowStage: window.WindowStage): void {
FlutterManager.getInstance().pushWindowStage(this, windowStage);
}
onDestroy(): void {
FlutterManager.getInstance().popUIAbility(this);
}
onWindowStageDestroy(): void {
FlutterManager.getInstance().popWindowStage(this);
}
}
- 初始化Flutter Boost
在onWindowStageCreate
中初始化Flutter Boost,并注册插件。以下是代码示例:
typescript
export default class EntryAbility extends UIAbility implements FlutterBoostDelegate {
pushNativeRoute(options: FlutterBoostRouteOptions,
onPageResult?: ((pageName: string, result: Record<string, Object>) => void) | undefined): void {
throw new Error('Method not implemented.');
}
pushFlutterRoute(options: FlutterBoostRouteOptions,
onPageResult?: ((pageName: string, result: Record<string, Object>) => void) | undefined): void {
router.pushUrl({
url: 'pages/AppFlutterPage', params: {
uri: options.getPageName(),
params: JSONUtil.toString(options.getArguments()),
}
}).then(() => {
console.info('Succeeded in jumping to the second page.')
})
}
popRoute(options: FlutterBoostRouteOptions): boolean {
const pageName = options.getPageName();
const value = options.getArguments();
entryLogger.debug(`Pop route called for page: ${pageName}`);
FlutterBoost.getInstance().sendEventToFlutter(pageName, value);
return false;
}
onWindowStageCreate(windowStage: window.WindowStage): void {
FlutterManager.getInstance().pushWindowStage(this, windowStage);
const optionsBuilder: FlutterBoostSetupOptionsBuilder = new FlutterBoostSetupOptionsBuilder();
FlutterBoost.getInstance().setup(this, this.context, (engine) => {
GeneratedPluginRegistrant.registerWith(engine);
}, optionsBuilder.build()).then(() => {
// 鸿蒙初始化
});
}
}
注意事项(敲黑板)
- pushFlutterRoute与popRoute的处理
- pushFlutterRoute:在跳转Flutter页面时,Flutter页面上传的序列化数据可能会丢失。因此,需要在鸿蒙原生中进行数据序列化处理。例如:
typescript
router.pushUrl({
url: 'pages/AppFlutterPage', params: {
uri: options.getPageName(),
params: JSONUtil.toString(options.getArguments()),
}
}).then(() => {
console.info('Succeeded in jumping to the second page.')
});
- popRoute:在Flutter页面执行
pop
后,无法像Flutter原生那样直接获取数据。需要通过sendEventToFlutter
方法发送事件,让Flutter页面感知数据。例如:
typescript
FlutterBoost.getInstance().sendEventToFlutter(pageName, value);
- 自定义FlutterPage
创建一个FlutterPage
,并添加FlutterBoostEntry
和FlutterView
的代码。以下是代码示例:
typescript
@Entry
@Component
struct AppFlutterPage {
private flutterEntry?: FlutterBoostEntry;
private flutterView?: FlutterView;
aboutToAppear() {
let option = router.getParams() as RouterOptions;
let params = option.params;
this.flutterEntry = new FlutterBoostEntry(getContext(this), {
uri: option.uri,
params: JSON.parse(params as string)
});
this.flutterEntry?.aboutToAppear();
this.flutterView = this.flutterEntry?.getFlutterView();
}
aboutToDisappear() {
this.flutterEntry?.aboutToDisappear();
}
onPageShow() {
this.flutterEntry?.onPageShow();
}
onPageHide() {
this.flutterEntry?.onPageHide();
}
onBackPress(): boolean | void {
FlutterBoost.getInstance()
.getPlugin()?.onBackPressed();
return true;
}
build() {
Column() {
FlutterPage({ viewId: this.flutterView?.getId() })
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
}
}
注意事项:这里要这么配置,可以保证数据不会丢失 this.flutterEntry = new FlutterBoostEntry(getContext(this), { uri: option.uri, params: JSON.parse(params as string) });
- 跳转Flutter界面
在需要跳转Flutter界面时,直接使用router
跳转到AppFlutterPage
即可。例如:
typescript
router.pushUrl({
url: 'pages/AppFlutterPage', params: {
uri: '这里写dart侧注册好的路由名',
params: '传递给界面的参数',
}
}).then(() => {
console.info('Succeeded in jumping to the second page.')
});
结语:实战经验的总结
通过上述步骤,可以成功集成Flutter Boost到HarmonyOS项目中。虽然过程中可能会遇到一些坑,但只要按照本文的指南操作,就能顺利解决。希望这篇文章能够帮助大家更好地使用Flutter Boost,提升开发效率