Flutter 调用鸿蒙原生组件:MethodChannel 与 PlatformView 的选择和落地
·
Flutter 调用鸿蒙原生组件:MethodChannel 与 PlatformView 的选择和落地
Flutter 鸿蒙项目里,“调用原生组件”这个说法很容易混淆。有人只是想调一个鸿蒙方法,有人是想把 ArkTS 写好的 Swiper 放进 Flutter 页面,还有人既要显示原生 UI,又要把点击事件传回 Flutter。不同需求对应不同方案,选错方案会让代码越来越难维护。

本文把原稿里的 MethodChannel 和 PlatformView 两条链路拆开讲:简单数据交互用 MethodChannel,原生 UI 嵌入用 PlatformView,原生 UI 事件回传可以在 PlatformView 基础上再配合 MethodChannel。


1. 先按需求选择方案
| 需求 | 推荐方式 | 典型例子 |
|---|---|---|
| Flutter 调原生方法 | MethodChannel | 获取设备信息、调用原生计算 |
| Flutter 嵌入原生 UI | PlatformView | 嵌入 ArkTS Swiper、地图、播放器 |
| 原生 UI 通知 Flutter | PlatformView + MethodChannel | Swiper 点击回传 itemId |
| 高频数据流 | EventChannel 或自定义协议 | 定位、传感器、进度流 |
不要把所有事情都塞进一个 NativePlugin。方法调用和视图嵌入最好分文件管理。
2. 推荐目录结构
project/
lib/
pages/
NativeDemo/
index.dart
bridge/
native_bridge.dart
ohos/
entry/
src/
main/
ets/
plugins/
NativeMethodPlugin.ets
views/
NativeSwiperView.ets
entryability/
EntryAbility.ets
代码解释:
native_bridge.dart封装 Flutter 侧通道。NativeMethodPlugin.ets处理方法调用。NativeSwiperView.ets处理原生 UI。EntryAbility.ets只负责注册。
3. MethodChannel 适合简单交互
Flutter 侧封装方法调用:
import 'package:flutter/services.dart';
class NativeBridge {
static const MethodChannel _channel =
MethodChannel('com.example.native/component');
Future<String> getNativeTitle() async {
final title = await _channel.invokeMethod<String>('getTitle');
return title ?? '鸿蒙原生组件';
}
}
代码解释:
- 通道名要稳定,并和 ArkTS 端一致。
- 方法名
getTitle要在原生端分发。 - 返回值允许为空时要给兜底文案。
鸿蒙端处理方法:
import { FlutterPlugin, FlutterPluginBinding } from '@ohos/flutter_ohos';
import { MethodCall, MethodCallHandler, MethodChannel, MethodResult } from '@ohos/flutter_ohos';
export class NativeMethodPlugin implements FlutterPlugin, MethodCallHandler {
private channel?: MethodChannel;
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel = new MethodChannel(binding.getBinaryMessenger(), 'com.example.native/component');
this.channel.setMethodCallHandler(this);
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
this.channel?.setMethodCallHandler(null);
this.channel = undefined;
}
onMethodCall(call: MethodCall, result: MethodResult): void {
if (call.method === 'getTitle') {
result.success('来自鸿蒙原生的标题');
return;
}
result.notImplemented();
}
}
代码解释:
result.success返回给 Flutter。- 未识别的方法要调用
notImplemented,不要静默失败。 - 插件解绑时清理 handler。
4. PlatformView 适合嵌入原生 UI
如果要在 Flutter 页面里显示鸿蒙原生 Swiper,就使用 PlatformView。
@Component
struct NativeBannerComponent {
build() {
Swiper() {
Text('鸿蒙原生 Banner 1').fontSize(24).fontColor(Color.White)
Text('鸿蒙原生 Banner 2').fontSize(24).fontColor(Color.White)
Text('鸿蒙原生 Banner 3').fontSize(24).fontColor(Color.White)
}
.autoPlay(true)
.interval(3000)
.indicator(true)
.width('100%')
.height('100%')
}
}
代码解释:
- ArkTS 组件负责真实 UI。
- 根节点要有明确宽高。
- 复杂业务数据建议先定义 interface,再进入组件渲染。
PlatformView 包装:
import { PlatformView, PlatformViewFactory, StandardMessageCodec } from '@ohos/flutter_ohos';
@Builder
function NativeBannerBuilder(params: ESObject) {
NativeBannerComponent();
}
class NativeBannerPlatformView extends PlatformView {
getView(): WrappedBuilder<[ESObject]> {
return new WrappedBuilder(NativeBannerBuilder);
}
dispose(): void {}
}
export class NativeBannerFactory extends PlatformViewFactory {
constructor() {
super(StandardMessageCodec.INSTANCE);
}
create(context: Context, viewId: number, args: Object): PlatformView {
return new NativeBannerPlatformView();
}
}
代码解释:
NativeBannerBuilder把 ArkTS 组件交给 PlatformView。NativeBannerFactory由 FlutterEngine 注册。args可接收 Flutter 传入的初始化参数。
5. 统一在 EntryAbility 注册
注册逻辑集中在入口,便于排查。
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
import { NativeMethodPlugin } from '../plugins/NativeMethodPlugin';
import { NativeBannerFactory } from '../views/NativeBannerView';
export default class EntryAbility extends FlutterAbility {
configureFlutterEngine(flutterEngine: FlutterEngine): void {
super.configureFlutterEngine(flutterEngine);
GeneratedPluginRegistrant.registerWith(flutterEngine);
const methodPlugin = new NativeMethodPlugin();
methodPlugin.onAttachedToEngine(flutterEngine.getPluginBinding());
flutterEngine
.getPlatformViewRegistry()
.registerViewFactory('native-banner-view', new NativeBannerFactory());
}
}
代码解释:
- 自动生成插件注册保留在前面。
- MethodChannel 插件和 PlatformView 注册可以共存。
- 不同模板的 binding 获取方式可能不同,按当前工程生成 API 调整。
- 修改后要完整重启应用。
6. Flutter 页面同时使用方法和原生视图
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_ohos/flutter_ohos.dart';
import '../../bridge/native_bridge.dart';
class NativeDemoPage extends StatefulWidget {
const NativeDemoPage({super.key});
State<NativeDemoPage> createState() => _NativeDemoPageState();
}
class _NativeDemoPageState extends State<NativeDemoPage> {
final NativeBridge _bridge = NativeBridge();
String _title = '等待原生返回';
Future<void> _loadTitle() async {
try {
final title = await _bridge.getNativeTitle();
setState(() => _title = title);
} on PlatformException catch (e) {
setState(() => _title = e.message ?? '原生调用失败');
}
}
void initState() {
super.initState();
_loadTitle();
}
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(_title),
),
const SizedBox(
height: 220,
child: OhosView(
viewType: 'native-banner-view',
creationParams: {'page': 'native-demo'},
creationParamsCodec: StandardMessageCodec(),
),
),
],
);
}
}
代码解释:
- 顶部标题来自 MethodChannel。
- 下方 Banner 来自 PlatformView。
OhosView必须给出明确高度。viewType必须和鸿蒙端注册名一致。
7. 构建和验证
flutter clean
flutter pub get
flutter build hap --debug
flutter run
代码解释:
- 原生代码变更后需要重新构建。
- 先确认 HAP 能构建,再看运行效果。
- 如果只有 Flutter UI 改动,可以热重载;如果改了注册、ArkTS 组件、插件,建议完整重启。
8. 排查表
| 问题 | 排查方向 | 修复建议 |
|---|---|---|
| MethodChannel 无响应 | 通道名、注册、方法名 | 对齐三处名称并重启 |
| OhosView 空白 | 尺寸、viewType、注册 | 给高度,检查注册名 |
| ArkTS 编译失败 | 类型声明不完整 | 补 interface,避免隐式对象 |
| 参数没传到原生 | codec 或字段名 | 对齐 creationParams 和 args |
| 热重载不生效 | 改了原生层 | 停止应用后重新运行 |
9. 总结
Flutter 调用鸿蒙原生组件时,先选对桥:数据交互用 MethodChannel,原生 UI 嵌入用 PlatformView,事件回传再组合通道。工程上把 Flutter 页面、Dart bridge、ArkTS plugin、ArkTS view 和 EntryAbility 注册分开,后续调试会更清晰,也更适合扩展真实业务组件。
更多推荐



所有评论(0)