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;
}
}
MethodChannel、BasicMessageChannel、EventChannel 结构来看,都是由name,messenger和codec三个属性字段组成
name:String 类型,唯一标识符代表 Channel 的名字,因为一个 Flutter 应用中存在多个 Channel,每个 Channel 在创建时必须指定一个独一无二的 name 作为标识
messenger:BinaryMessenger 类型,充当信使邮递员角色,消息的发送与接收工具人。
codec:MethodCodec 或MessageCodec<T>类型,充当消息的编解码器。
重点逻辑是messenger字段,看下BinaryMessenger定义
public interface BinaryMessenger {
public interface TaskQueue {}
@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 {
void reply(@Nullable ByteBuffer reply);
}
}
看下DartMessenger实现类
class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
@NonNull private final Map<String, HandlerInfo> messageHandlers = new HashMap<>();
@Override
public void setMessageHandler(
@NonNull String channel,
@Nullable BinaryMessenger.BinaryMessageHandler handler,
@Nullable TaskQueue taskQueue) {
......
List<BufferedMessageInfo> list;
synchronized (handlersLock) {
messageHandlers.put(channel, new HandlerInfo(handler, dartMessengerTaskQueue));
......
}
......
}
}
@Override
public void handleMessageFromDart(
@NonNull String channel, @Nullable ByteBuffer message, int replyId, long messageData) {
synchronized (handlersLock) {
handlerInfo = messageHandlers.get(channel);
messageDeferred = (enableBufferingIncomingMessages.get() && handlerInfo == null);
......
if (!messageDeferred) {
dispatchMessageToQueue(channel, handlerInfo, message, replyId, messageData);
}
}
private void dispatchMessageToQueue(
@NonNull String channel,
@Nullable HandlerInfo handlerInfo,
@Nullable ByteBuffer message,
int replyId,
long messageData) {
// Called from any thread.
final DartMessengerTaskQueue taskQueue = (handlerInfo != null) ? handlerInfo.taskQueue : null;
TraceSection.beginAsyncSection("PlatformChannel ScheduleHandler on " + channel, replyId);
Runnable myRunnable =
() -> {
TraceSection.endAsyncSection("PlatformChannel ScheduleHandler on " + channel, replyId);
try (TraceSection e =
TraceSection.scoped("DartMessenger#handleMessageFromDart on " + channel)) {
invokeHandler(handlerInfo, message, replyId);
if (message != null && message.isDirect()) {
// This ensures that if a user retains an instance to the ByteBuffer and it
// happens to be direct they will get a deterministic error.
message.limit(0);
}
} finally {
// This is deleting the data underneath the message object.
flutterJNI.cleanupMessageData(messageData);
}
};
final DartMessengerTaskQueue nonnullTaskQueue =
taskQueue == null ? platformTaskQueue : taskQueue;
nonnullTaskQueue.dispatch(myRunnable);
}
private void invokeHandler(
@Nullable HandlerInfo handlerInfo, @Nullable ByteBuffer message, final int replyId) {
// Called from any thread.
if (handlerInfo != null) {
try {
Log.v(TAG, "Deferring to registered handler to process message.");
handlerInfo.handler.onMessage(message, new Reply(flutterJNI, replyId));
} catch (Exception ex) {
Log.e(TAG, "Uncaught exception in binary message listener", ex);
flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
} catch (Error err) {
handleError(err);
}
} else {
Log.v(TAG, "No registered handler for message. Responding to Dart with empty reply message.");
flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
}
}
}
上面整体流程先注册handler,以channel name为key缓存到messageHandlers,等待
handleMessageFromDart(String channel, ByteBuffer message, int replyId, long messageData)
从Flutter端收到数据后,根据channel参数从messageHandlers获取到对应HandlerInfo对象,然后执行该队向的onMessage方法 handlerInfo.handler.onMessage(message, new Reply(flutterJNI, replyId));
这里可以先看下Reply对象,创建Reply对象保存replyId字段,后面用来回复Flutter。
static class Reply implements BinaryMessenger.BinaryReply {
@NonNull private final FlutterJNI flutterJNI;
private final int replyId;
private final AtomicBoolean done = new AtomicBoolean(false);
Reply(@NonNull FlutterJNI flutterJNI, int replyId) {
this.flutterJNI = flutterJNI;
this.replyId = replyId;
}
@Override
public void reply(@Nullable ByteBuffer reply) {
if (done.getAndSet(true)) {
throw new IllegalStateException("Reply already submitted");
}
if (reply == null) {
flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
} else {
flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
}
}
}
通过flutterJNI调用invokePlatformMessageResponseCallback发送到Flutter端
现在回过头继续跟踪setMessageHandler流程,前面提到channel有MethodChannel,EventChannel和BasicMessageChannel,分别看下它们是如何注册handler的,三种类型有啥不一样。
先看MethodChannel类型
public class MethodChannel {
private static final String TAG = "MethodChannel#";
private final BinaryMessenger messenger;
private final String name;
private final MethodCodec codec;
private final BinaryMessenger.TaskQueue taskQueue;
......
@UiThread
public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
// We call the 2 parameter variant specifically to avoid breaking changes in
// mock verify calls.
// See https://github.com/flutter/flutter/issues/92582.
if (taskQueue != null) {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingMethodCallHandler(handler), taskQueue);
} else {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingMethodCallHandler(handler));
}
}
......
}
注册的类型为IncomingMethodCallHandler,从Incoming名字看就是“接听”,用来处理Flutter端发送的数据。
private final class IncomingMethodCallHandler implements BinaryMessageHandler {
private final MethodCallHandler handler;
IncomingMethodCallHandler(MethodCallHandler handler) {
this.handler = handler;
}
@Override
@UiThread
public void onMessage(ByteBuffer message, final BinaryReply reply) {
final MethodCall call = codec.decodeMethodCall(message);
try {
handler.onMethodCall(
call,
new Result() {
@Override
public void success(Object result) {
reply.reply(codec.encodeSuccessEnvelope(result));
}
@Override
public void error(String errorCode, String errorMessage, Object errorDetails) {
reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
}
@Override
public void notImplemented() {
reply.reply(null);
}
});
} catch (RuntimeException e) {
Log.e(TAG + name, "Failed to handle method call", e);
reply.reply(
codec.encodeErrorEnvelopeWithStacktrace(
"error", e.getMessage(), null, Log.getStackTraceString(e)));
}
}
}
onMessage方法通过codec编码器将字节数组message转化成MethodCall对象,MethodCall对象里面包括方法名称和方法携带参数
再看EventChannel类型
public final class EventChannel {
private static final String TAG = "EventChannel#";
private final BinaryMessenger messenger;
private final String name;
private final MethodCodec codec;
@Nullable private final BinaryMessenger.TaskQueue taskQueue;
......
public void setStreamHandler(final StreamHandler handler) {
// We call the 2 parameter variant specifically to avoid breaking changes in
// mock verify calls.
// See https://github.com/flutter/flutter/issues/92582.
if (taskQueue != null) {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingStreamRequestHandler(handler), taskQueue);
} else {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingStreamRequestHandler(handler));
}
}
......
}
注册的类型为IncomingStreamRequestHandler,从Incoming名字看也是带“接听”,同样是用来处理Flutter端发送的数据。
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) {
final MethodCall call = codec.decodeMethodCall(message);
if (call.method.equals("listen")) {
onListen(call.arguments, reply);
} else if (call.method.equals("cancel")) {
onCancel(call.arguments, reply);
} else {
reply.reply(null);
}
}
}
IncomingStreamRequestHandler 的onMessage方法通过使用codec编码器将字节数组转成MethodCall对象,可以看到该对象只有listen和cancel两个方法,listen标识监听,cancel标识取消监听
最后再看BasicMessageChannel
public final class BasicMessageChannel<T> {
private static final String TAG = "BasicMessageChannel#";
public static final String CHANNEL_BUFFERS_CHANNEL = "dev.flutter/channel-buffers";
@NonNull private final BinaryMessenger messenger;
@NonNull private final String name;
@NonNull private final MessageCodec<T> codec;
@Nullable private final BinaryMessenger.TaskQueue taskQueue;
......
public void setMessageHandler(@Nullable final MessageHandler<T> handler) {
// We call the 2 parameter variant specifically to avoid breaking changes in
// mock verify calls.
// See https://github.com/flutter/flutter/issues/92582.
if (taskQueue != null) {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingMessageHandler(handler), taskQueue);
} else {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingMessageHandler(handler));
}
}
......
}
注册的类型为IncomingMessageHandler,名字依然带Incoming,同样是用来处理Flutter端发送的数据。
private final class IncomingMessageHandler implements BinaryMessageHandler {
private final MessageHandler<T> handler;
private IncomingMessageHandler(@NonNull MessageHandler<T> handler) {
this.handler = handler;
}
@Override
public void onMessage(@Nullable ByteBuffer message, @NonNull final BinaryReply callback) {
try {
handler.onMessage(
codec.decodeMessage(message),
new Reply<T>() {
@Override
public void reply(T reply) {
callback.reply(codec.encodeMessage(reply));
}
});
} catch (RuntimeException e) {
Log.e(TAG + name, "Failed to handle message", e);
callback.reply(null);
}
}
}
onMessage方法里面将message通过codec编码器转成T对应类型。
通过上面的代码跟踪,我们已经明了MethodChannel注册到messageHandlers里面的是IncomingMethodCallHandler,EventChannel注册的是IncomingStreamRequestHandler,BasicMessageChannel注册的是IncomingMessageHandler
MethodChannel | IncomingMethodCallHandler |
EventChannel | IncomingStreamRequestHandler |
BasicMessageChannel | IncomingMessageHandler |
我们继续跟踪IncomingMethodCallHandler,确认它是如何处理Flutter的方法调用
我们以官方的MouseCursorChannel为例,确认逻辑细节
public class MouseCursorChannel {
private static final String TAG = "MouseCursorChannel";
@NonNull public final MethodChannel channel;
@Nullable private MouseCursorMethodHandler mouseCursorMethodHandler;
public MouseCursorChannel(@NonNull DartExecutor dartExecutor) {
channel = new MethodChannel(dartExecutor, "flutter/mousecursor", StandardMethodCodec.INSTANCE);
channel.setMethodCallHandler(parsingMethodCallHandler);
}
/**
* Sets the {@link MouseCursorMethodHandler} which receives all events and requests that are
* parsed from the underlying platform channel.
*/
public void setMethodHandler(@Nullable MouseCursorMethodHandler mouseCursorMethodHandler) {
this.mouseCursorMethodHandler = mouseCursorMethodHandler;
}
@NonNull
private final MethodChannel.MethodCallHandler parsingMethodCallHandler =
new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (mouseCursorMethodHandler == null) {
// If no explicit mouseCursorMethodHandler has been registered then we don't
// need to forward this call to an API. Return.
return;
}
final String method = call.method;
Log.v(TAG, "Received '" + method + "' message.");
try {
// More methods are expected to be added here, hence the switch.
switch (method) {
case "activateSystemCursor":
@SuppressWarnings("unchecked")
final HashMap<String, Object> data = (HashMap<String, Object>) call.arguments;
final String kind = (String) data.get("kind");
try {
mouseCursorMethodHandler.activateSystemCursor(kind);
} catch (Exception e) {
result.error("error", "Error when setting cursors: " + e.getMessage(), null);
break;
}
result.success(true);
break;
default:
}
} catch (Exception e) {
result.error("error", "Unhandled error: " + e.getMessage(), null);
}
}
};
@VisibleForTesting
public void synthesizeMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
parsingMethodCallHandler.onMethodCall(call, result);
}
public interface MouseCursorMethodHandler {
// Called when the pointer should start displaying a system mouse cursor
// specified by {@code shapeCode}.
public void activateSystemCursor(@NonNull String kind);
}
}
可以看到,真正干活的handler就是parsingMethodCallHandler,它里面复写了onMethodCall方法,从源码可以看出支持方法名activateSystemCursor,执行完成后通过result.success(true)回调回去,这里的result就是前面的Result
public void onMessage(ByteBuffer message, final BinaryReply reply) {
final MethodCall call = codec.decodeMethodCall(message);
try {
handler.onMethodCall(
call,
new Result() {
@Override
public void success(Object result) {
reply.reply(codec.encodeSuccessEnvelope(result));
}
@Override
public void error(String errorCode, String errorMessage, Object errorDetails) {
reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
}
@Override
public void notImplemented() {
reply.reply(null);
}
});
} catch (RuntimeException e) {
Log.e(TAG + name, "Failed to handle method call", e);
reply.reply(
codec.encodeErrorEnvelopeWithStacktrace(
"error", e.getMessage(), null, Log.getStackTraceString(e)));
}
}
result接收到success回调后,通过reply.reply 回调给Flutter层。
这样就明确了,Android从Flutter端收到数据后,执行完对应方法后,再通过reply通过FlutterJNI发送到Flutter,这样一个调用回路就形成了。
EventChannel和BasicMessageChannel逻辑也是类似,这里就不再赘述,大家可以查阅源码进行分析。
上面的整个流程都是Flutter调用Android原生的方法流程,接下来我们跟踪下Android如何Flutter的方法
我们以NavigationChannel为例,看看它是如何调用的
public void pushRoute(@NonNull String route) {
Log.v(TAG, "Sending message to push route '" + route + "'");
channel.invokeMethod("pushRoute", route);
}
@UiThread
public void invokeMethod(@NonNull String method, @Nullable Object arguments) {
invokeMethod(method, arguments, null);
}
@UiThread
public void invokeMethod(
@NonNull String method, @Nullable Object arguments, @Nullable Result callback) {
messenger.send(
name,
codec.encodeMethodCall(new MethodCall(method, arguments)),
callback == null ? null : new IncomingResultHandler(callback));
}
@Override
public void send(
@NonNull String channel,
@Nullable ByteBuffer message,
@Nullable BinaryMessenger.BinaryReply callback) {
try (TraceSection e = TraceSection.scoped("DartMessenger#send on " + channel)) {
Log.v(TAG, "Sending message with callback over channel '" + channel + "'");
int replyId = nextReplyId++;
if (callback != null) {
pendingReplies.put(replyId, callback);
}
if (message == null) {
flutterJNI.dispatchEmptyPlatformMessage(channel, replyId);
} else {
flutterJNI.dispatchPlatformMessage(channel, message, message.position(), replyId);
}
}
}
跟踪源码,我们看到最后是通过flutterJNI调用了dispatchPlatformMessage方法发送到了Flutter层。
Android原生MethodChannel整体调用流程如下图
接下来我们根据下MethodChannel里面的codec编码器是如何工作的。
我们可以看到MethodChannel里面的codec是MethodCodec类型。
public interface MethodCodec {
@NonNull
ByteBuffer encodeMethodCall(@NonNull MethodCall methodCall);
@NonNull
MethodCall decodeMethodCall(@NonNull ByteBuffer methodCall);
@NonNull
ByteBuffer encodeSuccessEnvelope(@Nullable Object result);
@NonNull
ByteBuffer encodeErrorEnvelope(
@NonNull String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails);
@NonNull
ByteBuffer encodeErrorEnvelopeWithStacktrace(
@NonNull String errorCode,
@Nullable String errorMessage,
@Nullable Object errorDetails,
@Nullable String errorStacktrace);
@NonNull
Object decodeEnvelope(@NonNull ByteBuffer envelope);
}
这里一般使用的是StandardMethodCodec类型。
public final class StandardMethodCodec implements MethodCodec {
public static final StandardMethodCodec INSTANCE =
new StandardMethodCodec(StandardMessageCodec.INSTANCE);
private final StandardMessageCodec messageCodec;
/** Creates a new method codec based on the specified message codec. */
public StandardMethodCodec(@NonNull StandardMessageCodec messageCodec) {
this.messageCodec = messageCodec;
}
@Override
@NonNull
public ByteBuffer encodeMethodCall(@NonNull MethodCall methodCall) {
final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
messageCodec.writeValue(stream, methodCall.method);
messageCodec.writeValue(stream, methodCall.arguments);
final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
buffer.put(stream.buffer(), 0, stream.size());
return buffer;
}
@Override
@NonNull
public MethodCall decodeMethodCall(@NonNull ByteBuffer methodCall) {
methodCall.order(ByteOrder.nativeOrder());
final Object method = messageCodec.readValue(methodCall);
final Object arguments = messageCodec.readValue(methodCall);
if (method instanceof String && !methodCall.hasRemaining()) {
return new MethodCall((String) method, arguments);
}
throw new IllegalArgumentException("Method call corrupted");
}
}
可以看到encodeMethodCall将MethodCall对象编码成字节数组,decodeMethodCall将字节数组转化成MethodCall对象。这里的核心算法是通过messageCodec writeValue和readValue转化。
protected void writeValue(@NonNull ByteArrayOutputStream stream, @Nullable Object value) {
if (value == null || value.equals(null)) {
stream.write(NULL);
} else if (value instanceof Boolean) {
stream.write(((Boolean) value).booleanValue() ? TRUE : FALSE);
} else if (value instanceof Number) {
if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
stream.write(INT);
writeInt(stream, ((Number) value).intValue());
} else if (value instanceof Long) {
stream.write(LONG);
writeLong(stream, (long) value);
} else if (value instanceof Float || value instanceof Double) {
stream.write(DOUBLE);
writeAlignment(stream, 8);
writeDouble(stream, ((Number) value).doubleValue());
} else if (value instanceof BigInteger) {
stream.write(BIGINT);
writeBytes(stream, ((BigInteger) value).toString(16).getBytes(UTF8));
} else {
throw new IllegalArgumentException("Unsupported Number type: " + value.getClass());
}
} else if (value instanceof CharSequence) {
stream.write(STRING);
writeBytes(stream, value.toString().getBytes(UTF8));
} else if (value instanceof byte[]) {
stream.write(BYTE_ARRAY);
writeBytes(stream, (byte[]) value);
} else if (value instanceof int[]) {
stream.write(INT_ARRAY);
final int[] array = (int[]) value;
writeSize(stream, array.length);
writeAlignment(stream, 4);
for (final int n : array) {
writeInt(stream, n);
}
} else if (value instanceof long[]) {
stream.write(LONG_ARRAY);
final long[] array = (long[]) value;
writeSize(stream, array.length);
writeAlignment(stream, 8);
for (final long n : array) {
writeLong(stream, n);
}
} else if (value instanceof double[]) {
stream.write(DOUBLE_ARRAY);
final double[] array = (double[]) value;
writeSize(stream, array.length);
writeAlignment(stream, 8);
for (final double d : array) {
writeDouble(stream, d);
}
} else if (value instanceof List) {
stream.write(LIST);
final List<?> list = (List) value;
writeSize(stream, list.size());
for (final Object o : list) {
writeValue(stream, o);
}
} else if (value instanceof Map) {
stream.write(MAP);
final Map<?, ?> map = (Map) value;
writeSize(stream, map.size());
for (final Entry<?, ?> entry : map.entrySet()) {
writeValue(stream, entry.getKey());
writeValue(stream, entry.getValue());
}
} else if (value instanceof float[]) {
stream.write(FLOAT_ARRAY);
final float[] array = (float[]) value;
writeSize(stream, array.length);
writeAlignment(stream, 4);
for (final float f : array) {
writeFloat(stream, f);
}
} else {
throw new IllegalArgumentException(
"Unsupported value: '" + value + "' of type '" + value.getClass() + "'");
}
}
可以看到写入到字节流时,先写入类型,再写入数据,类型固定占一个字节。
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;
private static final byte FLOAT_ARRAY = 14;
我们追踪下字符串如何写入
if (value instanceof CharSequence) {
stream.write(STRING);
writeBytes(stream, value.toString().getBytes(UTF8));
}
-------------------------------------------------------------------------
protected static final void writeBytes(
@NonNull ByteArrayOutputStream stream, @NonNull byte[] bytes) {
writeSize(stream, bytes.length);
stream.write(bytes, 0, bytes.length);
}
先写入STRING类型,再写入字符串的长度,再写入字符串内容。
现在我们已经明确了,通过类型+(数据长度)+数据就能将方法进行编码,响应的我们根据这个规则就可以将字节数据进行解码,获得方法名和参数类型。
类型 | 数据长度 | 数据 | ...... |
从上面也能看到,这里不支持自定义类型,只支持普通数据类型。