Flutter MethodChannel 在 OpenHarmony 上调用原生能力的实践
本文分享了在OpenHarmony项目中使用Flutter MethodChannel调用原生能力的实践经验。文章介绍了MethodChannel的基本概念和使用场景,详细说明了Flutter端和OpenHarmony原生侧的代码实现,并总结了开发过程中遇到的常见问题及解决方案,包括通道命名不一致、异步操作处理、频繁调用优化、生命周期管理等。建议将原生通信模块化、统一管理通道名称、避免在build
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
Flutter MethodChannel 在 OpenHarmony 上调用原生能力的实践
前言
最近在做 Flutter for OpenHarmony 项目时,开始慢慢遇到一些 Flutter 本身不好直接处理的功能。
比如:
- 获取设备信息
- 调用系统相册
- 读取电池状态
- 获取系统版本
- 调用鸿蒙原生能力
这些功能很多都需要和 OpenHarmony 原生层通信。
Flutter 虽然跨平台能力很强,但真正做业务项目的时候,原生通信其实绕不过去。
这次项目里我主要用的是:
MethodChannel
整体接下来之后,感觉和 Android 原生通信思路比较像,但 OpenHarmony 下还是有一些细节需要注意。
这篇文章主要记录一下我这次在鸿蒙项目里的 MethodChannel 实践过程,以及踩过的一些坑。
一、为什么需要 MethodChannel
Flutter 本身提供了很多组件。
但有些能力:
只能通过原生层获取。
例如:
| 功能 | Flutter 是否直接支持 |
|---|---|
| 系统版本 | 部分支持 |
| 电池信息 | 不完整 |
| 相册权限 | 原生更灵活 |
| 设备唯一标识 | 需要原生 |
| 鸿蒙系统能力 | 必须原生 |
所以最终还是需要:
Flutter ↔ OpenHarmony
进行通信。
二、MethodChannel 基础概念
Flutter 和原生通信:
核心其实就两部分:
| 角色 | 作用 |
|---|---|
| Flutter | 发起调用 |
| 原生层 | 接收并返回结果 |
通信方式:
MethodChannel
三、Flutter 端代码
这里我先拿“获取系统版本”举例。
创建 Channel
static const platform =
MethodChannel(
"com.demo.device/info",
);
调用原生方法
Future<void> getSystemVersion() async {
try {
final String version =
await platform.invokeMethod(
"getSystemVersion",
);
print(version);
} catch (e) {
print(e);
}
}
这里:
invokeMethod()
会主动调用原生层。
四、OpenHarmony 原生侧处理
鸿蒙这边我使用 ArkTS。
注册 MethodChannel
this.methodChannel =
new MethodChannel(
'com.demo.device/info'
)
监听 Flutter 调用
this.methodChannel
.setMethodCallHandler(
(call, result) => {
if (
call.method ===
"getSystemVersion"
) {
result.success("OpenHarmony 5.0");
}
}
)
Flutter 调用后:
原生层返回:
OpenHarmony 5.0
五、我最开始踩到的坑
这个问题我一开始排查了挺久。
问题现象
Flutter 调用:
invokeMethod()
直接报错:
MissingPluginException
原因
大部分情况下:
其实就是:
- channel 名不一致
- method 名写错
- 原生侧没注册成功
例如:
Flutter:
com.demo.device/info
原生:
com.demo.device/test
这种很容易忽略。
后来的习惯
我现在会统一抽常量。
class ChannelName {
static const device =
"com.demo.device/info";
}
避免字符串乱写。
六、参数传递实践
MethodChannel 不只是返回字符串。
还可以传:
- Map
- List
- int
- bool
Flutter 端
final result =
await platform.invokeMethod(
"login",
{
"token": "123456",
"uid": 1001,
},
);
原生接收
let token = call.arguments["token"];
这个用起来其实挺方便。
七、异步操作问题
这里是我后面踩得比较明显的一个问题。
问题
原生层如果:
- 请求网络
- 读取文件
- 调用系统能力
可能是异步。
如果处理不好:
Flutter 会一直等待。
后来的处理方式
原生异步完成后:
主动:
result.success(data)
失败:
result.error(code, msg)
Flutter 侧:
try {
} on PlatformException catch (e) {
}
这样错误处理会清晰很多。
八、页面频繁调用的问题
这个我在设备信息页踩过。
问题现象
页面 build 时:
频繁:
invokeMethod()
导致:
- 页面卡顿
- 原生调用频繁
- 通信开销增加
后来的优化
我改成:
- 页面初始化调用一次
- 数据缓存到 Provider
- 避免 build 里直接调原生
例如:
initState() {
loadDeviceInfo();
}
稳定很多。
九、OpenHarmony 生命周期问题
这个问题在鸿蒙设备上还挺容易碰到。
场景
页面切后台后:
原生能力状态变化。
Flutter 页面恢复:
数据还是旧的。
后来的方案
监听页面生命周期:
WidgetsBindingObserver
恢复前台时:
重新同步原生数据。
AppLifecycleState.resumed
这个在:
- 电池状态
- 网络状态
- 系统信息
场景里挺重要。
十、不要把所有原生逻辑都塞进 Channel
这个是我后面最大的一个感受。
一开始的错误结构
if (method == "xxx") {}
if (method == "xxx2") {}
if (method == "xxx3") {}
后面 method 越来越多。
代码会非常乱。
后来的结构
我把:
- DeviceChannel
- FileChannel
- BatteryChannel
拆开。
每个模块单独管理。
维护轻松很多。
十一、实际效果
优化前:
| 问题 | 表现 |
|---|---|
| Channel 管理 | 混乱 |
| 原生调用 | 高频 |
| 页面卡顿 | 存在 |
| 错误排查 | 困难 |
优化后:
| 项目 | 效果 |
|---|---|
| 原生通信 | 更稳定 |
| 模块结构 | 更清晰 |
| 页面性能 | 更流畅 |
| 错误定位 | 更方便 |
目前这套方案已经在 OpenHarmony 项目里稳定使用了一段时间。
十二、总结
这次做 Flutter MethodChannel 在 OpenHarmony 下的实践,一个比较明显的感受是:
Flutter 真正做业务项目时:
原生通信其实很难避免。
尤其 OpenHarmony 还有很多系统能力:
目前必须通过原生层调用。
我现在项目里的原则基本是:
- Channel 模块化
- 名称统一管理
- 不在 build 中频繁调用
- 生命周期变化时同步状态
- 原生异步结果统一处理
整体稳定性会好很多。
后面我还准备继续研究:
- EventChannel 实时通信
- Flutter Plugin 开发
- OpenHarmony 原生桥接
- Flutter 混合开发方案
希望这篇文章能给正在做 Flutter for OpenHarmony 开发的同学一点参考。
更多推荐

所有评论(0)