一、问题:Dart 和原生代码如何通信?
-
Dart 和 Java/Kotlin 运行在不同的虚拟机中
-
它们的内存空间完全隔离
-
不能直接调用对方的函数或访问对象
解决方案:进程间通信(IPC)
Flutter 采用了类似 IPC(进程间通信) 的机制,虽然它们在同一个进程,但原理相同:

二、底层通信的完整流程
1. 消息从 Dart 到原生的路径

2. 每一步的原理解析
第一步:Dart 侧的序列化
// Dart 代码
platform.invokeMethod('getBattery', {'unit': 'percent'});
// 底层实际执行(简化)
Future<ByteBuffer> _sendPlatformMessage(String channel, ByteBuffer message) {
// 1. 将参数序列化为二进制
final List<int> encoded = StandardMethodCodec.instance.encodeMethodCall(
MethodCall('getBattery', {'unit': 'percent'})
);
// 2. 调用 Engine 的 C++ 函数
return _dispatchPlatformMessage(channel, encoded);
}
序列化后的二进制格式:
[method_name_length][method_name][arguments_length][arguments_data]
[0x0B][getBattery][0x0F][{unit:percent}]
第二步:跨语言边界调用
// Flutter Engine C++ 代码(简化)
void PlatformView::DispatchPlatformMessage(const std::string& channel,
const std::vector<uint8_t>& message) {
// 1. 创建消息对象
auto platform_message = std::make_unique<PlatformMessage>(channel, message);
// 2. 放入消息队列(线程安全)
task_runner_->PostTask([this, message = std::move(platform_message)]() {
// 3. 在 Platform Thread 处理消息
HandlePlatformMessage(std::move(message));
});
}
第三步:查找并调用原生 Handler
// Flutter Engine 调用 Java 的桥梁
void PlatformMessageRouter::HandlePlatformMessage(
std::unique_ptr<PlatformMessage> message) {
// 1. 找到对应的 Channel
auto& channel = message->channel();
// 2. 通过 JNI 调用 Java 方法
JNIEnv* env = AttachCurrentThread();
// 3. 查找 Java 中的 MethodChannel 类
jclass channel_class = env->FindClass("io/flutter/plugin/common/MethodChannel");
// 4. 调用 Java 的 onMethodCall 方法
env->CallVoidMethod(channel_object, on_method_call_id,
call_object, result_object);
}
第四步:Java 侧接收消息
// Android 侧的 MethodChannel 内部实现
public class MethodChannel {
public void invokeMethod(String method, Object arguments, Result callback) {
// 1. 将二进制消息反序列化为 MethodCall
MethodCall call = codec.decodeMethodCall(message);
// 2. 调用你注册的 Handler
handler.onMethodCall(call, new Result() {
@Override
public void success(Object result) {
// 3. 序列化结果并返回
reply(encodeSuccessResult(result));
}
});
}
}
三、关键底层机制
1. JNI(Java Native Interface)- Dart 与 Java 的桥梁
// Flutter Engine 中的 JNI 调用示例
void FlutterJNI::DispatchPlatformMessage(JNIEnv* env, jobject jcaller,
jstring jchannel,
jbyteArray jmessage,
jint jposition,
jint jresponseId) {
// 1. 将 Java 字符串转为 C++ 字符串
const char* channel = env->GetStringUTFChars(jchannel, nullptr);
// 2. 将 Java 字节数组转为 C++ 向量
std::vector<uint8_t> message = JavaByteArrayToVector(env, jmessage);
// 3. 调用 C++ 处理函数
nativeEngine->DispatchPlatformMessage(channel, message, responseId);
// 4. 释放 Java 资源
env->ReleaseStringUTFChars(jchannel, channel);
}
JNI 的作用:
-
让 C++ 代码可以调用 Java 代码
-
让 Java 代码可以调用 C++ 代码
-
实现跨语言的数据转换
2. Dart Native Extension - Dart 与 C++ 的桥梁
// Flutter Engine 注册 Dart 函数
void PlatformConfiguration::RegisterNatives(
tonic::DartLibraryNatives* natives) {
// 注册 Dart 可调用的 C++ 函数
natives->Register({
{"Window_scheduleFrame", ScheduleFrame},
{"Window_platformConfiguration", PlatformConfiguration},
{"Window_updateSemantics", UpdateSemantics},
// 平台消息相关
{"PlatformConfiguration_sendPlatformMessage", SendPlatformMessage},
});
}
// Dart 调用这个 C++ 函数
void SendPlatformMessage(Dart_NativeArguments args) {
// 1. 获取 Dart 传递的参数
Dart_Handle channel = Dart_GetNativeArgument(args, 0);
Dart_Handle message = Dart_GetNativeArgument(args, 1);
// 2. 转为 C++ 类型
std::string channel_name = tonic::DartConverter<std::string>::FromDart(channel);
std::vector<uint8_t> message_data = tonic::DartConverter<std::vector<uint8_t>>::FromDart(message);
// 3. 调用 C++ 处理函数
auto* window = tonic::DartConverter<Window*>::FromDart(Dart_GetNativeArgument(args, 2));
window->client()->SendPlatformMessage(channel_name, message_data);
}
3. 消息队列与线程调度
// Flutter 的线程模型
class PlatformTaskRunner {
public:
void PostTask(std::function<void()> task) {
// 使用互斥锁保护消息队列
std::lock_guard<std::mutex> lock(queue_mutex_);
task_queue_.push(std::move(task));
// 通知平台线程有新消息
NotifyPlatformThread();
}
void Run() {
while (running_) {
std::function<void()> task;
{
std::lock_guard<std::mutex> lock(queue_mutex_);
if (task_queue_.empty()) {
// 等待新消息
condition_.wait(lock);
continue;
}
task = std::move(task_queue_.front());
task_queue_.pop();
}
// 执行任务
task();
}
}
};
四、与 IPC 的类比
| 特性 | Flutter Channel | 传统 IPC(如 Binder) |
|---|---|---|
| 数据隔离 | 内存空间隔离 | 进程隔离 |
| 序列化 | StandardMessageCodec | Parcel/Marshalling |
| 线程模型 | 消息队列 + 任务调度 | Binder 线程池 |
| 调用方式 | 异步回调 | 同步/异步 |
| 性能 | 中等(2-5μs) | 较高(1-3μs) |