Floating Cat

深入Flutter技术内幕:Platform Channel设计与实现(一)

字数统计: 8.2k阅读时长: 36 min
2019/02/09 Share

Flutter作为一个灵活的UI框架,引入Platform Channel机制来支持不同平台的API调用,无论是Android上的由Java或Kotlin开发的API,还是IOS上用Objective-C或Swift开发API.需要注意的是Platform Channel不依赖代码生成,而是建立在消息传递方式上.实际上,它的工作模式和原理非常类似基于二进制协议开发的网络服务,在下文中,我们会对此有更深的理解与体会.

Platform Channel简介

在Flutter中,提供了三种Platform Channel用来支持和平台之间数据的传递:

  • BasicMessageChannel: 支持字符串和半结构化的数据传递
  • MethodChannel: 支持方法调用,既可以从Flutter发平台发起方法调用,也可以从平台代码向Flutter发起调用
  • EventChannel: 支持数据流通信

这三种Platform Channel分别用不同的作用,但在设计上大同小异,他们都有以下三个成员变量:

  • name:表示Channel名字,每个Channel使用唯一的name作为其唯一标志
  • messager:信使,是消息的发送和接受工具
  • codec: 表示消息的编解码器,目前有MethodCodec和MessageCodec两种类型

Platform Channel基本结构

为了对这三种Platform Channel有个比较感性的认识,通过以下简化过的代码来熟悉它们的结构.比较熟悉的同学可以直接跳过此章节.

BasicMessageChannel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public final class BasicMessageChannel<T> {
private final BinaryMessenger messenger;
private final String name;
private final MessageCodec<T> codec;

public void setMessageHandler(final MessageHandler<T> handler) {
messenger.setMessageHandler(name,
handler == null ? null : new IncomingMessageHandler(handler));
}

public interface MessageHandler<T> {
void onMessage(T message, Reply<T> reply);
}

private final class IncomingMessageHandler implements BinaryMessageHandler {
private final MessageHandler<T> handler;

private IncomingMessageHandler(MessageHandler<T> handler) {
this.handler = handler;
}

@Override
public void onMessage(ByteBuffer message, final BinaryReply callback) {
......
handler.onMessage();
......
}
}
}

MethodChannel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public final class MethodChannel {
private final BinaryMessenger messenger;
private final String name;
private final MethodCodec codec;

......

public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
messenger.setMessageHandler(name,
handler == null ? null : new IncomingMethodCallHandler(handler));
}

public interface Result {
void success(@Nullable Object result);
void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails);
void notImplemented();
}

public interface MethodCallHandler {
void onMethodCall(MethodCall call, Result result);
}

private final class IncomingMethodCallHandler implements BinaryMessageHandler {
private final MethodCallHandler handler;

IncomingMethodCallHandler(MethodCallHandler handler) {
this.handler = handler;
}

@Override
public void onMessage(ByteBuffer message, final BinaryReply reply) {
......
handler.onMethodCall();
......
}
}
}

EventChannel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public final class EventChannel {
private final BinaryMessenger messenger;
private final String name;
private final MethodCodec codec;

public void setStreamHandler(final StreamHandler handler) {
messenger.setMessageHandler(name, handler == null ? null : new IncomingStreamRequestHandler(handler));
}

public interface StreamHandler {
void onListen(Object arguments, EventSink events);
void onCancel(Object arguments);
}

public interface EventSink {
void success(Object event);
void error(String errorCode, String errorMessage, Object errorDetails);
void endOfStream();
}

private final class IncomingStreamRequestHandler implements BinaryMessageHandler {
private final StreamHandler handler;
private final AtomicReference<EventSink> activeSink = new AtomicReference<>(null);

IncomingStreamRequestHandler(StreamHandler handler) {
this.handler = handler;
}

@Override
public void onMessage(ByteBuffer message, final BinaryReply reply) {
......
handler.onCancel();
......
handler.onListen();
......
}
}
}

name(Channel名称)

name是用于区分不同Platform Channel的唯一标志.在一个Flutter应用中,通常会存在多个Platform Channel,不同Channel之间通过name那么来区分.比如在使用MethodChannel平台发起方法调用时,需要为MethodChannel指定对应的name.

messager(信使)

messager也称为信使,通俗来说信使就是现代的快递员,它负责把数据从Flutter搬运到JAndroid/IOS平台,或者从Android/IOS搬运到Flutter).对于Flutter中的三种Channel,尽管各自用途不同,但messager都是BinaryMessager.

当我们创建一个Channel时,并为其设置消息处理器时,最终会为该Channel绑定一个BinaryMessagerHandler.并以Channel的name为key,保存在Map结构中.当接受到发送消息后,会根据消息中携带的channel名称取出对应BinaryMessagerHandler,并交由其处理.在Android平台中,BinaryMessenger是一个接口,其实现类是FlutterNativeView.在后续MethodChannel调用原理中,会进一步分析.

Codec(编解码器)

在Platform Channel中,messager携带的数据需要在Dart层,Native层以及Android/IOS平台中传输,需要考虑一种与平台无关的数据协议,且又能支持图片/文件等资源,因此官方最终采用了二进制字节流作为数据传输协议:发送方需要把数据编码成二进制数据,接受方再把数据解码成原始数据.而负责编解码操作的就是Codec.

在Flutter中有两种Codec:

  • MethodCodec: 用于对MethodCall编解码
  • MessageCodec: 用于对Message进行编解码

MessageCodec

MessageCodec用于二进制数据与基础数据之间的编解码,其中BasicMessageChannel中采用的就是该Codec.以Android平台为例,MessageCodec定义如下:

1
2
3
4
5
6
public interface MessageCodec<T> {
// 将指定的类型message编码为二进制数据ByteBuffer
ByteBuffer encodeMessage(T message);
// 将二进制数据ByteBuffer解码成指定类型
T decodeMessage(ByteBuffer message);
}

MessageCodec被设计为一个泛型接口,用于实现二进制数据ByteBuffer和不同类型数据之间的转换.(在IOS中,可参考FlutterMessageCodec协议,其原理基本一致).

在Flutter中,目前MessageCodec有多种实现:

image-20190209205941331

BinaryCodec

用于二进制数据和二进制数据之间的编解码,在实现上什么也没有做,只是原封不动的将二进制数据返回而已.

StringCodec

用于字符串与二进制数据之间的编解码,对于字符串采用UTF-8编码格式.

JSONMessageCodec

用于数据类型与二进制数据之间的编解码,支持基础数据类型(boolean,char,double,float,int,long,short,String)以及List,Map.在Android端使用JSONUtil和StringCodec作为序列化和反序列化工具.

StandardMessageCodec

用于数据类型和二进制数据之间的编解码,它也是BasicMessageChannel中默认使用的编解码器,支持基础数据类型(boolean,char,double,float,int,long,short,String),List,Map以及二进制数据,更多参见:深入编解码器原理

MethodCodec

MethodCodec用于二进制数据与方法调用(MethodCall)和返回结果之间的编解码.MethodChannel和EventChannel所使用的编解码器均为MethodCodec.以Android平台为例,MethodCodec定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface MethodCodec {
// 将methodCall编码为二进制ByteBuffer
ByteBuffer encodeMethodCall(MethodCall methodCall);

// 将二进制methodCall解码为MethodCall
MethodCall decodeMethodCall(ByteBuffer methodCall);

// 将正常响应结果result编码为二进制ByteBuffer
ByteBuffer encodeSuccessEnvelope(Object result);

// 将错误响应提示编码为二进制ByteBuffer
ByteBuffer encodeErrorEnvelope(String errorCode, String errorMessage, Object errorDetails);

// 将二进制数据ByteBuffer解码成Object
Object decodeEnvelope(ByteBuffer envelope);
}

一个MethodCall对象代表一次从Flutter端发起的方法调用,对于方法调用而言,涉及方法名,方法参数以及方法返回结果,因此和MessageCodec相比,MethodCodec中多了两个处理调用结果的方法:

  • 方法调用成功,使用encodeSuccessEnvelope()编码result
  • 方法调用失败,使用encodeErrorEnvelope()编码errorCode,errorMessage,errorDetail

decodeEnvelope()方法则用于解码平台代码调用Dart中方法的结果.比如Android平台通过MethodChannel调用Flutter中的方法,且获取其返回结果

在Flutter中,目前MethodCodec有两种实现:

image-20190209174504635

JSONMethodCodec

JSONMethodCodec编解码器依赖于JSONMessageCodec.在将MethodCall对象进行编码时,会首先将该对象转成JSON对象:{“method”:method,”args”:args},比如当前想要调用某个Channel的setVolum(5),其对应的MethodCall被被转成{"method":"setVolum","args":{"volum":5}},接下来使用JSONMessageCodec将其编码为二进制数据.

StandardMethodCodec

StandardMethodCodec的编解码器依赖于StandardMessageCodec,它也是MethodCodec的默认实现.当其编码在将MethodCall对象进行编码时,会将MethoCall对象的method和args依次使用StandardMessageCodec进行编码,然后写成二进制数据.

深入编解码器原理

在学习编写Platform Channel过程中,Flutter官方介绍了如何借助MethodChannel编写获取Android/IOS平台上的电量插件.在Android平台中电量返回值是java.lang.Integer类型,而IOS平台中电量返回值是NSNumber类型,而在Dart中,该返回值类型是dart语言中的int类型.下面以Android平台为例,通过分析StandardMethodCodec实现来了解其原理.

上面我们已经说过StandardMethodCodec中使用标准的二进制消息编码器StandardMessageCodec,首先来看一下StandardMethodCodec的定义:

1
2
3
4
5
6
7
8
9
10
11
public final class StandardMethodCodec implements MethodCodec {
public static final StandardMethodCodec INSTANCE = new StandardMethodCodec(StandardMessageCodec.INSTANCE);
private final StandardMessageCodec messageCodec;

public StandardMethodCodec(StandardMessageCodec messageCodec) {
this.messageCodec = messageCodec;
}

.......

}

现在重点分析StandardMessageCodec:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
public class StandardMessageCodec implements MessageCodec<Object> {
public static final StandardMessageCodec INSTANCE = new StandardMessageCodec();

// 字节序判断,LITTLE_ENDIAN为true表示是小端模式,否则为大端模式.在对字节流写入和读取时,
// 需要根据字节序来决定读取和写入的顺序
private static final boolean LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
private static final Charset UTF8 = Charset.forName("UTF8");
// 下面14个常量值用来标志不同类型的数据,比如0表示NULL,3表示int类型.在向字节流写入指定类型
// 的数据时,需要首先写入类型标志,然后紧跟着写入具体的值;在从字节流读取数据时,首先读取类型标
// 志,然后读取具体的数值.
private static final byte NULL = 0;
private static final byte TRUE = 1;
private static final byte FALSE = 2;
private static final byte INT = 3;
private static final byte LONG = 4;
private static final byte BIGINT = 5;
private static final byte DOUBLE = 6;
private static final byte STRING = 7;
private static final byte BYTE_ARRAY = 8;
private static final byte INT_ARRAY = 9;
private static final byte LONG_ARRAY = 10;
private static final byte DOUBLE_ARRAY = 11;
private static final byte LIST = 12;
private static final byte MAP = 13;


@Override
public ByteBuffer encodeMessage(Object message) {
if (message == null) {
return null;
}
final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
// 将message写入二进制字节流中
writeValue(stream, message);
final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
buffer.put(stream.buffer(), 0, stream.size());
return buffer;
}

@Override
public Object decodeMessage(ByteBuffer message) {
if (message == null) {
return null;
}
message.order(ByteOrder.nativeOrder());
// 从二进制字节流message中读取数据
final Object value = readValue(message);
if (message.hasRemaining()) {
throw new IllegalArgumentException("Message corrupted");
}
return value;
}

// 根据数据类型,先向stream中写入类型标志值,及上述提到的14个常量值,然后将具体的
// value值转成byte继续写入到stream
protected void writeValue(ByteArrayOutputStream stream, Object value) {
if (value == null) {
stream.write(NULL);
} else if (value == Boolean.TRUE) {
stream.write(TRUE);
} else if (value == Boolean.FALSE) {
stream.write(FALSE);
} else if (value instanceof Number) {
if (value instanceof Integer || value instanceof Short || value instanceof Byte) { // 1.写入类型标志值
stream.write(INT);
// value转为byte,继续写入到stream中
writeInt(stream, ((Number) value).intValue());
}
.......
}else if (value instanceof String) {
stream.write(STRING);
writeBytes(stream, ((String) value).getBytes(UTF8));
}
.......
}

// 根据字节序决定写入顺序
protected static final void writeInt(ByteArrayOutputStream stream, int value) {
if (LITTLE_ENDIAN) {
stream.write(value);
stream.write(value >>> 8);
stream.write(value >>> 16);
stream.write(value >>> 24);
} else {
stream.write(value >>> 24);
stream.write(value >>> 16);
stream.write(value >>> 8);
stream.write(value);
}
}

// writeValue()方法反向过程,原理一致
protected final Object readValue(ByteBuffer buffer) {
.......
}

static final class ExposedByteArrayOutputStream extends ByteArrayOutputStream {
byte[] buffer() {
return buf;
}
}
}

在StandardMessageCodec中最重要的两个方法是writeValue()readValue().前者用于将value值写入到字节输出流ByteArrayOutputStream中,后者从字节缓冲数组中读取.在Android返回电量的过程中,假设电量值为100,该值转换成二进制数据流程为:首先向字节流stream中写入表示int类型的标志值3,再将100转为4个byte,继续写入到字节流stream中.当Dart中接受到该二进制数据后,先读取第一个byte值,根据此值得知后面需要读取一个int类型的数据,随后读取后面4个byte,并将其转为dart类型中int类型.

image-20190209194123776

Handler

Flutter中定义了一套Handler用于处理经过Codec解码后消息.在使用Platform Channel时,需要为其设置对应的Handler,实际上就是为其注册一个对应BinaryMessageHandler,二进制数据会被BinaryMessageHanler进行处理,首先使用Codec进行解码操作,然后再分发给具体Handler进行处理.与三种Platform Channel相对应,Flutter中也定义了三种Handler:

  • MessageHandler: 用于处理字符串或者半结构化消息,定义在BasicMessageChannel中.
  • MethodCallHandler: 用于处理方法调用,定义在MethodChannel中.
  • StreamHandler: 用于事件流通信,定义在EventChannel中.

MessageHandler

用于处理字符串或者半结构化的消息,其定义如下:

1
2
3
4
5
6
7
8
9
public final class BasicMessageChannel<T> {
......

public interface MessageHandler<T> {
void onMessage(T message, Reply<T> reply);
}

......
}

onMessage()用于处理来自Flutter中的消息,该接受两个参数:T类型的消息以及用于异步返回T类型的result

MethodCallHandler

MethodCallHandler用于处理方法的调用,其定义如下:

1
2
3
4
5
6
7
8
9
public final class MethodChannel {
......

public interface MethodCallHandler {
void onMethodCall(MethodCall call, Result result);
}

......
}

onMessage()用于处理来自Flutter中消息,该方法接受两个参数:用于方法调用MethodCall对象以及用于方法返回Result类型的对象.

StreamHandler

StreamHandler用于事件流的通信,通常是用于平台主动向Flutter发送事件通知,其定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
public final class EventChannel {
......

public interface StreamHandler {

void onListen(Object arguments, EventSink events);

void onCancel(Object arguments);
}

......
}

在StreamHandler存在两个方法:onListen()onCancel().当Flutter端开始监听平台事件时,会向平台发起一次MethodCall,其中方法名为listen,也就是最终会调用StreamHandler中的onListen()方法.该方法中接受两个参数,其中EventSink类型的参数可用于向Flutter发送事件(实际上还是通过BinaryMessager).当Flutter开始停止监听平台事件时,会再向平台发起一次MethodCall,其中方法名为cancel,最终会调用StreamHandler的onCancel()方法,在该方法中通常需要销毁一些无用的资源.关于StreamHandler原理,会另开一文.

MethodChannel调用原理

MethodChannel用于实现Flutter和Android/IOS平台间的方法调用.下文将以从Flutter调用Android平台代码为主线进行分析,主要涉及方法调用及方法调用结果返回两个过程.

方法调用

Dart -> Native

MethodChannel定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MethodChannel {
// 构造方法,通常我们只需要指定该channel的name,
const MethodChannel(this.name, [this.codec = const StandardMethodCodec()]);
// name作为通道的唯一标志付,用于区分不同的通道调用
final String name;
// 用于方法调用过程的编码
final MethodCodec codec;

// 用于发起异步平台方法调用,需要指定方法名,以及可选方法参数
Future<dynamic> invokeMethod(String method, [dynamic arguments]) async {
assert(method != null);
// 将一次方法调用中需要的方法名和方法参数封装为MethodCall对象,然后使用MethodCodec对该
// 对象进行进行编码操作,最后通过BinaryMessages中的send方法发起调用
final dynamic result = await BinaryMessages.send(
name,
codec.encodeMethodCall(MethodCall(method, arguments)),
);
if (result == null)
throw MissingPluginException('No implementation found for method $method on channel $name');
return codec.decodeEnvelope(result);
}
}

在使用MethodChannel时,需要我们根据Channel名称来创建MethodChannel对象.Channel名称作为MethodChannel的唯一标识符,用于区分不同的MethodChannel对象.创建MethodChannel对象的一般方式如下:

1
final MethodChannel _channel = new MethodChannel('flutter.io/player')

拿到MethodChannel对象后,通过调用其invokeMethod()方法用于向平台发起一次调用.在invokeMethod()方法中会将一次方法调中的方法名method和方法参数arguments封装为MethodCall对象,然后使用MethodCodec对其进行二进制编码,最后通过BinaryMessages的send()发起平台方法调用请求.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class BinaryMessages {
......
static Future<ByteData> send(String channel, ByteData message) {
final _MessageHandler handler = _mockHandlers[channel];
// 在没有设置Mock Handler的情况下,继续调用_sendPlatformMessage()
if (handler != null)
return handler(message);
return _sendPlatformMessage(channel, message);
}

static Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
final Completer<ByteData> completer = Completer<ByteData>();
ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
try {
completer.complete(reply);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: 'during a platform message response callback',
));
}
});
return completer.future;
}
......
}

BinaryMessages类中提供了用于发送和接受平台插件的二进制消息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Window{
......
void sendPlatformMessage(String name,
ByteData data,
PlatformMessageResponseCallback callback) {
final String error =
_sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data);
if (error != null)
throw new Exception(error);
}
// 和Java类似,Dart中同样提供了Native方法用于调用底层C++/C代码的能力
String _sendPlatformMessage(String name,
PlatformMessageResponseCallback callback,
ByteData data) native 'Window_sendPlatformMessage';
.......
}

上述过程最终会调用到ui.Window的_sendPlatformMessage()方法,该方法是一个native方法,这与Java中JNI技术非常类似.

image-20190209112548889

在调用该Native方法中,我们向native层发送了三个参数:

  • name: String类型,代表Channel名称
  • data: ByteData类型,代表之前封装的二进制数据
  • callback: Function类型,用于结果回调

_sendPlatformMessage()具体实现在Window.cc中:

1
2
3
4
5
6
7
8
9
10
11
12
void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({
{"Window_defaultRouteName", DefaultRouteName, 1, true},
{"Window_scheduleFrame", ScheduleFrame, 1, true},
{"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
{"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
{"Window_render", Render, 2, true},
{"Window_updateSemantics", UpdateSemantics, 2, true},
{"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
{"Window_reportUnhandledException", ReportUnhandledException, 2, true},
});
}
1
2
3
4
void _SendPlatformMessage(Dart_NativeArguments args) {
// 最终调用SendPlatformMessage函数
tonic::DartCallStatic(&SendPlatformMessage, args);
}

SendPlatformMessage()函数定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Dart_Handle SendPlatformMessage(Dart_Handle window,
const std::string& name,
Dart_Handle callback,
const tonic::DartByteData& data) {
UIDartState* dart_state = UIDartState::Current();
// 1.只能在main iolate调用平台方法
if (!dart_state->window()) {
// Must release the TypedData buffer before allocating other Dart objects.
data.Release();
return tonic::ToDart(
"Platform messages can only be sent from the main isolate");
}
// 此处response的作用?
fml::RefPtr<PlatformMessageResponse> response;
if (!Dart_IsNull(callback)) {
response = fml::MakeRefCounted<PlatformMessageResponseDart>(
tonic::DartPersistentValue(dart_state, callback),
dart_state->GetTaskRunners().GetUITaskRunner());
}
// 2.核心方法调用
if (Dart_IsNull(data.dart_handle())) {
dart_state->window()->client()->HandlePlatformMessage(
fml::MakeRefCounted<PlatformMessage>(name, response));
} else {
const uint8_t* buffer = static_cast<const uint8_t*>(data.data());

dart_state->window()->client()->HandlePlatformMessage(
fml::MakeRefCounted<PlatformMessage>(
name, std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()),
response));
}

return Dart_Null();
}

在上方代码中首先判断是否在main isolate中进行平台方法调用,如果不是返回错误信息;接下来就是执行关键的方法:dart_state->window()->client()->HandlePlatformMessage().其中HandlePlatformMessage()WindowClient中虚方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class WindowClient {
public:
virtual std::string DefaultRouteName() = 0;
virtual void ScheduleFrame() = 0;
virtual void Render(Scene* scene) = 0;
virtual void UpdateSemantics(SemanticsUpdate* update) = 0;
virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
virtual FontCollection& GetFontCollection() = 0;
virtual void UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) = 0;

protected:
virtual ~WindowClient();
};

RuntimeController是WindowClient中的唯一继承类,其头文件runtime_controller.h,为了方便起见,我们只看其部分定义:

1
2
3
4
5
6
7
8
9
10
11
class RuntimeController final : public WindowClient {
......

private:
RuntimeDelegate& client_;

.......
void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
......

}

知道其定义之后,现在就可以看起具体在runtime_controller.cc的实现了:

1
2
3
4
void RuntimeController::HandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) {
client_.HandlePlatformMessage(std::move(message));
}

在运行过程中,不同的平台有运行机制不同,需要不同的处理策略,因此RuntimeController中相关的方法实现都被委托到了不同的平台实现类RuntimeDelegate中,即上述代码中client_.

RuntimeDelegate的实现为Engine,其头文件Engine.h定义如下:

1
2
3
class Engine final : public blink::RuntimeDelegate {
........
}

对应真实的实现在Engine.cc中,直接来看其HandlePlatformMessage()的实现

1
2
3
4
5
6
7
8
9
void Engine::HandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message) {
// kAssetChannel值为flutter/assets
if (message->channel() == kAssetChannel) {
HandleAssetPlatformMessage(std::move(message));
} else {
delegate_.OnEngineHandlePlatformMessage(std::move(message));
}
}

在上述代码过程中,Engine在处理message时,如果该message值等于kAssetChannel,即flutter/assets,表示当前操作想要获取资源,因此会调用HandleAssetPlatformMessage()来走获取资源的逻辑;否则调用delegate_.OnEngineHandlePlatformMessage()方法.这里delegate的具体实现为Shell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Shell::OnEngineHandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());

// kSkiaChannel值为flutter/skia
if (message->channel() == kSkiaChannel) {
HandleEngineSkiaMessage(std::move(message));
return;
}
// 其他情况下,向PlatformTaskRunner中添加Task
task_runners_.GetPlatformTaskRunner()->PostTask(
[view = platform_view_->GetWeakPtr(), message = std::move(message)]() {
if (view) {
view->HandlePlatformMessage(std::move(message));
}
});
}

OnEngineHandlePlatformMessage在接收到消息后,首先判断要调用Channel是否是flutter/skia,如果是则调用HandleEngineSkiaMessage()进行处理后返回,否则向PlatformTaskRunner添加一个Task,在该Task中会调用PlatformView的HandlePlatformMessage()方法.根据运行平台不同PlatformView有不同的实现,对于Android平台而言,其具体实现是PlatformViewAndroid;对于IOS平台而言,其实现是PlatformViewIOS.

image-20190208112830510

Task中的代码执行在Platform Task Runner中,而之前的代码运行在UI Task Runner中

以PlatformViewAndroid为例,来了解HandlePlatformMessage()方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// |shell::PlatformView|
void PlatformViewAndroid::HandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message) {
JNIEnv* env = fml::jni::AttachCurrentThread();
fml::jni::ScopedJavaLocalRef<jobject> view = java_object_.get(env);
if (view.is_null())
return;
// response_id在Flutter调用平台代码时,会传到平台代码中,后续平台代码需要回传数据时
// 需要用到它
int response_id = 0;
// 如果message中有response(response类型为PlatformMessageResponseDart),则需要对
// response_id进行自增
if (auto response = message->response()) {
response_id = next_response_id_++;
// pending_responses是一个Map结构
pending_responses_[response_id] = response;
}
auto java_channel = fml::jni::StringToJavaString(env, message->channel());
if (message->hasData()) {
fml::jni::ScopedJavaLocalRef<jbyteArray> message_array(
env, env->NewByteArray(message->data().size()));
env->SetByteArrayRegion(
message_array.obj(), 0, message->data().size(),
reinterpret_cast<const jbyte*>(message->data().data()));
message = nullptr;

// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),
message_array.obj(), response_id);
} else {
message = nullptr;
// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),
nullptr, response_id);
}
}

在上述代码中,当该方法接受PlatformMessage类型的消息时,如果消息中有response,则对response_id自增,并以response_ide为key,response为value存放在变量pending_responses_中(pending_responsed是一个Map结构).

正常情况下,每次从Flutter调用Channel代码,都会生成对应的response_id和response.同时该response_id会被传到平台代码中,当平台代码需要为此次调用返回数据时,需要同时回传该response_id.

接着将消息中的channel和data数据转成Java可识别的数据,并连同response_id一同作为FlutterViewHandlePlatformMessage()方法的参数,最终通过JNI调用的方式传递到Java层.

简单的分析下该过程,首先来看FlutterViewHandlePlatformMessage()platform_android_jni.cc中的实现:

1
2
3
4
5
6
7
8
9
10
static jmethodID g_handle_platform_message_method = nullptr;
void FlutterViewHandlePlatformMessage(JNIEnv* env,
jobject obj,
jstring channel,
jobject message,
jint responseId) {
env->CallVoidMethod(obj, g_handle_platform_message_method, channel, message,
responseId);
FML_CHECK(CheckException(env));
}

在上述方法中,最终将调用g_handle_platform_message_method中指向Java层的方法.其中g_handle_platform_message_method在RegisterApi中被初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool PlatformViewAndroid::Register(JNIEnv* env) {
......
g_flutter_jni_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
env, env->FindClass("io/flutter/embedding/engine/FlutterJNI"));

......

return RegisterApi(env);
}

bool RegisterApi(JNIEnv* env) {
......
g_handle_platform_message_method =
env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
"(Ljava/lang/String;[BI)V");
......
}

不难看出g_flutter_jni_class指向FlutterJNI.java类,g_handle_platform_message_method指向FlutterJN.javaI中的handlePlatformMessage()方法.

现在我们知道从Flutter发一次Channel调用,需要经过Dart -> Native -> JNI -> Java几个层次,并把三个参数channel,message,responseId传给Java层.

image-20190209113644507

Native -> Java

通过上述分析,我们知道FlutterViewHandlePlatformMessage()实际上是通过JNI的方式最终调用了FlutterJNI.java中的handlePlatformMessage()方法,该方法接受三个来自Native层的参数:

  • channel: String类型,表示Channel名称.
  • message: 字节数组,表示方法调用中的数据,如方法名和参数.
  • replyId: int类型,在将此次调用的响应数据从Java层写回到Native层时用到
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class FlutterJNI {
private PlatformMessageHandler platformMessageHandler;

@UiThread
public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler) {
this.platformMessageHandler = platformMessageHandler;
}

// Called by native.
@SuppressWarnings("unused")
private void handlePlatformMessage(final String channel, byte[] message, final int replyId) {
if (platformMessageHandler != null) {
platformMessageHandler.handleMessageFromDart(channel, message, replyId);
}
}
}

FlutterJNI类定义了Java层和Flutter C/C++引擎之间的相关接口.此类目前处于实验性质,随着后续的发展可能会被不断的重构和优化,不保证一直存在,不建议开发者调用该类.

为了建立Android应用和Flutter C/C++引擎的连接,需要创建FlutterJNI实例,然后将其attach到Native,常见的使用方法如下:

1
2
3
4
5
6
7
8
9
// 1.创建FlutterJNI实例
FlutterJNI flutterJNI = new FlutterJNI();
// 2.建立和Native层的连接
flutterJNI.attachToNative();

......

// 3.断开和Native层的连接,并释放资源
flutterJNI.detachFromNativeAndReleaseResources();

重新回到FlutterJNI中handlePlatformMessage(),在该方法中首先判断platformMessageHandler是否为null,不为null,则调用其handleMessageFromDart()方法.其中platformMessageHandler需要通过FlutterJNI中的setPlatformMessageHandler()方法来设置.那该方法被调用的时机是在什么时候呢?直接来看FlutterNativeView的构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class FlutterNativeView implements BinaryMessenger {

private final Map<String, BinaryMessageHandler> mMessageHandlers;
private int mNextReplyId = 1;
private final Map<Integer, BinaryReply> mPendingReplies = new HashMap<>();

private final FlutterPluginRegistry mPluginRegistry;
private FlutterView mFlutterView;
private FlutterJNI mFlutterJNI;
private final Context mContext;
private boolean applicationIsRunning;

public FlutterNativeView(Context context, boolean isBackgroundView) {
mContext = context;
mPluginRegistry = new FlutterPluginRegistry(this, context);
// 创建FlutterJNI实例
mFlutterJNI = new FlutterJNI();
mFlutterJNI.setRenderSurface(new RenderSurfaceImpl());
// 将PlatformMessageHandlerImpl实例赋值给FlutterJNI中的platformMessageHandler属性
mFlutterJNI.setPlatformMessageHandler(new PlatformMessageHandlerImpl());
mFlutterJNI.addEngineLifecycleListener(new EngineLifecycleListenerImpl());
attach(this, isBackgroundView);
assertAttached();
mMessageHandlers = new HashMap<>();
}

.......
}

在FlutterNativeView的构造函数中,首先创建FlutterJNI实例mFlutterJNI,然后调用setPlatformMessageHandler()并把PlatformMessageHandlerImpl实例作为参数传入.因此在FlutterJNI的handlePlatformMessage()方法中,最终调用PlatformMessageHandlerImpl实例的handleMessageFromDart()来处理来自Flutter中的消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class FlutterNativeView implements BinaryMessenger {
private final Map<String, BinaryMessageHandler> mMessageHandlers;

......

private final class PlatformMessageHandlerImpl implements PlatformMessageHandler {
// Called by native to send us a platform message.
public void handleMessageFromDart(final String channel, byte[] message, final int replyId) {
// 1.根据channel名称获取对应的BinaryMessageHandler对象.每个Channel对应一个
// Handler对象
BinaryMessageHandler handler = mMessageHandlers.get(channel);
if (handler != null) {
try {
// 2.将字节数组对象封装为ByteBuffer对象
final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
// 3.调用handler对象的onMessage()方法来分发消息
handler.onMessage(buffer, new BinaryReply() {
private final AtomicBoolean done = new AtomicBoolean(false);
@Override
public void reply(ByteBuffer reply) {
// 4.根据reply的情况,调用FlutterJNI中invokePlatformMessageXXX()方法将响应数据发送给Flutter层
if (reply == null) {
mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
} else {
mFlutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
}
}
});
} catch (Exception exception) {
mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
}
return;
}
mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
}
}

在FlutterNativeView中存在Map类型的成员变量mMessageHandler:以Channel名称作为key,以BinaryMessageHandler类型为value.在handleMessageFromDart()方法中,首先根据Channel名称从mMessageHandlers取出对应的二进制消息处理器BinaryMessageHandler,然后将字节数组message封装为ByteBuffer对象,然后调用BinaryMessageHandler实例的onMessage()方法处理ByteBuffer,并进行响应.

BinaryReply是一个接口,主要用来将ByteBuffer类型的响应数据reply从Java层写回到Flutter层.根据reply是否为null,调用FlutterJNI实例不同的方法:reply为null时,调用invokePlatformMessageEmptyResponseCallback();否则调用invokePlatformMessageResponseCallback().关于具体的实现流程,稍后再述.

现在来看下BinaryMessageHandler是如何添加到mMessageHandler中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FlutterNativeView implements BinaryMessenger {
private final Map<String, BinaryMessageHandler> mMessageHandlers;

......

@Override
public void setMessageHandler(String channel, BinaryMessageHandler handler) {
if (handler == null) {
mMessageHandlers.remove(channel);
} else {
mMessageHandlers.put(channel, handler);
}
}
.......
}

setMessageHandler()方法接受两个参数:channel作为Channel的名称,用来区分不同的Channel;handler是该Channel对应的二进制消息处理器.在该方法中,会根据handler是否为null来决定对mMessageHandlers是进行添加还是删除操作.那该方法什么时候回被调用呢?要想弄明白这个问题,需要了解编写平台Channel的过程.以官方获取Android平台电量的平台Channel为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MainActivity extends FlutterActivity {
// 1.定义Channel的名称,该名称作为Channel的唯一标识符
private static final String CHANNEL = "samples.flutter.io/battery";

@Override
public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
// 2.创建MethodChannel对象channel
MethodChannel channel = new MethodChannel(getFlutterView(), CHANNEL);
// 3.调用MethodChannel实例的setMethodCallHandler()方法为当前channel设置Handler
channel.setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
// TODO
}
});
}
}

在上述代码中,演示了编写平台代码的基本过程:首先创建MethodChanel实例,然后设置MethodCallHandler.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public final class MethodChannel {
// 二进制信使
private final BinaryMessenger messenger;
// Channel名称
private final String name;
// 方法编码
private final MethodCodec codec;

public MethodChannel(BinaryMessenger messenger, String name) {
this(messenger, name, StandardMethodCodec.INSTANCE);
}

public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
assert messenger != null;
assert name != null;
assert codec != null;
this.messenger = messenger;
this.name = name;
this.codec = codec;
}

......

public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
messenger.setMessageHandler(name,
handler == null ? null : new IncomingMethodCallHandler(handler));
}
......
}

在创建MethodChannel过程中需要指定三个参数:

  • name: Channel名称,用作唯一标识符.
  • codec: 用于方法编码的MethodCodec,.默认情况下,codec被指定为StandartMethodCodec.INSTANCE.
  • messager: 用于消息发送的BinaryMessager,

创建完MethodChannel后,接下来需要调用setMethodCallHandler()设置用于处理方法调用MethodCallHandler.在该方法参数handler不为null的情况下,会将该handler包装为IncomingMethodCallHandler实例,然后调用BinaryMessager实例的setMessageHanlder()方法将I该ncomingMethodCallHandler实例保存在FlutterNativeView中的mMessageHandlers中.

简单来说就是在编写平台Channel时,需要创建对应的MethodChannel实例,并调用其setMethodCallHandler()将MethodCallHandler实例保存起来.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public final class MethodChannel {

private final class IncomingMethodCallHandler implements BinaryMessageHandler {
private final MethodCallHandler handler;

IncomingMethodCallHandler(MethodCallHandler handler) {
this.handler = handler;
}

@Override
public void onMessage(ByteBuffer message, final BinaryReply reply) {
// 1.使用codec对来自Flutter方法调用数据进行解码,并将其封装为MethodCall对象.
// MethodCall中包含两部分数据:method表示要调用的方法;arguments表示方法所需参数
final MethodCall call = codec.decodeMethodCall(message);
try {
// 2.调用自定义MethodCallHandler中的onMethodCall方法继续处理方法调用
handler.onMethodCall(call, new Result() {
@Override
public void success(Object result) {
// 调用成功时,需要回传数据给Flutter层时,使用codec对回传数据result
// 进行编码
reply.reply(codec.encodeSuccessEnvelope(result));
}

@Override
public void error(String errorCode, String errorMessage, Object errorDetails) {
// 调用失败时,需要回传错误数据给Flutter层时,使用codec对errorCode,
// errorMessage,errorDetails进行编码
reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
}

@Override
public void notImplemented() {
// 方法没有实现时,调用该方法后,flutter将会受到相应的错误消息
reply.reply(null);
}
});
} catch (RuntimeException e) {
Log.e(TAG + name, "Failed to handle method call", e);
reply.reply(codec.encodeErrorEnvelope("error", e.getMessage(), null));
}
}
}
}

在上述代码中,首先使用codec对来自Flutter层的二进制数据进行解码,并将其封装为MethodCall对象,然后调用MethodCallHandler的onMethodCall()方法.

image-20190209115925942

.MethodCall中包含两部分数据:method部分表示要调用的方法;arguments表示被调用方法所需要的参数.

1
2
3
4
5
6
7
public final class MethodChannel {
.......
public interface MethodCallHandler {
void onMethodCall(MethodCall call, Result result);
}
.......
}

接下来便是调用自定义MethodCallHandler中的onMethodCall()方法,该方法接受两个参数:

  • call: MethodCall类型,它包含方法调用所需的信息

  • result: Result类型,用于处理方法调用结果

Result是一个回调接口,其定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
public final class MethodChannel {
.......
public interface Result {
// 方法调用处理成功时,调用success()
void success(@Nullable Object result);
// 方法调用处理失败时,调用error()
void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails);
// 方法调用遇到为定义的方法时,调用notImplemented()
void notImplemented();
}
.......
}

方法返回

Java -> Native

回到IncomingMethodCallHandler中的onMessage()中,我们看到在调用MethodCallHandler的onMethodCall()时,以匿名内部的形式实现了Result接口,而且在实现中又调用reply实例的reply()方法来把响应数据写会到Flutter层.reply是BinaryReply接口类型,其具体实现之前已经说过(即PlatformMessageHandlerImpl,在此就不做重复了.

当数据需要写回时,数据首先通过codec被编码成ByteBuffer类型,然后调用reply的reply()方法.在reply()方法中,对于非null类型的ByteBuffer,会调用FlutterJNI中的invokePlatformMessageResponseCallback()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class FlutterJNI {
private Long nativePlatformViewId;

......
@UiThread
public void invokePlatformMessageResponseCallback(int responseId, ByteBuffer message, int position) {
// 1.检查FlutterJNI是否已经attach到Native层,如若没有则抛出异常
ensureAttachedToNative();
// 2.继续调用nativeInvokePlatformMessageResponseCallback()
nativeInvokePlatformMessageResponseCallback(
nativePlatformViewId,
responseId,
message,
position
);
}

private native void nativeInvokePlatformMessageResponseCallback(
long nativePlatformViewId,
int responseId,
ByteBuffer message,
int position
);

......

private void ensureAttachedToNative() {
// FlutterJNI attach到Native层后,会返回一个long类型的值用来初始化nativePlatformViewId
if (nativePlatformViewId == null) {
throw new RuntimeException("Cannot execute operation because FlutterJNI is not attached to native.");
}
}

}

在上述invokePlatformMessageResponseCallback()方法中,首先检查当前FlutterJNI实例是否已经attach到Native层,然后调用Native方法nativeInvokePlatformMessageResponseCallback()向JNI层写入数据,该Native方法Native层的实现在platform_view_android.cc,其中参数responseId是之前Native层生成,又传至Java层的,现在有又需要将它传至Native层:

1
2
3
4
5
6
7
8
9
10
11
12
bool RegisterApi(JNIEnv* env) {
static const JNINativeMethod flutter_jni_methods[] = {
......
{
.name = "nativeInvokePlatformMessageResponseCallback",
.signature = "(JILjava/nio/ByteBuffer;I)V",
.fnPtr = reinterpret_cast<void*>(&shell::InvokePlatformMessageResponseCallback),
},
.......
}
.......
}

通过上述代码定义不难看出其最终实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void PlatformViewAndroid::InvokePlatformMessageResponseCallback(
JNIEnv* env,
jint response_id,
jobject java_response_data,
jint java_response_position) {
if (!response_id)
return;
// 1.通过response_id从pending_responses_中取出response
auto it = pending_responses_.find(response_id);
if (it == pending_responses_.end())
return;
// 2.GetDirectBufferAddress函数返回一个指向被传入的ByteBuffer对象的地址指针
uint8_t* response_data =
static_cast<uint8_t*>(env->GetDirectBufferAddress(java_response_data));
std::vector<uint8_t> response = std::vector<uint8_t>(
response_data, response_data + java_response_position);
auto message_response = std::move(it->second);
// 3.从pending_responses_中移除该response
pending_responses_.erase(it);
// 4.调用response的Complete()方法将二进制结果返回
message_response->Complete(
std::make_unique<fml::DataMapping>(std::move(response)));
}

在上述代码中,首先以response_id为key,从pending_responsed_取出对应response.然后通过GetDirectBufferAddress函数获取二进制响应数据java_response_data对象的指针,最后调用reponse的Complete()方法将二进制结果返回.

Native -> Dart

上文提到response是PlatformMessageResponseDart类型,简单看一下其Complete()方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) {
if (callback_.is_empty())
return;
FML_DCHECK(!is_complete_);
is_complete_ = true;
ui_task_runner_->PostTask(fml::MakeCopyable(
[callback = std::move(callback_), data = std::move(data)]() mutable {
std::shared_ptr<tonic::DartState> dart_state =
callback.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
// 将Native层的二进制数据data转为Dart中的二进制数据byte_buffer
Dart_Handle byte_buffer = WrapByteData(std::move(data));
tonic::DartInvoke(callback.Release(), {byte_buffer});
}));
}

在上述代码中,向ui_task_runner_添加了一个新的Task,在该Task中首先将Native层二进制数据转为Dart中的二进制数据,然后调用Dart中的callback将数据返回到Dart层.Dart层在接受到数据后,使用MethodCodec进行解码数据并将其返回到业务代码.

小结

上述以Dart作为发起方,完整梳理一次从Dart向Android平台发起方法调用(MethodCall)流程.实际MethodCall也支持以Android平台为发起方,通过MethodChannel调用Dart中的方法,对此就不做说明了.=

总结

目前为止,关于Platform Channel基本原理已经讲解完成,最后通过对MethodChannel工作原理进行分析来加深理解.对于IOS开发者而言,其原理实现类似.

总体而言,Flutter中实现跨平台通信的机制简单却高效,总体难度不大.最后祝大家新年快乐,人人都能拐卖小学妹😈(Flutter).

CATALOG
  1. 1. Platform Channel简介
    1. 1.1. Platform Channel基本结构
      1. 1.1.1. BasicMessageChannel
      2. 1.1.2. MethodChannel
      3. 1.1.3. EventChannel
    2. 1.2. name(Channel名称)
    3. 1.3. messager(信使)
    4. 1.4. Codec(编解码器)
      1. 1.4.1. MessageCodec
        1. 1.4.1.1. BinaryCodec
        2. 1.4.1.2. StringCodec
        3. 1.4.1.3. JSONMessageCodec
        4. 1.4.1.4. StandardMessageCodec
      2. 1.4.2. MethodCodec
        1. 1.4.2.1. JSONMethodCodec
        2. 1.4.2.2. StandardMethodCodec
      3. 1.4.3. 深入编解码器原理
  2. 2. Handler
    1. 2.1. MessageHandler
    2. 2.2. MethodCallHandler
    3. 2.3. StreamHandler
  3. 3. MethodChannel调用原理
    1. 3.1. 方法调用
      1. 3.1.1. Dart -> Native
      2. 3.1.2. Native -> Java
    2. 3.2. 方法返回
      1. 3.2.1. Java -> Native
      2. 3.2.2. Native -> Dart
    3. 3.3. 小结
  4. 4. 总结