Flutter 跨端原生交互全解析:对接鸿蒙 / Android/iOS 原生能力
Flutter 的跨端能力虽强,但无法完全脱离原生平台 —— 比如调用鸿蒙分布式文件服务、Android 相机、iOS 相册、支付 SDK 等,都需要与原生代码交互。本文将从通信原理、基础交互、高级实战三个维度,用 6000 字 + 完整代码案例,带你掌握 Flutter 与鸿蒙 / Android/iOS 的原生交互全流程,解决 “Flutter 调用原生能力” 的所有痛点。Method Cha
引言
Flutter 的跨端能力虽强,但无法完全脱离原生平台 —— 比如调用鸿蒙分布式文件服务、Android 相机、iOS 相册、支付 SDK 等,都需要与原生代码交互。很多开发者卡在 “Flutter 与原生通信” 环节:不知道选哪种通信方式、数据传输出错、原生视图嵌入 Flutter 卡顿…… 本文将从通信原理、基础交互、高级实战三个维度,用 6000 字 + 完整代码案例,带你掌握 Flutter 与鸿蒙 / Android/iOS 的原生交互全流程,解决 “Flutter 调用原生能力” 的所有痛点。
一、Flutter 与原生交互核心原理
1.1 通信通道类型
Flutter 提供了三种核心通信通道,覆盖所有交互场景:
| 通道类型 | 用途 | 数据流向 | 适用场景 |
|---|---|---|---|
| Method Channel | 方法调用(单次请求 - 响应) | 双向(Flutter↔原生) | 调用原生 API(如获取设备信息、支付) |
| Event Channel | 事件流(原生主动推送数据) | 原生→Flutter | 监听传感器、设备状态、实时数据 |
| Basic Message Channel | 自定义消息(持续双向通信) | 双向(Flutter↔原生) | 复杂数据交互(如 protobuf 传输) |
1.2 数据序列化规则
Flutter 与原生之间的通信数据需遵循序列化规则,支持的基础类型如下:
| Flutter 类型 | Android 类型 | iOS 类型 | 鸿蒙类型 |
|---|---|---|---|
| int | int/long | NSNumber | int/long |
| double | double | NSNumber | double |
| bool | boolean | NSNumber | boolean |
| String | String | NSString | String |
| List | List/ArrayList | NSArray | List |
| Map | Map/HashMap | NSDictionary | Map |
| null | null | nil | null |
注意:复杂类型(如对象)需转换为 Map 传输,再在两端分别解析。
1.3 不同平台交互差异
- Android:基于 JNI/NDK,Flutter 工程下的
android/app/src/main/kotlin目录编写原生代码; - iOS:基于 Objective-C/Swift,Flutter 工程下的
ios/Runner目录编写原生代码; - 鸿蒙(OpenHarmony):基于方舟开发框架,Flutter 工程下的
harmony目录编写原生代码(需 Flutter 鸿蒙适配插件)。
二、基础交互:Method Channel 实战(Flutter↔原生)
Method Channel 是最常用的交互方式,适用于 “Flutter 调用原生方法,原生返回结果” 的场景。
2.1 通用流程(所有平台)
- Flutter 端创建 Method Channel,调用原生方法;
- 原生端注册 Method Channel,监听并处理调用;
- 原生端返回结果给 Flutter 端;
- Flutter 端接收结果并处理。
2.2 实战 1:获取设备信息(Flutter↔Android/iOS/ 鸿蒙)
2.2.1 Flutter 端代码
dart
import 'package:flutter/services.dart';
class DeviceInfoManager {
// 1. 创建Method Channel(名称需与原生端一致)
static const MethodChannel _channel = MethodChannel('com.example/device_info');
// 2. 调用原生方法:获取设备信息
static Future<Map<String, dynamic>?> getDeviceInfo() async {
try {
// 调用原生方法,参数为可选
final result = await _channel.invokeMethod('getDeviceInfo');
return Map<String, dynamic>.from(result);
} on PlatformException catch (e) {
debugPrint("获取设备信息失败:${e.message}");
return null;
}
}
}
// 使用示例
class DeviceInfoPage extends StatelessWidget {
const DeviceInfoPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const AppBar(title: Text("设备信息")),
body: Center(
child: FutureBuilder<Map<String, dynamic>?>(
future: DeviceInfoManager.getDeviceInfo(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError || !snapshot.hasData) {
return const Text("获取设备信息失败");
}
final info = snapshot.data!;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("设备名称:${info['deviceName']}"),
Text("设备类型:${info['deviceType']}"),
Text("系统版本:${info['systemVersion']}"),
Text("设备ID:${info['deviceId']}"),
],
);
},
),
),
);
}
}
2.2.2 Android 端代码(Kotlin)
kotlin
// android/app/src/main/kotlin/com/example/flutter_native_interaction/MainActivity.kt
package com.example.flutter_native_interaction
import android.os.Build
import android.provider.Settings
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity : FlutterActivity() {
// 1. 定义Channel名称(与Flutter端一致)
private val CHANNEL = "com.example/device_info"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// 2. 注册Method Channel
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
// 3. 处理Flutter调用的方法
when (call.method) {
"getDeviceInfo" -> {
// 获取设备信息
val deviceInfo = mapOf(
"deviceName" to android.os.Build.MODEL,
"deviceType" to "Android",
"systemVersion" to Build.VERSION.RELEASE,
"deviceId" to Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
)
// 4. 返回结果给Flutter
result.success(deviceInfo)
}
else -> {
// 方法不存在
result.notImplemented()
}
}
}
}
}
2.2.3 iOS 端代码(Swift)
swift
// ios/Runner/AppDelegate.swift
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
// 1. 注册Method Channel(名称与Flutter端一致)
let deviceChannel = FlutterMethodChannel(name: "com.example/device_info", binaryMessenger: controller.binaryMessenger)
// 2. 处理Flutter调用
deviceChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
if call.method == "getDeviceInfo" {
// 获取设备信息
let deviceName = UIDevice.current.name
let deviceType = "iOS"
let systemVersion = UIDevice.current.systemVersion
let deviceId = UIDevice.current.identifierForVendor?.uuidString ?? ""
// 返回结果
result([
"deviceName": deviceName,
"deviceType": deviceType,
"systemVersion": systemVersion,
"deviceId": deviceId
])
} else {
result(FlutterMethodNotImplemented)
}
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
2.2.4 鸿蒙端代码(ArkTS)
typescript
运行
// harmony/src/main/ets/entryability/EntryAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
import { FlutterHarmonyChannel } from '@ohos/flutter_harmony';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
// 1. 注册Method Channel(名称与Flutter端一致)
FlutterHarmonyChannel.registerMethodChannel('com.example/device_info', (method, params, callback) => {
if (method === 'getDeviceInfo') {
// 获取鸿蒙设备信息
const deviceInfo = {
deviceName: ohos.system.deviceInfo.deviceName,
deviceType: ohos.system.deviceInfo.deviceType,
systemVersion: ohos.system.deviceInfo.sdkVersion,
deviceId: ohos.system.deviceInfo.uuid
};
// 返回结果给Flutter
callback.success(deviceInfo);
} else {
callback.notImplemented();
}
});
}
onWindowStageCreate(windowStage: window.WindowStage) {
super.onWindowStageCreate(windowStage);
windowStage.loadContent('pages/index', (err, data) => {
if (err) {
console.error('Failed to load content. Cause: ' + JSON.stringify(err));
return;
}
});
}
}
2.3 实战 2:原生调用 Flutter 方法(反向调用)
Method Channel 也支持原生主动调用 Flutter 方法,适用于 “原生事件触发 Flutter 更新” 的场景:
2.3.1 Flutter 端代码(注册方法)
dart
class ReverseCallManager {
static const MethodChannel _channel = MethodChannel('com.example/reverse_call');
// 初始化:注册原生可调用的方法
static void init() {
_channel.setMethodCallHandler((call) async {
switch (call.method) {
case "onNativeEvent":
// 处理原生触发的事件
final message = call.arguments as String;
debugPrint("收到原生事件:$message");
// 返回结果给原生
return "Flutter已接收事件:$message";
default:
throw MissingPluginException("方法未实现");
}
});
}
}
// 在main中初始化
void main() {
ReverseCallManager.init();
runApp(const MyApp());
}
2.3.2 Android 端代码(调用 Flutter 方法)
kotlin
// 在需要调用的地方执行
private fun callFlutterMethod() {
val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example/reverse_call")
// 调用Flutter方法
channel.invokeMethod("onNativeEvent", "Android原生触发的事件", object : MethodChannel.Result {
override fun success(result: Any?) {
Log.d("Native", "Flutter返回:$result")
}
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
Log.e("Native", "调用失败:$errorMessage")
}
override fun notImplemented() {
Log.w("Native", "方法未实现")
}
})
}
三、实时通信:Event Channel 实战(原生→Flutter)
Event Channel 适用于 “原生主动向 Flutter 推送实时数据” 的场景,比如监听鸿蒙分布式设备状态、Android 传感器数据、iOS 定位信息等。
3.1 通用流程
- Flutter 端创建 Event Channel,监听原生事件;
- 原生端注册 Event Channel,提供事件流;
- 原生端推送事件到 Flutter 端;
- Flutter 端接收并处理事件。
3.2 实战:监听鸿蒙分布式设备状态
3.2.1 Flutter 端代码
dart
import 'package:flutter/services.dart';
class DeviceStatusManager {
// 1. 创建Event Channel(名称与原生端一致)
static const EventChannel _channel = EventChannel('com.example/device_status');
// 2. 监听设备状态
static Stream<Map<String, dynamic>> listenDeviceStatus() {
return _channel.receiveBroadcastStream().map((event) {
return Map<String, dynamic>.from(event);
});
}
}
// 使用示例
class DeviceStatusPage extends StatefulWidget {
const DeviceStatusPage({super.key});
@override
State<DeviceStatusPage> createState() => _DeviceStatusPageState();
}
class _DeviceStatusPageState extends State<DeviceStatusPage> {
List<Map<String, dynamic>> _deviceList = [];
@override
void initState() {
super.initState();
// 监听设备状态
DeviceStatusManager.listenDeviceStatus().listen((deviceInfo) {
setState(() {
// 更新设备列表
final index = _deviceList.indexWhere((d) => d['deviceId'] == deviceInfo['deviceId']);
if (index >= 0) {
_deviceList[index] = deviceInfo;
} else {
_deviceList.add(deviceInfo);
}
});
}, onError: (error) {
debugPrint("监听设备状态失败:$error");
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const AppBar(title: Text("鸿蒙设备状态")),
body: ListView.builder(
itemCount: _deviceList.length,
itemBuilder: (context, index) {
final device = _deviceList[index];
return ListTile(
title: Text(device['deviceName']),
subtitle: Text("状态:${device['status']}"),
leading: Icon(
device['status'] == 'online' ? Icons.check_circle : Icons.error,
color: device['status'] == 'online' ? Colors.green : Colors.red,
),
);
},
),
);
}
}
3.2.2 鸿蒙端代码(ArkTS)
typescript
运行
// harmony/src/main/ets/entryability/DeviceStatusProvider.ets
import { FlutterHarmonyChannel } from '@ohos/flutter_harmony';
import distributedDevice from '@ohos.distributedDevice';
// 1. 注册Event Channel并提供事件流
export function registerDeviceStatusChannel() {
FlutterHarmonyChannel.registerEventChannel('com.example/device_status', (events) => {
// 监听鸿蒙分布式设备状态
distributedDevice.on('deviceChange', (deviceInfo) => {
// 推送设备状态到Flutter
events.success({
deviceId: deviceInfo.deviceId,
deviceName: deviceInfo.deviceName,
deviceType: deviceInfo.deviceType,
status: deviceInfo.status // online/offline/connected
});
});
// 初始加载设备列表
distributedDevice.getDeviceList().then((list) => {
list.forEach((device) => {
events.success({
deviceId: device.deviceId,
deviceName: device.deviceName,
deviceType: device.deviceType,
status: device.status
});
});
});
// 取消监听的回调
return () => {
distributedDevice.off('deviceChange');
};
});
}
// 在EntryAbility中初始化
import UIAbility from '@ohos.app.ability.UIAbility';
import { registerDeviceStatusChannel } from './DeviceStatusProvider';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
// 注册设备状态Event Channel
registerDeviceStatusChannel();
}
}
四、高级交互:原生视图嵌入 Flutter
有时需要在 Flutter 中嵌入原生视图,比如鸿蒙原生地图、Android 支付控件、iOS 视频播放器等。
4.1 通用流程
- 原生端创建自定义视图(View/UIView/Component);
- Flutter 端使用
AndroidView/UiKitView/HarmonyView嵌入原生视图; - 通过 Method Channel 实现 Flutter 与原生视图的交互。
4.2 实战:Flutter 中嵌入鸿蒙原生地图组件
4.2.1 鸿蒙端创建地图组件(ArkTS)
typescript
运行
// harmony/src/main/ets/pages/MapComponent.ets
@Entry
@Component
struct MapComponent {
@State latitude: number = 39.908823;
@State longitude: number = 116.397470;
build() {
Map({
latitude: this.latitude,
longitude: this.longitude,
zoomLevel: 16
})
.width('100%')
.height('100%')
.onMapClick((lat, lng) => {
// 地图点击事件,通过Method Channel传递给Flutter
FlutterHarmonyChannel.invokeMethod('map_click', {
latitude: lat,
longitude: lng
});
});
}
// 接收Flutter的参数(如修改地图中心点)
setCenter(lat: number, lng: number) {
this.latitude = lat;
this.longitude = lng;
}
}
4.2.2 Flutter 端嵌入鸿蒙地图组件
dart
import 'package:flutter/material.dart';
import 'package:flutter_harmony/flutter_harmony.dart';
class HarmonyMapPage extends StatefulWidget {
const HarmonyMapPage({super.key});
@override
State<HarmonyMapPage> createState() => _HarmonyMapPageState();
}
class _HarmonyMapPageState extends State<HarmonyMapPage> {
late HarmonyViewController _mapController;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const AppBar(title: Text("鸿蒙地图")),
body: Column(
children: [
// 嵌入鸿蒙地图组件
SizedBox(
width: double.infinity,
height: 400,
child: HarmonyView(
viewType: "com.example/map_view",
onPlatformViewCreated: (controller) {
_mapController = controller;
// 初始化地图中心点
_mapController.invokeMethod('setCenter', [39.908823, 116.397470]);
},
// 监听地图点击事件
methodChannel: MethodChannel('com.example/map_view'),
onMethodCall: (call) async {
if (call.method == 'map_click') {
final lat = call.arguments['latitude'];
final lng = call.arguments['longitude'];
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("地图点击:$lat, $lng")),
);
}
},
),
),
// 按钮:修改地图中心点
ElevatedButton(
onPressed: () {
_mapController.invokeMethod('setCenter', [31.230416, 121.473701]);
},
child: const Text("切换到上海"),
),
],
),
);
}
}
五、实战项目:Flutter + 鸿蒙分布式文件选择器
5.1 项目需求
打造一个 Flutter 应用,调用鸿蒙分布式文件服务,实现:
- 扫描鸿蒙分布式设备;
- 选择远程设备的文件;
- 下载文件到本地;
- 实时显示下载进度。
5.2 核心代码实现
5.2.1 Flutter 端代码(整合 Method/Event Channel)
dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// 1. 设备管理
class HarmonyDeviceManager {
static const MethodChannel _deviceChannel = MethodChannel('com.example/harmony_device');
static const EventChannel _fileProgressChannel = EventChannel('com.example/file_progress');
// 扫描分布式设备
static Future<List<Map<String, dynamic>>?> scanDevices() async {
try {
final result = await _deviceChannel.invokeMethod('scanDevices');
return (result as List).map((e) => Map<String, dynamic>.from(e)).toList();
} on PlatformException catch (e) {
debugPrint("扫描设备失败:${e.message}");
return null;
}
}
// 浏览远程设备文件
static Future<List<Map<String, dynamic>>?> browseFiles(String deviceId, String path) async {
try {
final result = await _deviceChannel.invokeMethod('browseFiles', {
'deviceId': deviceId,
'path': path,
});
return (result as List).map((e) => Map<String, dynamic>.from(e)).toList();
} on PlatformException catch (e) {
debugPrint("浏览文件失败:${e.message}");
return null;
}
}
// 下载文件
static Future<String?> downloadFile(String deviceId, String srcPath, String destPath) async {
try {
final taskId = await _deviceChannel.invokeMethod('downloadFile', {
'deviceId': deviceId,
'srcPath': srcPath,
'destPath': destPath,
});
return taskId as String;
} on PlatformException catch (e) {
debugPrint("下载文件失败:${e.message}");
return null;
}
}
// 监听下载进度
static Stream<Map<String, dynamic>> listenDownloadProgress() {
return _fileProgressChannel.receiveBroadcastStream().map((event) {
return Map<String, dynamic>.from(event);
});
}
}
// 2. 文件选择页面
class HarmonyFilePickerPage extends StatefulWidget {
const HarmonyFilePickerPage({super.key});
@override
State<HarmonyFilePickerPage> createState() => _HarmonyFilePickerPageState();
}
class _HarmonyFilePickerPageState extends State<HarmonyFilePickerPage> {
List<Map<String, dynamic>> _devices = [];
List<Map<String, dynamic>> _files = [];
Map<String, dynamic>? _selectedDevice;
String _currentPath = '/';
Map<String, int> _downloadProgress = {};
@override
void initState() {
super.initState();
// 扫描设备
_scanDevices();
// 监听下载进度
HarmonyDeviceManager.listenDownloadProgress().listen((progress) {
setState(() {
_downloadProgress[progress['taskId']] = progress['progress'];
});
});
}
Future<void> _scanDevices() async {
final devices = await HarmonyDeviceManager.scanDevices();
if (devices != null) {
setState(() => _devices = devices);
}
}
Future<void> _browseFiles() async {
if (_selectedDevice == null) return;
final files = await HarmonyDeviceManager.browseFiles(
_selectedDevice!['deviceId'],
_currentPath,
);
if (files != null) {
setState(() => _files = files);
}
}
Future<void> _downloadFile(Map<String, dynamic> file) async {
if (_selectedDevice == null) return;
final destPath = "/sdcard/Download/${file['name']}";
final taskId = await HarmonyDeviceManager.downloadFile(
_selectedDevice!['deviceId'],
file['path'],
destPath,
);
if (taskId != null) {
setState(() => _downloadProgress[taskId] = 0);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("开始下载:${file['name']}")),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const AppBar(title: Text("鸿蒙分布式文件选择器")),
body: Column(
children: [
// 设备选择
Padding(
padding: const EdgeInsets.all(16),
child: DropdownButton<Map<String, dynamic>>(
hint: const Text("选择分布式设备"),
value: _selectedDevice,
items: _devices.map((device) {
return DropdownMenuItem(
value: device,
child: Text(device['deviceName']),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedDevice = value;
_currentPath = '/';
});
_browseFiles();
},
),
),
// 路径导航
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text("当前路径:$_currentPath"),
),
// 文件列表
Expanded(
child: ListView.builder(
itemCount: _files.length,
itemBuilder: (context, index) {
final file = _files[index];
return ListTile(
leading: Icon(file['isDirectory'] ? Icons.folder : Icons.file_copy),
title: Text(file['name']),
subtitle: Text(file['isDirectory'] ? "文件夹" : "大小:${_formatSize(file['size'])}"),
onTap: () {
if (file['isDirectory']) {
setState(() => _currentPath = file['path']);
_browseFiles();
} else {
_downloadFile(file);
}
},
);
},
),
),
// 下载进度
if (_downloadProgress.isNotEmpty)
Column(
children: _downloadProgress.entries.map((entry) {
return LinearProgressIndicator(
value: entry.value / 100,
backgroundColor: Colors.grey[200],
valueColor: const AlwaysStoppedAnimation<Color>(Colors.blue),
);
}).toList(),
),
],
),
);
}
// 格式化文件大小
String _formatSize(int size) {
if (size < 1024) return "$size B";
if (size < 1024 * 1024) return "${(size / 1024).toStringAsFixed(2)} KB";
if (size < 1024 * 1024 * 1024) return "${(size / (1024 * 1024)).toStringAsFixed(2)} MB";
return "${(size / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB";
}
}
// 3. 入口
void main() {
runApp(const MaterialApp(
title: "Flutter鸿蒙原生交互",
home: HarmonyFilePickerPage(),
debugShowCheckedModeBanner: false,
));
}
5.2.2 鸿蒙端核心代码(ArkTS)
typescript
运行
// 分布式文件服务封装
import distributedFile from '@ohos.file.distributed';
import { FlutterHarmonyChannel } from '@ohos/flutter_harmony';
// 注册Method Channel
export function registerFileChannel() {
// 设备扫描
FlutterHarmonyChannel.registerMethodChannel('com.example/harmony_device', (method, params, callback) => {
switch (method) {
case 'scanDevices':
// 扫描分布式设备
distributedFile.scanDevices().then((devices) => {
callback.success(devices);
}).catch((err) => {
callback.error('SCAN_FAILED', err.message, null);
});
break;
case 'browseFiles':
// 浏览文件
const deviceId = params.deviceId;
const path = params.path;
distributedFile.listFiles(deviceId, path).then((files) => {
callback.success(files);
}).catch((err) => {
callback.error('BROWSE_FAILED', err.message, null);
});
break;
case 'downloadFile':
// 下载文件
const taskId = `download_${Date.now()}`;
const srcPath = params.srcPath;
const destPath = params.destPath;
// 监听下载进度
distributedFile.on('transferProgress', taskId, (progress) => {
// 推送进度到Flutter
FlutterHarmonyChannel.emitEvent('com.example/file_progress', {
taskId: taskId,
progress: Math.round((progress.transferred / progress.total) * 100),
});
});
// 执行下载
distributedFile.transferFile({
taskId: taskId,
sourceDeviceId: params.deviceId,
sourcePath: srcPath,
targetPath: destPath,
}).then(() => {
callback.success(taskId);
}).catch((err) => {
callback.error('DOWNLOAD_FAILED', err.message, null);
});
break;
default:
callback.notImplemented();
}
});
// 注册Event Channel(下载进度)
FlutterHarmonyChannel.registerEventChannel('com.example/file_progress', (events) => {
// 保持通道打开,接收进度推送
return () => {};
});
}
六、避坑指南与最佳实践
6.1 常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 通信通道名称不一致 | Flutter 与原生端 Channel 名称不同 | 统一命名规范(如 com. 公司 / 功能) |
| 数据类型转换失败 | 两端数据类型不匹配(如 int→String) | 严格遵循序列化规则,复杂类型转 Map 传输 |
| 原生方法未实现 | Flutter 调用的方法名拼写错误 | 统一方法名常量,避免硬编码 |
| 内存泄漏 | Event Channel 未取消监听 | 在 dispose 中取消 Stream 订阅 |
| 鸿蒙端通信无响应 | 未配置分布式权限 | 在 config.json 中添加分布式权限声明 |
6.2 最佳实践
- 统一通道命名规范:采用 “域名反转 + 功能” 的格式(如 com.example/device_info),避免冲突;
- 错误处理:所有通信都要捕获 PlatformException,给出友好提示;
- 资源释放:Event Channel 的 Stream 订阅需在 dispose 中取消,避免内存泄漏;
- 数据校验:原生端返回数据前校验格式,Flutter 端接收后二次校验;
- 性能优化:避免频繁通信
更多推荐
所有评论(0)