Flutter 的平台通信架构
Flutter 使用平台通道 (Platform Channels) 作为 Dart 与原生代码之间的桥梁。通信通过序列化/反序列化过程进行。
类型转换的工作原理
1. 序列化过程
当你将 Dart 字符串发送到原生代码时:
dart
// Dart 端
const platform = MethodChannel('my_plugin');
String dartString = "Hello from Dart";
await platform.invokeMethod('sendString', dartString);
内部发生的过程:
- Dart 字符串 → 二进制数据:Dart 字符串使用 Flutter 的标准消息编解码器序列化为二进制数据
- 二进制传输:该二进制数据通过平台通道发送
- 二进制数据 → 原生类型:原生端将二进制数据反序列化为相应的原生类型
2. 标准消息编解码器
Flutter 使用处理类型映射的 StandardMessageCodec:
objectivec
Dart 类型 → iOS 原生类型 → Android 原生类型
String → NSString → String
int → NSNumber → Integer
double → NSNumber → Double
bool → NSNumber → Boolean
List → NSArray → ArrayList
Map → NSDictionary → HashMap
详细示例
Dart 端 (插件)
dart
class MyPlugin {
static const MethodChannel _channel = MethodChannel('my_plugin');
static Future<String> sendStringToNative(String message) async {
// 此字符串会自动序列化
final result = await _channel.invokeMethod('processString', message);
return result;
}
}
iOS 原生端 (Objective-C)
objc
@implementation MyPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"my_plugin"
binaryMessenger:[registrar messenger]];
MyPlugin* instance = [[MyPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"processString" isEqualToString:call.method]) {
// call.arguments 自动转换为 NSString
NSString* receivedString = call.arguments;
// 处理字符串
NSString* processedString = [NSString stringWithFormat:@"处理后的字符串: %@", receivedString];
// 返回结果 (将转换回 Dart 字符串)
result(processedString);
} else {
result(FlutterMethodNotImplemented);
}
}
@end
Android 原生端 (Kotlin)
kotlin
class MyPlugin: FlutterPlugin, MethodCallHandler {
private lateinit var channel: MethodChannel
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "my_plugin")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"processString" -> {
// call.arguments 自动转换为 String
val receivedString = call.arguments as String
// 处理字符串
val processedString = "处理后的字符串: $receivedString"
// 返回结果 (将转换回 Dart 字符串)
result.success(processedString)
}
else -> result.notImplemented()
}
}
}
类型转换背后的原理
1. 二进制消息格式
Flutter 使用自定义二进制格式进行消息序列化:
css
消息结构:
[类型字节][长度][数据]
例如字符串 "Hello":
[0x07][0x05][H][e][l][l][o]
2. 编解码器实现
StandardMessageCodec
处理转换:
dart
// 内部过程的简化版本
class StandardMessageCodec {
static const int valueString = 7;
// 编码 Dart → 二进制
void writeValue(ByteData data, dynamic value) {
if (value is String) {
data.setUint8(offset++, valueString);
writeString(data, value);
}
}
// 解码 二进制 → 原生类型
dynamic readValue(ByteData data) {
int type = data.getUint8(offset++);
if (type == valueString) {
return readString(data);
}
}
}
3. 平台特定的反序列化
每个平台有自己的反序列化逻辑:
iOS (FlutterStandardMessageCodec.mm):
objc
- (id)readValueOfType:(UInt8)type {
switch (type) {
case FlutterStandardFieldString: {
return [self readUTF8String]; // 返回 NSString*
}
}
}
Android (StandardMessageCodec.java):
java
protected Object readValueOfType(byte type) {
switch (type) {
case STRING:
return readUTF8String(); // 返回 String
}
}
复杂数据类型
对于复杂对象,需要自定义序列化:
dart
// Dart 端
Map<String, dynamic> complexData = {
'name': 'John',
'age': 30,
'scores': [85, 92, 78]
};
await platform.invokeMethod('sendComplexData', complexData);
objc
// iOS 端 - 接收 NSDictionary
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"sendComplexData" isEqualToString:call.method]) {
NSDictionary* data = call.arguments;
NSString* name = data[@"name"]; // NSString
NSNumber* age = data[@"age"]; // NSNumber
NSArray* scores = data[@"scores"]; // NSArray of NSNumber
}
}
性能注意事项
- 序列化开销:每条消息都需要序列化/反序列化
- 异步特性:所有平台通道调用都是异步的
- 主线程限制:原生代码默认在主线程运行
总结
关键要点如下:
- 无直接类型共享:Dart 和原生类型不直接交互
- 二进制序列化:数据转换为二进制格式进行传输
- 自动转换:Flutter 的编解码器自动处理常见类型转换
- 平台特定的反序列化:每个平台将二进制数据转换为其原生类型
- 双向通信:相同流程也适用于从原生端返回值给 Dart
这种架构使 Flutter 能够保持平台独立性,同时实现与原生代码的无缝通信。