flutter的android平台的通讯Channel大致有三种。
Name |
Function |
BasicMessageChannel |
用于简单的数据传递 |
MethodChannel |
传递一个方法名和参数来完成通讯 |
EventChannel |
类似于长连接的通讯 |
每个Channel都会配置一个Codec,用于通讯数据的编解码。Flutter的平台通讯方式采用了二进制协议,图中的
MethodCodec和MessageCodec的实现者都是采用了字节写入写出完成数据的编解码。
MessageCodec完成基础的编解码,MethodCodec在MessageCodec的基础上进一步完成方法名字的编解码。
MessageCodec目前的实现类有四个,BinaryCodec基本不做操作,直接将获得的字节数据返回;StringCodec完成
字节和字符串的转化;JSONMessageCodec完成Json结构的字符串与字节之间转化;而StandardMessageCodec采用了
更加细分的规则。
总的来说参数传递时都是只支持基本数据类型和List与Map类型的数据,只不过StandardMessageCodec比
其他的Codec更加精准,StandardMessageCodec能根据数字编号直接确定当前读到的字节数据是何种类型。
如图中所示,一串数据,开头字节表示为类型type,然后才是数据本体,比如当前type表示为Int型数据,那么在取数据时
直接以int形式的方式将data取出。
而MethodCodec先将方法名取出,然后将参数取出,实际还是由MessageCodec来处理。
在Flutter android中真正完成数据收发的是DartMessenger,DartMessenger包含了两个回调集合,一个关于BinaryMessageHandler
的回调集合用于接收来自Flutter的主动调用,一个BinaryReply集合用于接收Flutter对于平台调用的响应,当然BinaryMessageHandler
是需要事先完成注册的,这样Flutter调用原生时才不会扑空。
通讯流程
有了对通道的一个初步认识,现在我们继续来看,Flutter如何实现平台通讯的。
注册
如果Flutter想要调用android平台上一个功能,android就必须实现注册一个接收器,这个接收器就是BinaryMessageHandler。android 平台
事先会将自己定义的Channel进行注册,这里我们选择MethodChannel。并且实现了一个FlutterPlugin 插件,继承于MethodCallHandler。
注册名字就是 flutter_plugin。
1
2
|
MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_plugin");
channel.setMethodCallHandler(new FlutterPlugin());
|
调用了setMethodCallHandler之后会封装一个BinaryMessageHandler。
1
2
3
4
5
6
7
8
9
10
11
|
public final class MethodChannel {
...
public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) {
this.messenger.setMessageHandler(this.name, handler == null ? null : new MethodChannel.IncomingMethodCallHandler(handler));
}
...
private final class IncomingMethodCallHandler implements BinaryMessageHandler {
...
}
...
}
|
最重会调用到DartMessenger的setMessageHandler,根据注册名字来完成注册。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
...
private final Map<String, BinaryMessageHandler> messageHandlers;
...
public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessageHandler handler) {
if (handler == null) {
this.messageHandlers.remove(channel);
} else {
this.messageHandlers.put(channel, handler);
}
}
...
}
|
调用
完成注册之后,从Flutter发起调用。由Dart完成调用逻辑,Dart也实现了跟Java层一样的对接接口,
调用了MethodChannel来完成分发。在MethodChannel中调用codec将参数封装成二进制数据,然后调用
binaryMessenger发送。这里属于异步调用,可以直接将任务的Future返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) async {
assert(method != null);
//发送
final ByteData result = await binaryMessenger.send(
name,
//封装数据
codec.encodeMethodCall(MethodCall(method, arguments)),
);
if (result == null) {
throw MissingPluginException('No implementation found for method $method on channel $name');
}
final T typedResult = codec.decodeEnvelope(result);
return typedResult;
}
|
在Dart层代码中binaryMessenger的实现者目前只有_DefaultBinaryMessenger,_DefaultBinaryMessenger
关于发送的逻辑的实现如下,并且设置了相应的回调。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class _DefaultBinaryMessenger extends BinaryMessenger {
...
Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
final Completer<ByteData> completer = Completer<ByteData>();
//最终调用了window的发送渠道
ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
...
completer.complete(reply);
...
});
return completer.future;
}
...
@override
Future<ByteData> send(String channel, ByteData message) {
...
return _sendPlatformMessage(channel, message);
}
...
}
|
在window的实现中最终调用了native层的代码
1
2
3
4
|
//window.dart
String _sendPlatformMessage(String name,
PlatformMessageResponseCallback callback,
ByteData data) native 'Window_sendPlatformMessage';
|
Window_sendPlatformMessage 这个标示是在Engine层事先注册过的。
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
|
//window.cc
Dart_Handle SendPlatformMessage(Dart_Handle window,
const std::string& name,
Dart_Handle callback,
const tonic::DartByteData& data) {
...
dart_state->window()->client()->HandlePlatformMessage(
fml::MakeRefCounted<PlatformMessage>(
name, std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()),
response));
...
}
void _SendPlatformMessage(Dart_NativeArguments args) {
tonic::DartCallStatic(&SendPlatformMessage, args);
}
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},
});
}
|
这里有个client的转发,具体的关联如下图。
最终会分发到PlatformViewAndroid的HandlePlatformMessage上,之后就会使用JNI技术传给Java
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
|
void PlatformViewAndroid::HandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message) {
...
FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),
nullptr, response_id);
...
}
}
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_flutter_jni_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
env, env->FindClass("io/flutter/embedding/engine/FlutterJNI"));
...
g_handle_platform_message_method =
env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
"(Ljava/lang/String;[BI)V");
...
|
上边代码显示,最终java层的FlutterJNI类的handlePlatformMessage方法会被调用。
1
2
3
4
5
6
7
8
9
10
|
public class FlutterJNI {
...
private void handlePlatformMessage(@NonNull String channel, byte[] message, int replyId) {
if (this.platformMessageHandler != null) {
this.platformMessageHandler.handleMessageFromDart(channel, message, replyId);
}
}
...
}
|
继续分发,会给到platformMessageHandler调用。platformMessageHandler其实就是DartMessenger。
1
2
3
4
5
6
7
8
9
10
|
class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
public void handleMessageFromDart(@NonNull String channel, @Nullable byte[] message, int replyId) {
BinaryMessageHandler handler = (BinaryMessageHandler)this.messageHandlers.get(channel);
...
ByteBuffer buffer = message == null ? null : ByteBuffer.wrap(message);
handler.onMessage(buffer, new DartMessenger.Reply(this.flutterJNI, replyId));
...
}
}
|
这里会取出之前注册时 ,相应的名字对应的BinaryMessageHandler,这个BinaryMessageHandler应该时MethodChannel中实现的
IncomingMethodCallHandler,而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 class IncomingMethodCallHandler implements BinaryMessageHandler {
private final MethodChannel.MethodCallHandler handler;
IncomingMethodCallHandler(MethodChannel.MethodCallHandler handler) {
this.handler = handler;
}
@UiThread
public void onMessage(ByteBuffer message, final BinaryReply reply) {
MethodCall call = MethodChannel.this.codec.decodeMethodCall(message);
...
this.handler.onMethodCall(call, new MethodChannel.Result() {
public void success(Object result) {
reply.reply(MethodChannel.this.codec.encodeSuccessEnvelope(result));
}
public void error(String errorCode, String errorMessage, Object errorDetails) {
reply.reply(MethodChannel.this.codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
}
public void notImplemented() {
reply.reply((ByteBuffer)null);
}
});
...
}
}
}
|
只这里就完成了调用过程,下面就是回传过程。
回传