第13章 Flutter与原生交互¶
学习目标:掌握Flutter与原生Android/iOS的通信机制,实现平台特定功能。
预计学习时间:5-7天 实践时间:2-3天
目录¶
1. 平台通道概述¶
1.1 通信架构¶
Text Only
Flutter Layer Platform Layer
│ │
│ MethodChannel │
│ EventChannel │
│ BasicMessageChannel │
│◄─────────────────────►│
│ │
Dart Code Android/iOS
1.2 通信方式对比¶
| 方式 | 方向 | 适用场景 |
|---|---|---|
| MethodChannel | 双向 | 方法调用 |
| EventChannel | 原生→Flutter | 事件流 |
| BasicMessageChannel | 双向 | 自定义编解码 |
2. MethodChannel基础通信¶
2.1 Flutter端¶
Dart
import 'package:flutter/services.dart';
class BatteryService {
// 通道名称必须与原生端一致,作为双方通信的唯一标识
static const platform = MethodChannel('samples.flutter.dev/battery');
// Flutter → 原生:调用原生方法获取电量
static Future<String> getBatteryLevel() async {
try {
final int result = await platform.invokeMethod('getBatteryLevel');
return 'Battery level: $result%';
} on PlatformException catch (e) {
// 原生端抛出异常时会被封装为 PlatformException
return 'Failed to get battery level: ${e.message}';
}
}
// 原生 → Flutter:注册原生端主动调用 Flutter 的处理器
static void setupHandler() {
platform.setMethodCallHandler((call) async {
switch (call.method) {
case 'showToast':
final String message = call.arguments;
// 显示Toast
return null;
default:
throw MissingPluginException(); // 未实现的方法抛出此异常
}
});
}
}
2.2 Android端(Kotlin)¶
Kotlin
class MainActivity : FlutterActivity() {
private val CHANNEL = "samples.flutter.dev/battery"
// Flutter 引擎初始化时注册平台通道
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// 创建 MethodChannel 并设置方法调用处理器
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
.setMethodCallHandler { call, result ->
when (call.method) {
"getBatteryLevel" -> {
val batteryLevel = getBatteryLevel()
result.success(batteryLevel) // 返回成功结果给 Flutter
}
else -> result.notImplemented() // 未识别的方法调用
}
}
}
// 通过 Android 系统服务获取电池电量
private fun getBatteryLevel(): Int {
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
}
}
3. EventChannel事件流¶
3.1 传感器数据流示例¶
Dart
// Flutter端:通过 EventChannel 接收原生端持续推送的传感器数据
class SensorService {
static const EventChannel _eventChannel =
EventChannel('samples.flutter.dev/sensor');
// 将原生事件流转换为 Dart Stream,实现响应式数据订阅
static Stream<AccelerometerEvent> get accelerometerEvents {
return _eventChannel.receiveBroadcastStream().map(
(event) => AccelerometerEvent(
x: event[0], // 原生端发送的数组,按 [x, y, z] 排列
y: event[1],
z: event[2],
),
);
}
}
// 使用
StreamBuilder<AccelerometerEvent>(
stream: SensorService.accelerometerEvents,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('X: ${snapshot.data!.x}');
}
return CircularProgressIndicator();
},
)
3.2 Android端¶
Kotlin
class MainActivity : FlutterActivity() {
private val SENSOR_CHANNEL = "samples.flutter.dev/sensor"
private var sensorEventSink: EventChannel.EventSink? = null
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
EventChannel(flutterEngine.dartExecutor.binaryMessenger, SENSOR_CHANNEL)
.setStreamHandler(object : EventChannel.StreamHandler {
// Flutter 端开始监听时触发,启动传感器并保存事件发送器
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
sensorEventSink = events // 通过 EventSink 向 Flutter 推送数据
startSensor()
}
// Flutter 端取消监听时触发,释放资源
override fun onCancel(arguments: Any?) {
sensorEventSink = null
stopSensor()
}
})
}
}
4. BasicMessageCodec自定义编解码¶
Dart
// 自定义消息通道
class CustomMessageChannel {
static const BasicMessageChannel<dynamic> _channel =
BasicMessageChannel(
'samples.flutter.dev/custom',
StandardMessageCodec(),
);
static Future<void> sendCustomData(Map<String, dynamic> data) async {
final response = await _channel.send(data);
print('Response: $response');
}
}
5. FFI外部函数接口¶
5.1 调用C/C++库¶
Dart
import 'dart:ffi';
import 'package:ffi/ffi.dart';
// 加载动态库:Android 加载 .so 文件,iOS 直接使用进程内符号
final DynamicLibrary nativeLib = Platform.isAndroid
? DynamicLibrary.open('libnative.so')
: DynamicLibrary.process();
// 定义C函数签名(需要两套:Native 类型用于 FFI 查找,Dart 类型用于实际调用)
typedef NativeAddFunc = Int32 Function(Int32 a, Int32 b); // C 层签名
typedef DartAddFunc = int Function(int a, int b); // Dart 层签名
// 通过符号名查找 C 函数,并转换为可直接调用的 Dart 函数
final add = nativeLib
.lookup<NativeFunction<NativeAddFunc>>('native_add') // 按符号名查找
.asFunction<DartAddFunc>(); // 转为 Dart 函数
// 使用
void main() {
final result = add(10, 20);
print('Result: $result'); // 30
}
6. 实践练习¶
练习1:电池信息获取¶
任务:实现获取电池电量和充电状态
要求: - MethodChannel通信 - 显示电量百分比 - 显示充电状态
练习2:原生相机调用¶
任务:调用原生相机并返回图片
要求: - 打开原生相机 - 拍摄照片 - 返回图片路径给Flutter
本章小结¶
核心要点¶
- MethodChannel用于双向方法调用
- EventChannel用于原生向Flutter发送事件流
- FFI可直接调用C/C++库,性能更高
- 平台通道是Flutter扩展能力的关键
下一步¶
完成本章学习后,请进入第14章:Android系统服务深度解析。
本章完成时间:预计5-7天