Flutter原理Platform与Dart通信方式分析

Posted 牧羊人.阿标

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter原理Platform与Dart通信方式分析相关的知识,希望对你有一定的参考价值。

背景

我们知道Flutter作为一个跨平台框架,那么必定存在着Native到Dart,Dart到Native之间的双工通信问题。本文我们一起来看看Flutter 平台通信相关原理。

三种通信方式

Flutter 官方提供三种 Platform 与 Dart 端消息通信方式,他们分别是 MethodChannel、BasicMessageChannel、EventChannel。他们都是全双工通信,他们的主要区别是:

  • MethodChanel:用于传递方法调用(Method invocation),一次性通信。MethodCallHandler 最终必须在 UI 线程通过result.success(x)方法返回结果,返回前自己可以异步新起线程做任意耗时操作。
  • BasicMessageChannel:用于传递字符串和半结构化的消息,持续通信
  • EventChannel:用于数据流(event streams)的通信,持续通信

请记住这张图

  • 无论是何总Channle,能实现Native与Dart之间通信都离不开核心类BinaryMessengers
  • 三种类型在各端都有对应的实现

MethodChannel使用方法(Dart——>Native)

  1. 调用方创建MethodChannel,这里是dart端创建MethodChannel

     static const platform = MethodChannel('samples.flutter.dev/battery');
    
  2. 调用native方法

    final int result = await platform.invokeMethod('getBatteryLevel');
    

    这个时候调用是无效的,应为native端该方法还未添加

  3. native创建对应的MethodChannel并设置它的MethodCallHandler,name保持一致

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
          // Note: this method is invoked on the main thread.
          call, result ->
          if (call.method == "getBatteryLevel") {
            val batteryLevel = getBatteryLevel()
    
            if (batteryLevel != -1) {
              result.success(batteryLevel)
            } else {
              result.error("UNAVAILABLE", "Battery level not available.", null)
            }
          } else {
            result.notImplemented()
          }
        }
    

    到这里dart端调用native端流程就已经结束了。

EventChannel使用方法(Dart——>Native)

  1. 事件接受方创建EventChannel,这里是dart端创建EventChannel并设置监听

    static const EventChannel eventChannel = EventChannel(
          'samples.flutter.dev/battery');
    // 设置监听,返回的是StreamSubscription对象,注意界面销毁的时候调用StreamSubscription的cancel取消监听
    eventChannel
            .receiveBroadcastStream()
            .listen(_onEvent, onError: _onError);
    
  2. native同样创建Channel之后设置它的streamHandler

     EventChannel eventChannel = new EventChannel(registrar.messenger(), CHANNEL);
     eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
                @Override
                public void onListen(Object o, EventChannel.EventSink eventSink) {
                    this.eventSink = eventSink;
                }
    
                @Override
                public void onCancel(Object o) {
                    this.eventSink = null;
                }
            });
    

    dart在设置监听之后,这边会触发onListen方法,这里需要保存EventChannel.EventSink对象

  3. native端发送事件

    eventSink.success(object);
    eventSink.error(...);
    eventSink.endOfStream();
    

BasicMessageChannel使用方法(Dart——>Native)

  1. 调用方创建BasicMessageChannel,也就是dart端创建BasicMessengerChannle

      static const messageChannel = const BasicMessageChannel(
          'flutter_and_native_100', StandardMessageCodec());
    
  2. 发送消息

        Map reply = await messageChannel.send(arguments);
    
  3. native创建channel

    		mMessageChannel = new BasicMessageChannel<Object>(getFlutterView(), "flutter_and_native_100", StandardMessageCodec.INSTANCE);
    
  4. 设置消息接收监听

    		mMessageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler<Object>() {
    			@Override
    			public void onMessage(Object o, BasicMessageChannel.Reply<Object> reply) {
          }
        }
    

    收到消息会会调到onMessage方法,如果需要回调的话, 调用:

    //回调 此方法只能使用一次
    reply.reply(resultMap);
    

讲到这,这三个Channel的用法只是简单介绍了Dart端到Native端的方法, 其实Native端到Dart端的调用如出一辙,也很简单,这里就不啰嗦了。下面在分析下原理。

源码简要分析

我们首先来看Platform端几个Channel的构造方法和核心成员变量

public class MethodChannel {
  private final BinaryMessenger messenger;
  private final String name;
  private final MethodCodec codec;
  //......
  private final class IncomingMethodCallHandler implements BinaryMessageHandler {
    private final MethodCallHandler handler;
  }
}

public final class BasicMessageChannel<T> {
  @NonNull private final BinaryMessenger messenger;
  @NonNull private final String name;
  @NonNull private final MessageCodec<T> codec;
  //......
  private final class IncomingMessageHandler implements BinaryMessageHandler {
    private final MessageHandler<T> handler;
  }
}

public final class EventChannel {
  private final BinaryMessenger messenger;
  private final String name;
  private final MethodCodec codec;
  //......
  private final class IncomingStreamRequestHandler implements BinaryMessageHandler {
    private final StreamHandler handler;
  }
}

可以看到,Platform 端无论哪种方式,他们都有三种重要的成员,分别是:

  • name:String 类型,唯一标识符代表 Channel 的名字
  • messager:BinaryMessenger 类型,充当信使邮递员角色,消息的发送与接收工具人。
  • codec:MethodCodec 或MessageCodec类型,充当消息的编解码器。

所以这三者的关系本身核心逻辑都在BinaryMessenger这个抽象类,我们先来看看:

Java端的BinaryMessenger的源码

public interface BinaryMessenger {
    @UiThread
    void send(@NonNull String var1, @Nullable ByteBuffer var2);

    @UiThread
    void send(@NonNull String var1, @Nullable ByteBuffer var2, @Nullable BinaryMessenger.BinaryReply var3);

    @UiThread
    void setMessageHandler(@NonNull String var1, @Nullable BinaryMessenger.BinaryMessageHandler var2);

    public interface BinaryReply {
        @UiThread
        void reply(@Nullable ByteBuffer var1);
    }

    public interface BinaryMessageHandler {
        @UiThread
        void onMessage(@Nullable ByteBuffer var1, @NonNull BinaryMessenger.BinaryReply var2);
    }
}

Dart端的BinaryMessenger的源码

public interface BinaryMessenger {
  @UiThread
  void send(@NonNull String channel, @Nullable ByteBuffer message);

  @UiThread
  void send(@NonNull String channel, @Nullable ByteBuffer message, @Nullable BinaryReply callback);

  @UiThread
  void setMessageHandler(@NonNull String channel, @Nullable BinaryMessageHandler handler);

  interface BinaryMessageHandler {
    @UiThread
    void onMessage(@Nullable ByteBuffer message, @NonNull BinaryReply reply);
  }

  interface BinaryReply {
    @UiThread
    void reply(@Nullable ByteBuffer reply);
  }
}

从接口的功能来看两端的设计功能几乎完全一模一样。这不难了理解,主要是为了保持各端的一致性。所以后面主要以EventChannel为例来讲讲Dart端的收发流程:

android端的收发流程也跟Dart收发流程极为相似,这里就不画图 了,画图真累…

所以这里总结来看无论是Dart还是Android端的收发流程都差不多:

作为接收方主要步骤:

  1. 统一channel name,初始化channel
  2. 设置MethodCallHandler

作为发送方主要步骤:

  1. 统一channel name,初始化channel
  2. 调用invokeMethod调用指定的方法。

以上是关于Flutter原理Platform与Dart通信方式分析的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 安卓 Platform 与 Dart 端消息通信方式 Channel 源码解析

Flutter 安卓 Platform 与 Dart 端消息通信方式 Channel 源码解析

Flutter 安卓 Platform 与 Dart 端消息通信方式 Channel 源码解析

Flutter 安卓 Platform 与 Dart 端消息通信方式 Channel 源码解析

Flutter 安卓 Platform 与 Dart 端消息通信方式 Channel 源码解析

Flutter 条件导入移动端 vs 桌面端