flutter 与原生通信的底层原理(二)

一、问题: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)
相关推荐
Lanren的编程日记2 小时前
Flutter 鸿蒙应用离线模式实战:无网络也能流畅使用
网络·flutter·harmonyos
IntMainJhy3 小时前
【Flutter for OpenHarmony 】第三方库 聊天应用:Provider 状态管理实战指南
flutter·华为·harmonyos
IntMainJhy3 小时前
【futter for open harmony】Flutter 聊天应用实战:Material Design 3 全局 UI 规范落地指南✨
flutter·华为·harmonyos
IntMainJhy3 小时前
【flutter for open harmony】Flutter 聊天应用实战:go_router 路由管理完全实现指南
flutter·华为·harmonyos
liulian09163 小时前
【Flutter For OpenHarmony第三方库】Flutter 页面导航的鸿蒙化适配实战
flutter·华为·学习方法·harmonyos
Lanren的编程日记4 小时前
Flutter 鸿蒙应用用户反馈功能实战:快速收集用户意见与建议
flutter·华为·harmonyos
程序员老刘19 小时前
跨平台开发地图:四月风暴前夕,你该怎么选?| 2026年4月
flutter·ai编程·客户端
MakeZero20 小时前
Flutter那些事-PageView
flutter
Lanren的编程日记1 天前
Flutter鸿蒙应用开发:数据加密功能实现实战,全方位保护用户隐私数据
flutter·华为·harmonyos