Flutter 以模块化方案 适配 HarmonyOS 的实现方法
Flutter的SDK: https://gitcode.com/openharmony-tpc/flutter_flutter
分支Tag:3.27.5-ohos-0.1.0-beta
DevecoStudio:DevEco Studio 5.1.1 Release
HarmonyOS版本:API18
本文使用的Mac,环境配置步骤不再赘述,参考社区文档!!!
Flutter 应用可以通过与 HarmonyOS 原生代码交互来适配 HarmonyOS 平台。主要涉及 Flutter 端的插件开发和 HarmonyOS 端的原生能力实现。
Flutter 侧代码实现
在 Flutter 中,通过 MethodChannel
与 HarmonyOS 原生代码通信。以下是一个示例:
main.dart
dart
void main() => runApp(GetMaterialApp(
// home: const HomePage(),
title: "Flutter侧",
getPages: [
GetPage(name: "/home", page: () => const HomePage()),
GetPage(name: "/first", page: () => const FirstPage()), //空页面
],
));
home_page.dart
dart
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() {
return _HomePageState();
}
}
class _HomePageState extends State<HomePage> {
String deviceTypeName = "";
String receiveData = "xxxxxx";
@override
void initState() {
super.initState();
Get.parameters.forEach((key, value) {
if (key == "receiveData") {
setState(() {
receiveData = value!;
});
}
});
}
@override
Widget build(BuildContext context) {
deviceTypeName = Platform.operatingSystem;
return Scaffold(
appBar: AppBar(
title: const Text(
'适配Android/iOS/HarmonyOS',
style: TextStyle(fontSize: 20),
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
deviceTypeName,
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
const SizedBox(
width: double.infinity,
height: 20,
),
Text('接收来自原生的数据:$receiveData'),
const SizedBox(
width: double.infinity,
height: 20,
),
GestureDetector(
onTap: () {
ToastUtil.showToastCenter("Send Native");
NativeChannel.sendData();
},
child: Container(
width: 120,
height: 40,
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color(0xff08b326),
borderRadius: BorderRadius.circular(10)),
child: const Text(
"Send Native",
style: TextStyle(color: Colors.white),
),
),
),
GestureDetector(
onTap: () {
ToastUtil.showToastCenter("Finish Page");
NativeChannel.finishPage();
},
child: Container(
width: 120,
height: 40,
margin: const EdgeInsets.only(top: 10),
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color(0xff08b326),
borderRadius: BorderRadius.circular(10)),
child: const Text(
"Finish Page",
style: TextStyle(color: Colors.white),
),
),
)
],
),
);
}
}
native_channel.dart
dart
class NativeChannel {
//创建通道
static const _channel = MethodChannel('com.flutter/native_channel');
///调用原生方法,关闭原生页面
static Future<void> finishPage() async {
await _channel.invokeMethod('finishPage');
}
///调用原生方法,发送flutter数据
static Future<void> sendData() async {
await _channel.invokeMethod('sendData', {'data': '我是FLutter传到原生客户端的数据'});
}
}
HarmonyOS 侧代码实现
在 HarmonyOS 中,需要实现 Ability
来处理 Flutter 的调用。
- 创建项目默认创建
EntryAbility
类
在EntryAbility
类中初始化Flutter管理部分:
java
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
FlutterManager.getInstance().pushUIAbility(this)
}
onDestroy(): void {
FlutterManager.getInstance().popUIAbility(this)
}
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
FlutterManager.getInstance().pushWindowStage(this, windowStage);
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
return;
}
hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口
// 1. 设置窗口全屏
windowClass.setWindowLayoutFullScreen(true)
// 2. 设置状态栏和导航条隐藏
windowClass.setSpecificSystemBarEnabled('status', true)
let sysBarProps: window.SystemBarProperties = {
statusBarContentColor: '#000000' //全局设置状态栏文字颜色
};
windowClass.setWindowSystemBarProperties(sysBarProps);
});
}
onWindowStageDestroy(): void {
FlutterManager.getInstance().popWindowStage(this);
}
onForeground(): void {
}
onBackground(): void {
}
}
- 实现FlutterPage页面 负责承载FLutter模块的Harmony页面
java
@Entry
@Component
struct FlutterViewPage {
private flutterEntry?: FlutterEntry | null = null;
private flutterView?: FlutterView;
aboutToAppear() {
//跳转至指定路由 ?后面为参数
let params: Record<string, Object> = {
"route": "/home?receiveData=HarmonyOS已经诞生5年了"
}
this.flutterEntry = new FlutterHomeAbility(getContext(this) as common.UIAbilityContext, params);
this.flutterEntry.aboutToAppear();
this.flutterView = this.flutterEntry.getFlutterView();
this.flutterEntry.addPlugin(new HomePlugin(this.getUIContext()));
}
aboutToDisappear() {
this.flutterEntry?.aboutToDisappear();
}
onPageShow() {
this.flutterEntry?.onPageShow();
}
onPageHide() {
this.flutterEntry?.onPageHide();
}
build() {
RelativeContainer() {
FlutterPage({ viewId: this.flutterView?.getId() })
.width('100%')
.height('100%')
}
}
}
class HomePlugin implements FlutterPlugin {
private channel?: MethodChannel; //交互通道
private cxt?: UIContext
constructor(context: UIContext) {
this.cxt = context
}
getUniqueClassName(): string {
return HomePlugin.name;
}
//交互过程
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel = new MethodChannel(binding.getBinaryMessenger(), "com.flutter/native_channel");
let context = this.cxt
this.channel.setMethodCallHandler({
onMethodCall(call: MethodCall, result: MethodResult) {
switch (call.method) {
case "finishPage":
ToastUtil.showToast("页面关闭");
context?.getRouter().back()
break;
case "sendData":
ToastUtil.showToast("发送flutter数据:" + call.argument("data"));
break;
default:
result.notImplemented();
break;
}
}
})
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
this.channel?.setMethodCallHandler(null)
}
}
- 实现Flutter引擎
java
export default class FlutterHomeAbility extends FlutterEntry {
configureFlutterEngine(flutterEngine: FlutterEngine): void {
super.configureFlutterEngine(flutterEngine);
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}
交互过程
-
Flutter 调用 HarmonyOS 方法
- Flutter 通过
MethodChannel
调用finishPage
方法。 - HarmonyOS 收到请求后处理信息。
- Flutter 通过
-
Flutter 向 HarmonyOS 传递参数
- Flutter 调用
sendData
方法并传递data
参数。 - HarmonyOS 解析参数并显示 Toast。
- Flutter 调用
-
通信流程
- Flutter 发送方法名和参数到 HarmonyOS。
- HarmonyOS 根据方法名执行对应逻辑并返回结果。
注意事项
- 插件打包
将 Flutter 代码打包为 Harmony可用的 har 插件,方便调用。
Flutter打包 har 命令:
java
flutter build har --release
//构建结果在 项目根目录/build/ohos/har/release
-
性能优化
频繁通信建议使用
EventChannel
替代MethodChannel
以减少开销。 -
HarmonyOS侧导入har
1、项目根目录下
oh-package.json5
文件
java
{
"modelVersion": "5.1.1",
"description": "Please describe the basic information.",
"dependencies": {
},
"overrides": {//导入har包
"@ohos/flutter_ohos": "file:../../FlutterProject/mobile_flutter_ohos/build/ohos/har/release/flutter_embedding_release.har",
"flutter_native_arm64_v8a": "file:../../FlutterProject/mobile_flutter_ohos/build/ohos/har/release/arm64_v8a_release.har",
"@ohos/flutter_module": "file:../../FlutterProject/mobile_flutter_ohos/build/ohos/har/release/flutter_module.har"
},
"devDependencies": {
"@ohos/hypium": "1.0.21",
"@ohos/hamock": "1.0.0"
}
}
2、模块entry
根目录下oh-package.json5
文件
java
{
"name": "entry",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "",
"author": "",
"license": "",
"dependencies": {//新增
"@ohos/flutter_ohos": "file:../../../FlutterProject/mobile_flutter_ohos/build/ohos/har/release/flutter_embedding_release.har",
"flutter_native_arm64_v8a": "file:../../../FlutterProject/mobile_flutter_ohos/build/ohos/har/release/arm64_v8a_release.har",
"@ohos/flutter_module": "file:../../../FlutterProject/mobile_flutter_ohos/build/ohos/har/release/flutter_module.har"
}
}
通过以上方法,Flutter 应用可以无缝适配 HarmonyOS,并调用原生功能。