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)
-
调用方创建MethodChannel,这里是dart端创建MethodChannel
static const platform = MethodChannel('samples.flutter.dev/battery');
-
调用native方法
final int result = await platform.invokeMethod('getBatteryLevel');
这个时候调用是无效的,应为native端该方法还未添加
-
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)
-
事件接受方创建EventChannel,这里是dart端创建EventChannel并设置监听
static const EventChannel eventChannel = EventChannel( 'samples.flutter.dev/battery'); // 设置监听,返回的是StreamSubscription对象,注意界面销毁的时候调用StreamSubscription的cancel取消监听 eventChannel .receiveBroadcastStream() .listen(_onEvent, onError: _onError);
-
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对象 -
native端发送事件
eventSink.success(object); eventSink.error(...); eventSink.endOfStream();
BasicMessageChannel使用方法(Dart——>Native)
-
调用方创建
BasicMessageChannel
,也就是dart端创建BasicMessengerChannlestatic const messageChannel = const BasicMessageChannel( 'flutter_and_native_100', StandardMessageCodec());
-
发送消息
Map reply = await messageChannel.send(arguments);
-
native创建channel
mMessageChannel = new BasicMessageChannel<Object>(getFlutterView(), "flutter_and_native_100", StandardMessageCodec.INSTANCE);
-
设置消息接收监听
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端的收发流程都差不多:
作为接收方主要步骤:
- 统一channel name,初始化channel
- 设置MethodCallHandler
作为发送方主要步骤:
- 统一channel name,初始化channel
- 调用invokeMethod调用指定的方法。
以上是关于Flutter原理Platform与Dart通信方式分析的主要内容,如果未能解决你的问题,请参考以下文章
Flutter 安卓 Platform 与 Dart 端消息通信方式 Channel 源码解析
Flutter 安卓 Platform 与 Dart 端消息通信方式 Channel 源码解析
Flutter 安卓 Platform 与 Dart 端消息通信方式 Channel 源码解析
Flutter 安卓 Platform 与 Dart 端消息通信方式 Channel 源码解析