哈嘍大家好,新年又見面了郁季,不知道大家有沒有想我呢烙荷,我可是一有空就想著為大家更新博客呢??,上一期給大家分享了 <Flutter運行原理篇之paint重繪原理> 巾陕,本來說這期應(yīng)該是接上一期分享 <Flutter運行原理篇之Compose合成原理的>,但是今天咋們插入一篇《從Platform到Dart通信原理分析之Android篇》來說一說從Native也就是PlatForm端到Dart的通信原理,這個也是我一直都想寫的內(nèi)容了鄙煤,好了讓我們愉快的開始吧
其實經(jīng)常逛論壇的都知道已經(jīng)有一些文章分析過了這個的運行原理了為什么我還要寫呢晾匠,
一個我覺得他們水平?jīng)]有問題但是博客里面有一些小的漏洞,小瑕疵作為有潔癖梯刚,不將就的工程師混聊,大家肯定不是很滿意
第二也是最關(guān)鍵的一點就是那些文章基本上是一氣呵成的要不就是作者沒有設(shè)計到更深入的層次去分析,而是點到而止就“打道回府”了乾巧,要么就是水平很高但是內(nèi)容不夠詳細(xì)豐富,特別是不夠通俗易懂的去給講解预愤,導(dǎo)致大家看了他們寫的文章以后有一種“失落”的感覺沟于,覺得大致都能看懂但就是理解不了什么意思,于是就有了我們今天這篇文章植康,看我能不能帶著大家 通·俗·易·懂· 的去理解一下這個原理的過程旷太,我保證絕對會讓大家看完以后長舒一口氣感嘆:“原來原理就是這么的‘簡單’啊”,希望大家在末尾給我評論留言销睁,every body let’s go
說到了運行原理供璧,那么我們就帶大家來復(fù)習(xí)一下從Platform到Dart的使用會基本用到的幾個類,來作為文章的預(yù)熱:首先我們要知道的是一般來說Native到Flutter端相互通信有三種調(diào)用的方式冻记,也就是三種不同的Channel睡毒,兩端通過同一個Channel來進(jìn)行互相的通信,分別是一下三個Channel:
- BasicMessageChannel:用于傳遞字符串和半結(jié)構(gòu)化的信息冗栗。
- MethodChannel:用于傳遞方法調(diào)用(method invocation)演顾。
- EventChannel: 用于數(shù)據(jù)流(event streams)的通信。
三種Channel之間互相獨立隅居,各有用途钠至,但它們在設(shè)計上卻非常相近,所以我們分析的時候可能就只會分析幾種情況即可胎源,不會所有的情況都分析到
好了說了這么多棉钧,咋們再來看看這三個通道的基本使用:MethodChanel,BasicMessageChannel涕蚤,EventChannel這三個通道在Dart端以及Platform端都有對應(yīng)相同名字的類來作為雙方通信/接收的使用宪卿,我們以BasicMessageChannel來舉例子:Dart端以及Android端首先都需要實例化這個Channel并且名字也要一樣,并且都需要提供一個send發(fā)送方法赞季,以及一個接收的方法來作為監(jiān)聽愧捕,例如:
BasicMessageChannel Dart端代碼片段:
//初始化
static const BasicMessageChannel<String> _basicMessageChannel =
const BasicMessageChannel('BasicMessageChannelPlugin', StringCodec());
//設(shè)置監(jiān)聽函數(shù)
_basicMessageChannel
.setMessageHandler((String message) => Future<String>(() {
setState(() {
showMessage = 'BasicMessageChannel:'+message;
});
return "收到Native的消息ab:" + message;
}));
//向Native端發(fā)送消息
response = await _basicMessageChannel.send(value);
BasicMessageChannel Android端代碼片段:
//初始化
this.messageChannel = new BasicMessageChannel<>(messenger, "BasicMessageChannelPlugin", StringCodec.INSTANCE);
//設(shè)置監(jiān)聽函數(shù)
@Override
public void onMessage(String s, BasicMessageChannel.Reply<String> reply) {//處理Dart發(fā)來的消息
reply.reply("BasicMessageChannel收到:" + s);//可以通過reply進(jìn)行回復(fù)
if (activity instanceof IShowMessage) {
((IShowMessage) activity).onShowMessage(s);
}
Toast.makeText(activity, s, Toast.LENGTH_SHORT).show();
}
//向Dart端發(fā)送消息
messageChannel.send(message, callback);
好了,使用就是這么簡單申钩,我們現(xiàn)從雙方的構(gòu)造方法開始說起次绘,不論是Dart端還是Native端的構(gòu)造函數(shù)都需要這三個元素:
- name: String類型,代表Channel的名字,也是其唯一標(biāo)識符邮偎。
- messager:BinaryMessenger類型管跺,代表消息信使,是消息的發(fā)送與接收的工具禾进。
- codec: MessageCodec類型或MethodCodec類型豁跑,代表消息的編解碼器。
Channel name
一個Flutter應(yīng)用中可能存在多個不同的Channel泻云,每個Channel在創(chuàng)建時必須指定一個獨一無二的name艇拍,Channel之間使用name來區(qū)分彼此,當(dāng)有消息從Flutter端發(fā)送到Native端時會根據(jù)其傳遞過來的channel name找到該Channel對應(yīng)的Handler(消息處理器)消息信使:BinaryMessenger
雖然三種Channel各有用途宠纯,但是他們與Flutter通信的工具卻是相同的卸夕,均為BinaryMessager,在Dart端默認(rèn)是_DefaultBinaryMessenger婆瓜,在Android端默認(rèn)是DartExecutor
- MessageCodec
MessageCodec用于二進(jìn)制格式數(shù)據(jù)與基礎(chǔ)數(shù)據(jù)之間的編解碼快集,BasicMessageChannel所使用的編解碼器默認(rèn)就是MessageCodec
我們重點看看后面兩個,先來看看BinaryMessager的使用:
BinaryMessager:
在Dart端默認(rèn)是_DefaultBinaryMessenger
class _DefaultBinaryMessenger extends BinaryMessenger {
}
在Android端默認(rèn)是DartExecutor
public class DartExecutor implements BinaryMessenger {
private static final String TAG = "DartExecutor";
}
BinaryMessenger是Platform端與Flutter端通信的中間人廉白,其通信使用的消息格式為二進(jìn)制格式數(shù)據(jù)(理解這個很重要个初,這個也是數(shù)據(jù)傳遞的核心),當(dāng)我們初始化一個Channel猴蹂,并向該Channel注冊處理消息的Handler時院溺,實際上會生成一個與之對應(yīng)的BinaryMessageHandler,并以channel name為key晕讲,注冊到BinaryMessenger中:
Android的注冊步驟:
public class EventChannelPlugin implements EventChannel.StreamHandler {
private EventChannel.EventSink eventSink;
static EventChannelPlugin registerWith(BinaryMessenger messenger) {
EventChannelPlugin plugin = new EventChannelPlugin();
new EventChannel(messenger, "EventChannelPlugin").setStreamHandler(plugin);
return plugin;
}
}
Android的messenger 默認(rèn)是DartExecutor
public void setStreamHandler(final StreamHandler handler) {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingStreamRequestHandler(handler));
}
最終是存在DartMessenger里面的messageHandlers Map里面
class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
private static final String TAG = "DartMessenger";
@NonNull private final FlutterJNI flutterJNI;
@NonNull private final Map<String, BinaryMessenger.BinaryMessageHandler> messageHandlers;
@NonNull private final Map<Integer, BinaryMessenger.BinaryReply> pendingReplies;
private int nextReplyId = 1;
DartMessenger(@NonNull FlutterJNI flutterJNI) {
this.flutterJNI = flutterJNI;
this.messageHandlers = new HashMap<>();
this.pendingReplies = new HashMap<>();
}
@Override
public void setMessageHandler(
@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
if (handler == null) {
Log.v(TAG, "Removing handler for channel '" + channel + "'");
messageHandlers.remove(channel);
} else {
Log.v(TAG, "Setting handler for channel '" + channel + "'");
messageHandlers.put(channel, handler);
}
}
}
差不多就是這兩個方法了覆获,很簡單不再贅述,好了再說回來我們再看看Dart方面的BinaryMessenger與BinaryMessageHandler是怎么樣的呢瓢省,上面說了BinaryMessenger默認(rèn)是_DefaultBinaryMessenger弄息,我們來看看他的注冊setMessageHandler方法:
BasicMessageChannel.setMessageHandler:
/// Sets a callback for receiving messages from the platform plugins on this
/// channel. Messages may be null.
///
/// The given callback will replace the currently registered callback for this
/// channel, if any. To remove the handler, pass null as the `handler`
/// argument.
///
/// The handler's return value is sent back to the platform plugins as a
/// message reply. It may be null.
void setMessageHandler(Future<T> Function(T? message)? handler) {
if (handler == null) {
binaryMessenger.setMessageHandler(name, null);
} else {
binaryMessenger.setMessageHandler(name, (ByteData? message) async {
return codec.encodeMessage(await handler(codec.decodeMessage(message)));
});
}
}
_DefaultBinaryMessenger.setMessageHandler:
@override
void setMessageHandler(String channel, MessageHandler? handler) {
if (handler == null) {
_handlers.remove(channel);
} else {
_handlers[channel] = handler;
ui.channelBuffers.drain(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
await handlePlatformMessage(channel, data, callback);
});
}
}
把MessageHandler存在了 static final Map<String, MessageHandler> _handlers = <String, MessageHandler>{}; 之中
上面說的是注冊,我們看看監(jiān)聽是什么樣子的:
當(dāng)Dart端發(fā)送消息到Android端的BinaryMessenger時勤婚,BinaryMessenger會根據(jù)其入?yún)hannel找到對應(yīng)的BinaryMessageHandler摹量,并交由其處理,我們看看Android端是什么樣的
DartMessenger.handleMessageFromDart
@Override
public void handleMessageFromDart(
@NonNull final String channel, @Nullable byte[] message, final int replyId) {
Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
if (handler != null) {
try {
Log.v(TAG, "Deferring to registered handler to process message.");
final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
handler.onMessage(buffer, 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);
}
}
他會通過messageHandlers取出來對應(yīng)的BinaryMessageHandler馒胆,調(diào)用其注冊的onMessage方法(如果忘記了使用的話缨称,可以往上查看Android端的使用步驟)
現(xiàn)在再去看看當(dāng)Android端發(fā)送消息到Dart端的BinaryMessenger時他的處理是怎么樣的呢:
@override
Future<void> handlePlatformMessage(
String channel,
ByteData? data,
ui.PlatformMessageResponseCallback? callback,
) async {
ByteData? response;
try {
final MessageHandler? handler = _handlers[channel];
if (handler != null) {
response = await handler(data);
} else {
ui.channelBuffers.push(channel, data, callback!);
callback = null;
}
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('during a platform message callback'),
));
} finally {
if (callback != null) {
callback(response);
}
}
}
在Dart端通過也是根據(jù)channel的名字從_handlers取出MessageHandler直接調(diào)用await handler(data); 方法,等待監(jiān)聽方法返回數(shù)據(jù)然后再通過callback傳回給Android端
好了上面我們看了Android與Dart兩端簡單注冊以及收發(fā)消息的步驟祝迂,現(xiàn)在我們再來看看上面提到的另一個元素編解碼器Codec:
MessageCodec:
MessageCodec用于二進(jìn)制格式數(shù)據(jù)與基礎(chǔ)數(shù)據(jù)之間的編解碼睦尽,BasicMessageChannel所使用的編解碼器默認(rèn)就是MessageCodec,MessageCodec有多種不同的實現(xiàn)型雳,分為以下幾種:
- BinaryCodec
BinaryCodec是最為簡單的一種Codec当凡,因為其返回值類型和入?yún)⒌念愋拖嗤胶Γ鶠槎M(jìn)制格式(Android中為ByteBuffer,iOS中為NSData)實際上沿量,BinaryCodec在編解碼過程中什么都沒做浪慌,只是原封不動將二進(jìn)制數(shù)據(jù)消息返回而已,或許你會因此覺得BinaryCodec沒有意義朴则,但是在某些情況下它非常有用权纤,比如使用BinaryCodec可以使傳遞內(nèi)存數(shù)據(jù)塊時在編解碼階段免于內(nèi)存拷貝
Android部分
public final class BinaryCodec implements MessageCodec<ByteBuffer> {
// This codec must match the Dart codec of the same name in package flutter/services.
public static final BinaryCodec INSTANCE = new BinaryCodec();
private BinaryCodec() {}
@Override
public ByteBuffer encodeMessage(ByteBuffer message) {
return message;
}
@Override
public ByteBuffer decodeMessage(ByteBuffer message) {
return message;
}
}
Dart部分
class BinaryCodec implements MessageCodec<ByteData> {
/// Creates a [MessageCodec] with unencoded binary messages represented using
/// [ByteData].
const BinaryCodec();
@override
ByteData? decodeMessage(ByteData? message) => message;
@override
ByteData? encodeMessage(ByteData? message) => message;
}
都是直接返回數(shù)據(jù),代碼太簡單不解釋了
- StringCodec
StringCodec用于字符串與二進(jìn)制數(shù)據(jù)之間的編解碼乌妒,其編碼格式默認(rèn)為UTF-8 :
Dart部分
class StringCodec implements MessageCodec<String> {
/// Creates a [MessageCodec] with UTF-8 encoded String messages.
const StringCodec();
@override
String? decodeMessage(ByteData? message) {
if (message == null)
return null;
return utf8.decoder.convert(message.buffer.asUint8List(message.offsetInBytes, message.lengthInBytes));
}
@override
ByteData? encodeMessage(String? message) {
if (message == null)
return null;
final Uint8List encoded = utf8.encoder.convert(message);
return encoded.buffer.asByteData();
}
}
Android部分
public final class StringCodec implements MessageCodec<String> {
private static final Charset UTF8 = Charset.forName("UTF8");
public static final StringCodec INSTANCE = new StringCodec();
private StringCodec() {}
@Override
public ByteBuffer encodeMessage(String message) {
if (message == null) {
return null;
}
// TODO(mravn): Avoid the extra copy below.
final byte[] bytes = message.getBytes(UTF8);
final ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
buffer.put(bytes);
return buffer;
}
@Override
public String decodeMessage(ByteBuffer message) {
if (message == null) {
return null;
}
final byte[] bytes;
final int offset;
final int length = message.remaining();
if (message.hasArray()) {
bytes = message.array();
offset = message.arrayOffset();
} else {
// TODO(mravn): Avoid the extra copy below.
bytes = new byte[length];
message.get(bytes);
offset = 0;
}
return new String(bytes, offset, length, UTF8);
}
}
StringCodec默認(rèn)都是UTF8進(jìn)行編解碼汹想,代碼也很簡單不詳細(xì)敘述
- JSONMessageCodec
JSONMessageCodec用于基礎(chǔ)數(shù)據(jù)與二進(jìn)制數(shù)據(jù)之間的編解碼,其支持基礎(chǔ)數(shù)據(jù)類型以及列表撤蚊、字典欧宜,在Android端則使用了其自定義的JSONTokener與StringCodec作為序列化工具。
Android部分 JsonCodec.encode / JsonCodec.decode
class JSONMessageCodec implements MessageCodec<Object?> {
// The codec serializes messages as defined by the JSON codec of the
// dart:convert package. The format used must match the Android and
// iOS counterparts.
/// Creates a [MessageCodec] with UTF-8 encoded JSON messages.
const JSONMessageCodec();
@override
ByteData? encodeMessage(Object? message) {
if (message == null)
return null;
return const StringCodec().encodeMessage(json.encode(message));
}
@override
dynamic decodeMessage(ByteData? message) {
if (message == null)
return message;
return json.decode(const StringCodec().decodeMessage(message)!);
}
}
Dart部分 JsonCodec.encode / JsonCodec.decode
String encode(Object? value, {Object? toEncodable(dynamic object)?}) {
toEncodable ??= _toEncodable;
if (toEncodable == null) return encoder.convert(value);
return JsonEncoder(toEncodable).convert(value);
}
dynamic decode(String source,
{Object? reviver(Object? key, Object? value)?}) {
reviver ??= _reviver;
if (reviver == null) return decoder.convert(source);
return JsonDecoder(reviver).convert(source);
}
Dart與Android部分原理是一樣的拴魄,編碼首先通過JsonCodec.encode進(jìn)行編碼,然后再通過StringCodec 編碼成ByteData席镀;解碼部分首先通過StringCodec解碼成字符串再通過JsonCodec.decode解碼Json字符串
- StandardMessageCodec
StandardMessageCodec是BasicMessageChannel的默認(rèn)編解碼器匹中,常見類型基本上都支持,使用方式稍微復(fù)雜一點我們重點介紹下
Dart部分StandardMessageCodec.encodeMessage / StandardMessageCodec.decodeMessage
@override
ByteData? encodeMessage(Object? message) {
if (message == null)
return null;
final WriteBuffer buffer = WriteBuffer();
writeValue(buffer, message);
return buffer.done();
}
@override
dynamic decodeMessage(ByteData? message) {
if (message == null)
return null;
final ReadBuffer buffer = ReadBuffer(message);
final Object? result = readValue(buffer);
if (buffer.hasRemaining)
throw const FormatException('Message corrupted');
return result;
}
Dart端通過WriteBuffer豪诲,ReadBuffer作為字符的基本寫入與讀取的數(shù)據(jù)結(jié)構(gòu)的封裝顶捷,然后通過writeValue,readValue寫入以及讀取數(shù)據(jù)
void writeValue(WriteBuffer buffer, Object? value) {
if (value == null) {
buffer.putUint8(_valueNull);
} else if (value is bool) {
buffer.putUint8(value ? _valueTrue : _valueFalse);
} else if (value is double) { // Double precedes int because in JS everything is a double.
// Therefore in JS, both `is int` and `is double` always
// return `true`. If we check int first, we'll end up treating
// all numbers as ints and attempt the int32/int64 conversion,
// which is wrong. This precedence rule is irrelevant when
// decoding because we use tags to detect the type of value.
buffer.putUint8(_valueFloat64);
buffer.putFloat64(value);
} else if (value is int) {
if (-0x7fffffff - 1 <= value && value <= 0x7fffffff) {
buffer.putUint8(_valueInt32);
buffer.putInt32(value);
} else {
buffer.putUint8(_valueInt64);
buffer.putInt64(value);
}
} else if (value is String) {
buffer.putUint8(_valueString);
final Uint8List bytes = utf8.encoder.convert(value);
writeSize(buffer, bytes.length);
buffer.putUint8List(bytes);
} else if (value is Uint8List) {
buffer.putUint8(_valueUint8List);
writeSize(buffer, value.length);
buffer.putUint8List(value);
} else if (value is Int32List) {
buffer.putUint8(_valueInt32List);
writeSize(buffer, value.length);
buffer.putInt32List(value);
} else if (value is Int64List) {
buffer.putUint8(_valueInt64List);
writeSize(buffer, value.length);
buffer.putInt64List(value);
} else if (value is Float64List) {
buffer.putUint8(_valueFloat64List);
writeSize(buffer, value.length);
buffer.putFloat64List(value);
} else if (value is List) {
buffer.putUint8(_valueList);
writeSize(buffer, value.length);
for (final Object? item in value) {
writeValue(buffer, item);
}
} else if (value is Map) {
buffer.putUint8(_valueMap);
writeSize(buffer, value.length);
value.forEach((Object? key, Object? value) {
writeValue(buffer, key);
writeValue(buffer, value);
});
} else {
throw ArgumentError.value(value);
}
}
writeValue首先先寫入1個字節(jié)作為數(shù)據(jù)的類型屎篱,然后再寫入數(shù)據(jù)本身的值服赎;如果是“復(fù)雜”數(shù)據(jù)類型比如String,Uint8List交播,Int32List等等寫入數(shù)據(jù)類型的同時還會寫入數(shù)據(jù)的長度再寫入數(shù)據(jù)的值重虑;如果數(shù)據(jù)再“復(fù)雜”點比如List,Map最后會對他們的值(Map會對Key秦士,value)分別再調(diào)用writeValue去寫入缺厉;
Object? readValue(ReadBuffer buffer) {
if (!buffer.hasRemaining)
throw const FormatException('Message corrupted');
final int type = buffer.getUint8();
return readValueOfType(type, buffer);
}
/// Reads a value of the indicated [type] from [buffer].
///
/// The codec can be extended by overriding this method, calling super for
/// types that the extension does not handle. See the discussion at
/// [writeValue].
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case _valueNull:
return null;
case _valueTrue:
return true;
case _valueFalse:
return false;
case _valueInt32:
return buffer.getInt32();
case _valueInt64:
return buffer.getInt64();
case _valueFloat64:
return buffer.getFloat64();
case _valueLargeInt:
case _valueString:
final int length = readSize(buffer);
return utf8.decoder.convert(buffer.getUint8List(length));
case _valueUint8List:
final int length = readSize(buffer);
return buffer.getUint8List(length);
case _valueInt32List:
final int length = readSize(buffer);
return buffer.getInt32List(length);
case _valueInt64List:
final int length = readSize(buffer);
return buffer.getInt64List(length);
case _valueFloat64List:
final int length = readSize(buffer);
return buffer.getFloat64List(length);
case _valueList:
final int length = readSize(buffer);
final List<Object?> result = List<Object?>.filled(length, null, growable: false);
for (int i = 0; i < length; i++)
result[i] = readValue(buffer);
return result;
case _valueMap:
final int length = readSize(buffer);
final Map<Object?, Object?> result = <Object?, Object?>{};
for (int i = 0; i < length; i++)
result[readValue(buffer)] = readValue(buffer);
return result;
default: throw const FormatException('Message corrupted');
}
}
readValue讀取數(shù)據(jù)的時候就是一個逆向操作,先讀取1個字節(jié)的數(shù)據(jù)類型隧土,再讀取數(shù)據(jù)的值提针,讀取值的時候如果遇到“復(fù)雜”數(shù)據(jù)類型先讀取他的長度在讀取他的值,總之就是writeValue的逆操作曹傀,說完了Dart部分辐脖,讓我們再來看看Android部分:
Android部分 StandardMessageCodec.encodeMessage / StandardMessageCodec.decodeMessage
@Override
public ByteBuffer encodeMessage(Object message) {
if (message == null) {
return null;
}
final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
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());
final Object value = readValue(message);
if (message.hasRemaining()) {
throw new IllegalArgumentException("Message corrupted");
}
return value;
}
Android端通過ExposedByteArrayOutputStream作為字符的基本寫入與讀取的數(shù)據(jù)結(jié)構(gòu)的封裝,然后通過writeValue皆愉,readValue寫入以及讀取數(shù)據(jù)嗜价,ExposedByteArrayOutputStream 其實就是ByteArrayOutputStream的子類
protected void writeValue(ByteArrayOutputStream stream, 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 String) {
stream.write(STRING);
writeBytes(stream, ((String) value).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 {
throw new IllegalArgumentException("Unsupported value: " + value);
}
}
writeValue首先先寫入1個字節(jié)作為數(shù)據(jù)的類型艇抠,然后再寫入數(shù)據(jù)本身的值;如果是“復(fù)雜”數(shù)據(jù)類型比如String炭剪,寫入數(shù)據(jù)類型的同時還會寫入數(shù)據(jù)的長度再寫入數(shù)據(jù)的值练链;如果是數(shù)組的話還會先寫入對齊字符,他的長度大小是數(shù)據(jù)元素的單個長度大信埂媒鼓;如果數(shù)據(jù)再“復(fù)雜”點比如List,Map最后會對他們的值(Map會對Key错妖,value)分別再調(diào)用writeValue去寫入绿鸣;
Object? readValue(ReadBuffer buffer) {
if (!buffer.hasRemaining)
throw const FormatException('Message corrupted');
final int type = buffer.getUint8();
return readValueOfType(type, buffer);
}
/// Reads a value of the indicated [type] from [buffer].
///
/// The codec can be extended by overriding this method, calling super for
/// types that the extension does not handle. See the discussion at
/// [writeValue].
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case _valueNull:
return null;
case _valueTrue:
return true;
case _valueFalse:
return false;
case _valueInt32:
return buffer.getInt32();
case _valueInt64:
return buffer.getInt64();
case _valueFloat64:
return buffer.getFloat64();
case _valueLargeInt:
case _valueString:
final int length = readSize(buffer);
return utf8.decoder.convert(buffer.getUint8List(length));
case _valueUint8List:
final int length = readSize(buffer);
return buffer.getUint8List(length);
case _valueInt32List:
final int length = readSize(buffer);
return buffer.getInt32List(length);
case _valueInt64List:
final int length = readSize(buffer);
return buffer.getInt64List(length);
case _valueFloat64List:
final int length = readSize(buffer);
return buffer.getFloat64List(length);
case _valueList:
final int length = readSize(buffer);
final List<Object?> result = List<Object?>.filled(length, null, growable: false);
for (int i = 0; i < length; i++)
result[i] = readValue(buffer);
return result;
case _valueMap:
final int length = readSize(buffer);
final Map<Object?, Object?> result = <Object?, Object?>{};
for (int i = 0; i < length; i++)
result[readValue(buffer)] = readValue(buffer);
return result;
default: throw const FormatException('Message corrupted');
}
}
/** Reads a value as written by writeValue. */
protected final Object readValue(ByteBuffer buffer) {
if (!buffer.hasRemaining()) {
throw new IllegalArgumentException("Message corrupted");
}
final byte type = buffer.get();
return readValueOfType(type, buffer);
}
/**
* Reads a value of the specified type.
*
* <p>Subclasses may extend the codec by overriding this method, calling super for types that the
* extension does not handle.
*/
protected Object readValueOfType(byte type, ByteBuffer buffer) {
final Object result;
switch (type) {
case NULL:
result = null;
break;
case TRUE:
result = true;
break;
case FALSE:
result = false;
break;
case INT:
result = buffer.getInt();
break;
case LONG:
result = buffer.getLong();
break;
case BIGINT:
{
final byte[] hex = readBytes(buffer);
result = new BigInteger(new String(hex, UTF8), 16);
break;
}
case DOUBLE:
readAlignment(buffer, 8);
result = buffer.getDouble();
break;
case STRING:
{
final byte[] bytes = readBytes(buffer);
result = new String(bytes, UTF8);
break;
}
case BYTE_ARRAY:
{
result = readBytes(buffer);
break;
}
case INT_ARRAY:
{
final int length = readSize(buffer);
final int[] array = new int[length];
readAlignment(buffer, 4);
buffer.asIntBuffer().get(array);
result = array;
buffer.position(buffer.position() + 4 * length);
break;
}
case LONG_ARRAY:
{
final int length = readSize(buffer);
final long[] array = new long[length];
readAlignment(buffer, 8);
buffer.asLongBuffer().get(array);
result = array;
buffer.position(buffer.position() + 8 * length);
break;
}
case DOUBLE_ARRAY:
{
final int length = readSize(buffer);
final double[] array = new double[length];
readAlignment(buffer, 8);
buffer.asDoubleBuffer().get(array);
result = array;
buffer.position(buffer.position() + 8 * length);
break;
}
case LIST:
{
final int size = readSize(buffer);
final List<Object> list = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
list.add(readValue(buffer));
}
result = list;
break;
}
case MAP:
{
final int size = readSize(buffer);
final Map<Object, Object> map = new HashMap<>();
for (int i = 0; i < size; i++) {
map.put(readValue(buffer), readValue(buffer));
}
result = map;
break;
}
default:
throw new IllegalArgumentException("Message corrupted");
}
return result;
}
/** Reads alignment padding bytes as written by writeAlignment. */
protected static final void readAlignment(ByteBuffer buffer, int alignment) {
final int mod = buffer.position() % alignment;
if (mod != 0) {
buffer.position(buffer.position() + alignment - mod);
}
}
readValue讀取數(shù)據(jù)的時候就是一個逆向操作,先讀取1個字節(jié)的數(shù)據(jù)類型暂氯,再讀取數(shù)據(jù)的值潮模,讀取值的時候如果遇到“復(fù)雜”數(shù)據(jù)類型先讀取他的長度在讀取他的值,值得一提的是如果是數(shù)組類型的話會先讀出他的對齊字符痴施,目的是為了校驗當(dāng)前的position位置是否可以持續(xù)讀取數(shù)組元素類型擎厢,
- MethodCodec
MethodCodec用于二進(jìn)制數(shù)據(jù)與方法調(diào)用(MethodCall)和返回結(jié)果之間的編解碼,MethodChannel和EventChannel所使用的編解碼器均為MethodCodec辣吃,由于MethodCodec編解碼基本上原理是依賴于MessageCodec的动遭,所以我們大致講解下即可:
- StandardMethodCodec
Android部分 StandardMethodCodec.encodeMethodCall / StandardMethodCodec.decodeMethodCall
//send發(fā)送消息,調(diào)用編碼過程
@UiThread
public void invokeMethod(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 ByteBuffer encodeMethodCall(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
public MethodCall decodeMethodCall(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");
}
函數(shù)調(diào)用的時候首先把method方法名神得,argument參數(shù)封裝成一個MethodCall厘惦,然后分別對于函數(shù)名以及參數(shù)調(diào)用messageCodec.writeValue方法寫入;解碼的時候分別讀出method方法名哩簿,argument參數(shù)然后包裝成一個MethodCall
Dart部分 StandardMethodCodec.encodeMethodCall / StandardMethodCodec.decodeMethodCall
@override
ByteData encodeMethodCall(MethodCall call) {
final WriteBuffer buffer = WriteBuffer();
messageCodec.writeValue(buffer, call.method);
messageCodec.writeValue(buffer, call.arguments);
return buffer.done();
}
@override
MethodCall decodeMethodCall(ByteData? methodCall) {
final ReadBuffer buffer = ReadBuffer(methodCall!);
final Object? method = messageCodec.readValue(buffer);
final Object? arguments = messageCodec.readValue(buffer);
if (method is String && !buffer.hasRemaining)
return MethodCall(method, arguments);
else
throw const FormatException('Invalid method call');
}
Dart部分原理一模一樣宵蕉,不在贅述
- JSONMethodCodec
原理與上面較為相似,不再贅述
最后再附上一張表來說明上面代碼的Type類型與Dart與PlatForm類型對應(yīng)的表:
好了节榜,我們現(xiàn)在從BinaryMessenger到BinaryMessengerHandler再到消息編解碼器Codec基本都講清楚了羡玛,下面就剩下最關(guān)鍵的怎么去通信了,我們只以BasicMessageChannel來說明情況(因為MethodChannel宗苍,EventChannel原理差不多)缝左,我們先從Dart端向Android端發(fā)送消息看看他是怎么進(jìn)行的:
Dart端向Android端發(fā)送消息:
//發(fā)送代碼片段
response = await _basicMessageChannel.send(value);
BasicMessageChannel.send
Future<T?> send(T message) async {
return codec.decodeMessage(await binaryMessenger.send(name, codec.encodeMessage(message)));
}
發(fā)送的時候先把消息經(jīng)過Codec編碼處理(Codec我們上面講解過了)再調(diào)用發(fā)送,send函數(shù)返回的是一個Future浓若,是因為發(fā)送端需要await等待返回值渺杉,binaryMessenger在Dart端默認(rèn)是_DefaultBinaryMessenger上面也講過了
_DefaultBinaryMessenger.send
@override
Future<ByteData?>? send(String channel, ByteData? message) {
final MessageHandler? handler = _mockHandlers[channel];
if (handler != null)
return handler(message);
return _sendPlatformMessage(channel, message);
}
_DefaultBinaryMessenger._sendPlatformMessage
Future<ByteData?> _sendPlatformMessage(String channel, ByteData? message) {
final Completer<ByteData?> completer = Completer<ByteData?>();
// ui.PlatformDispatcher.instance is accessed directly instead of using
// ServicesBinding.instance.platformDispatcher because this method might be
// invoked before any binding is initialized. This issue was reported in
// #27541. It is not ideal to statically access
// ui.PlatformDispatcher.instance because the PlatformDispatcher may be
// dependency injected elsewhere with a different instance. However, static
// access at this location seems to be the least bad option.
ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
try {
completer.complete(reply);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('during a platform message response callback'),
));
}
});
return completer.future;
}
void sendPlatformMessage(String name, ByteData? data, PlatformMessageResponseCallback? callback) {
final String? error =
_sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data);
if (error != null)
throw Exception(error);
}
String? _sendPlatformMessage(String name, PlatformMessageResponseCallback? callback, ByteData? data)
native 'PlatformConfiguration_sendPlatformMessage';
_sendPlatformMessage是一個C++方法,現(xiàn)在我們會從Dart層進(jìn)入到C++層了挪钓,我們先借用網(wǎng)上的一個圖來看看
這個圖說明了整個Dart層與C++層的函數(shù)調(diào)用棧是越,我們不會每一個函數(shù)調(diào)用都走一遍這沒有太多的意義,但是我也不會什么都不說了只上一個圖來敷衍大家碌上,我會把關(guān)鍵步驟帶大家看一看(??這個也是我們今天這個博客與其他的博客不同的地方)倚评,首先我們來看看這個C++函數(shù)再哪注冊的
void PlatformConfiguration::RegisterNatives(
tonic::DartLibraryNatives* natives) {
natives->Register({
{"PlatformConfiguration_defaultRouteName", DefaultRouteName, 1, true},
{"PlatformConfiguration_scheduleFrame", ScheduleFrame, 1, true},
{"PlatformConfiguration_sendPlatformMessage", _SendPlatformMessage, 4,
true},
{"PlatformConfiguration_respondToPlatformMessage",
_RespondToPlatformMessage, 3, true},
{"PlatformConfiguration_render", Render, 3, true},
{"PlatformConfiguration_updateSemantics", UpdateSemantics, 2, true},
{"PlatformConfiguration_setIsolateDebugName", SetIsolateDebugName, 2,
true},
{"PlatformConfiguration_reportUnhandledException",
ReportUnhandledException, 2, true},
{"PlatformConfiguration_setNeedsReportTimings", SetNeedsReportTimings, 2,
true},
{"PlatformConfiguration_getPersistentIsolateData",
GetPersistentIsolateData, 1, true},
{"PlatformConfiguration_computePlatformResolvedLocale",
_ComputePlatformResolvedLocale, 2, true},
});
}
注冊到了_SendPlatformMessage函數(shù)里面浦徊,進(jìn)去看看
void _SendPlatformMessage(Dart_NativeArguments args) {
tonic::DartCallStatic(&SendPlatformMessage, args);
}
Dart_Handle SendPlatformMessage(Dart_Handle window,
const std::string& name,
Dart_Handle callback,
Dart_Handle data_handle) {
UIDartState* dart_state = UIDartState::Current();
if (!dart_state->platform_configuration()) {
return tonic::ToDart(
"Platform messages can only be sent from the main isolate");
}
fml::RefPtr<PlatformMessageResponse> response;
if (!Dart_IsNull(callback)) {
response = fml::MakeRefCounted<PlatformMessageResponseDart>(
tonic::DartPersistentValue(dart_state, callback),
dart_state->GetTaskRunners().GetUITaskRunner());
}
if (Dart_IsNull(data_handle)) {
dart_state->platform_configuration()->client()->HandlePlatformMessage(
std::make_unique<PlatformMessage>(name, response));
} else {
tonic::DartByteData data(data_handle);
const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
dart_state->platform_configuration()->client()->HandlePlatformMessage(
std::make_unique<PlatformMessage>(
name, fml::MallocMapping::Copy(buffer, data.length_in_bytes()),
response));
}
return Dart_Null();
}
大家看明白了沒有,Dart端的_sendPlatformMessage(String name, PlatformMessageResponseCallback? callback, ByteData? data) 函數(shù)對應(yīng)的是C++ 的 SendPlatformMessage(Dart_Handle window,const std::string& name,Dart_Handle callback,Dart_Handle data_handle) 這個函數(shù)天梧,大家注意觀察下Dart的參數(shù)都已經(jīng)轉(zhuǎn)換為了C++層的Dart_Handle 這個指針來處理盔性,這邊還把callback封裝成了一個PlatformMessageResponseDart對象來處理,并且值得一提的是這里還把channel的名字呢岗,data數(shù)據(jù)以及封裝過了的callback再封裝成了一個PlatformMessage對象作為下面函數(shù)棧調(diào)用的傳遞的參數(shù)
// |PlatformView|
void PlatformMessageHandlerAndroid::HandlePlatformMessage(
std::unique_ptr<flutter::PlatformMessage> message) {
// Called from the ui thread.
int response_id = next_response_id_++;
if (auto response = message->response()) {
std::lock_guard lock(pending_responses_mutex_);
pending_responses_[response_id] = response;
}
// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
jni_facade_->FlutterViewHandlePlatformMessage(std::move(message),
response_id);
}
我們再看到倒數(shù)第三步HandlePlatformMessage這個函數(shù)冕香,這里生產(chǎn)了一個唯一的response_id與message->response()也就是我們上面提到的PlatformMessageResponse對象(其實是對callback的封裝)綁定起來,然后把PlatformMessageResponse對象(其實是對callback的封裝)存在鍵值為response_id的pending_responses_里面,再把response_id發(fā)送給Android端后豫,如果需要回調(diào)的話悉尾,Android會把返回值以及這個response_id返回,pending_responses_查找到對應(yīng)的Dart端的response再執(zhí)行
void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessage(
std::unique_ptr<flutter::PlatformMessage> message,
int responseId) {
// Called from the ui thread.
JNIEnv* env = fml::jni::AttachCurrentThread();
auto java_object = java_object_.get(env);
if (java_object.is_null()) {
return;
}
fml::jni::ScopedJavaLocalRef<jstring> java_channel =
fml::jni::StringToJavaString(env, message->channel());
if (message->hasData()) {
fml::jni::ScopedJavaLocalRef<jobject> message_array(
env, env->NewDirectByteBuffer(
const_cast<uint8_t*>(message->data().GetMapping()),
message->data().GetSize()));
// Message data is deleted in CleanupMessageData.
fml::MallocMapping mapping = message->releaseData();
env->CallVoidMethod(java_object.obj(), g_handle_platform_message_method,
java_channel.obj(), message_array.obj(), responseId,
mapping.Release());
} else {
env->CallVoidMethod(java_object.obj(), g_handle_platform_message_method,
java_channel.obj(), nullptr, responseId, nullptr);
}
FML_CHECK(fml::jni::CheckException(env));
}
g_flutter_jni_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
env, env->FindClass("io/flutter/embedding/engine/FlutterJNI"));
if (g_flutter_jni_class->is_null()) {
FML_LOG(ERROR) << "Failed to find FlutterJNI Class.";
return false;
}
g_handle_platform_message_method =
env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
"(Ljava/lang/String;Ljava/nio/ByteBuffer;IJ)V");
最后面回到這個函數(shù)jni_facade_->FlutterViewHandlePlatformMessage部分挫酿,通過JNI去調(diào)用Android端handlePlatformMessage函數(shù)构眯,我們再來看看Android這個函數(shù)是什么樣子的:
FlutterJNI.handlePlatformMessage
// Called by native.
// TODO(mattcarroll): determine if message is nonull or nullable
@SuppressWarnings("unused")
@VisibleForTesting
public void handlePlatformMessage(
@NonNull final String channel, byte[] message, final int replyId) {
if (platformMessageHandler != null) {
platformMessageHandler.handleMessageFromDart(channel, message, replyId);
}
// TODO(mattcarroll): log dropped messages when in debug mode
// (https://github.com/flutter/flutter/issues/25391)
}
這里的platformMessageHandler其實就是初始化賦值的DartMessenger
DartMessenger.handleMessageFromDart
@Override
public void handleMessageFromDart(
@NonNull final String channel, @Nullable byte[] message, final int replyId) {
Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
if (handler != null) {
try {
Log.v(TAG, "Deferring to registered handler to process message.");
final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
handler.onMessage(buffer, 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);
}
}
這里面通過messageHandlers.get(channel)取出了handler(至于怎么放置的我們在上面注冊的時候已經(jīng)講過了),然后調(diào)用其監(jiān)聽的handler.onMessage方法早龟,這個在上面設(shè)置setMessageHandler的時候已經(jīng)設(shè)置好了監(jiān)聽了惫霸,現(xiàn)在我們再來看看Dart調(diào)用Android端以后Dart端的回調(diào)函數(shù)是怎么運行的
Dart端向Android端發(fā)送消息以后Dart端的回調(diào)處理:
@Override
public void onMessage(String s, BasicMessageChannel.Reply<String> reply) {//處理Dart發(fā)來的消息
reply.reply("BasicMessageChannel收到:" + s);//可以通過reply進(jìn)行回復(fù)
if (activity instanceof IShowMessage) {
((IShowMessage) activity).onShowMessage(s);
}
Toast.makeText(activity, s, Toast.LENGTH_SHORT).show();
}
Android端回調(diào)通過reply.reply進(jìn)行,reply則為上面參數(shù)的Reply對象
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());
}
}
}
調(diào)用到了invokePlatformMessageResponseCallback這個函數(shù)進(jìn)行回調(diào)處理葱弟,并且把replyId它褪,以及reply返回值傳過去,返回值也是ByteBuffer類型的
public void invokePlatformMessageResponseCallback(
int responseId, @Nullable ByteBuffer message, int position) {
ensureRunningOnMainThread();
if (isAttached()) {
nativeInvokePlatformMessageResponseCallback(
nativeShellHolderId, responseId, message, position);
} else {
Log.w(
TAG,
"Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: "
+ responseId);
}
}
他對應(yīng)的是一個C++函數(shù)nativeInvokePlatformMessageResponseCallback翘悉,現(xiàn)在我們又準(zhǔn)備進(jìn)入到C++層了
{
.name = "nativeInvokePlatformMessageResponseCallback",
.signature = "(JILjava/nio/ByteBuffer;I)V",
.fnPtr =
reinterpret_cast<void*>(&InvokePlatformMessageResponseCallback),
},
他對應(yīng)的是一個InvokePlatformMessageResponseCallback函數(shù),最后面回到這個PlatformMessageHandlerAndroid里面的InvokePlatformMessageResponseCallback函數(shù)
void PlatformMessageHandlerAndroid::InvokePlatformMessageResponseCallback(
int response_id,
std::unique_ptr<fml::Mapping> mapping) {
// Called from any thread.
if (!response_id) {
return;
}
// TODO(gaaclarke): Move the jump to the ui thread here from
// PlatformMessageResponseDart so we won't need to use a mutex anymore.
fml::RefPtr<flutter::PlatformMessageResponse> message_response;
{
std::lock_guard lock(pending_responses_mutex_);
auto it = pending_responses_.find(response_id);
if (it == pending_responses_.end())
return;
message_response = std::move(it->second);
pending_responses_.erase(it);
}
message_response->Complete(std::move(mapping));
}
message_response就是PlatformMessageResponse也就是我們一開始把回調(diào)callback封裝成的PlatformMessageResponseDart對象看看他的Complete方法
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);
Dart_Handle byte_buffer =
tonic::DartByteData::Create(data->GetMapping(), data->GetSize());
tonic::DartInvoke(callback.Release(), {byte_buffer});
}));
}
Dart_Handle DartPersistentValue::Release() {
Dart_Handle local = Get();
Clear();
return local;
}
通過callback.Release()拿到Dart_Handle也就是原來Dart端設(shè)置的callback對應(yīng)的指針居触,然后使用tonic::DartInvoke去調(diào)用這個函數(shù)
Dart_Handle DartInvoke(Dart_Handle closure,
std::initializer_list<Dart_Handle> args) {
int argc = args.size();
Dart_Handle* argv = const_cast<Dart_Handle*>(args.begin());
Dart_Handle handle = Dart_InvokeClosure(closure, argc, argv);
LogIfError(handle);
return handle;
}
最后通過Dart_InvokeClosure去調(diào)用這個Dart方法妖混,最后面會回到Dart函數(shù)的callback里面,代碼我們再貼一遍
Future<ByteData?> _sendPlatformMessage(String channel, ByteData? message) {
final Completer<ByteData?> completer = Completer<ByteData?>();
// ui.PlatformDispatcher.instance is accessed directly instead of using
// ServicesBinding.instance.platformDispatcher because this method might be
// invoked before any binding is initialized. This issue was reported in
// #27541. It is not ideal to statically access
// ui.PlatformDispatcher.instance because the PlatformDispatcher may be
// dependency injected elsewhere with a different instance. However, static
// access at this location seems to be the least bad option.
ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
try {
completer.complete(reply);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('during a platform message response callback'),
));
}
});
return completer.future;
}
這里通過completer.complete(reply)函數(shù)去返回函數(shù)send調(diào)用者使用await函數(shù)等待的future
Future<T?> send(T message) async {
return codec.decodeMessage(await binaryMessenger.send(name, codec.encodeMessage(message)));
}
然后返回值通過codec解碼后返回即可轮洋,好了到這里我們從Dart端調(diào)用到Android端以及其相關(guān)的回調(diào)我們已經(jīng)介紹完畢了制市,我們再來從Android端看看他與Dart通信是怎么樣的呢
Android端向Dart端發(fā)送消息:
由于原理相同我們只介紹BasicMessageChannel,首先Android端發(fā)送消息一般是通過BasicMessageChannel的send方法
@UiThread
public void send(@Nullable T message, @Nullable final Reply<T> callback) {
messenger.send(
name,
codec.encodeMessage(message),
callback == null ? null : new IncomingReplyHandler(callback));
}
public interface Reply<T> {
/**
* Handles the specified message reply.
*
* @param reply the reply, possibly null.
*/
void reply(@Nullable T reply);
}
Message是消息內(nèi)容弊予,Reply是一個函數(shù)式接口作為回調(diào)祥楣,里面把消息經(jīng)過Codec加密過后通過messenger.send繼續(xù)處理發(fā)送,上面說過messenger在Android端默認(rèn)是DartExecutor
DartExecutor.send
public void send(
@NonNull String channel,
@Nullable ByteBuffer message,
@Nullable BinaryMessenger.BinaryReply callback) {
messenger.send(channel, message, callback);
}
DartMessenger.send
@Override
public void send(
@NonNull String channel,
@Nullable ByteBuffer message,
@Nullable BinaryMessenger.BinaryReply callback) {
Log.v(TAG, "Sending message with callback over channel '" + channel + "'");
int replyId = 0;
if (callback != null) {
replyId = nextReplyId++;
pendingReplies.put(replyId, callback);
}
if (message == null) {
flutterJNI.dispatchEmptyPlatformMessage(channel, replyId);
} else {
flutterJNI.dispatchPlatformMessage(channel, message, message.position(), replyId);
}
}
看到發(fā)送的之前做了一些處理汉柒,pendingReplies存的是回調(diào)的replyId以及對應(yīng)的CallBack误褪,send調(diào)用方法的時候先把replyId設(shè)置一個唯一的整數(shù)綁定CallBack,然后把需要回調(diào)的replyId傳給調(diào)用端碾褂,然后等調(diào)用端回復(fù)的時候再把replyId傳回來找到對應(yīng)的Callback調(diào)用其回調(diào)兽间,方法還是很巧妙的,這樣設(shè)計雙方只是在傳遞一個的Id而已效率還是比較高的(可以看見回調(diào)的處理方式Dart端與Android端基本思路是一樣的)正塌;我們再來看看發(fā)送嘀略,發(fā)送是通過flutterJNI.dispatchPlatformMessage進(jìn)行的恤溶,我們具體看看他
/** Sends a reply {@code message} from Android to Flutter over the given {@code channel}. */
@UiThread
public void dispatchPlatformMessage(
@NonNull String channel, @Nullable ByteBuffer message, int position, int responseId) {
ensureRunningOnMainThread();
if (isAttached()) {
nativeDispatchPlatformMessage(nativeShellHolderId, channel, message, position, responseId);
} else {
Log.w(
TAG,
"Tried to send a platform message to Flutter, but FlutterJNI was detached from native C++. Could not send. Channel: "
+ channel
+ ". Response ID: "
+ responseId);
}
}
nativeDispatchPlatformMessage是一個C++的方法,從這里以后Android會轉(zhuǎn)換為C++層來執(zhí)行
{
.name = "nativeDispatchPlatformMessage",
.signature = "(JLjava/lang/String;Ljava/nio/ByteBuffer;II)V",
.fnPtr = reinterpret_cast<void*>(&DispatchPlatformMessage),
}
C++ 把這個JAVA方法調(diào)用映射成了DispatchPlatformMessage的C++方法
static void DispatchPlatformMessage(JNIEnv* env,
jobject jcaller,
jlong shell_holder,
jstring channel,
jobject message,
jint position,
jint responseId) {
ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchPlatformMessage(
env, //
fml::jni::JavaStringToString(env, channel), //
message, //
position, //
responseId //
);
}
void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env,
std::string name,
jobject java_message_data,
jint java_message_position,
jint response_id) {
uint8_t* message_data =
static_cast<uint8_t*>(env->GetDirectBufferAddress(java_message_data));
fml::MallocMapping message =
fml::MallocMapping::Copy(message_data, java_message_position);
fml::RefPtr<flutter::PlatformMessageResponse> response;
if (response_id) {
response = fml::MakeRefCounted<PlatformMessageResponseAndroid>(
response_id, jni_facade_, task_runners_.GetPlatformTaskRunner());
}
PlatformView::DispatchPlatformMessage(
std::make_unique<flutter::PlatformMessage>(
std::move(name), std::move(message), std::move(response)));
}
我們再往下看看這個方法帜羊,這里把調(diào)用的name咒程,message以及response封裝成一個PlatformMessage用于往下的函數(shù)調(diào)用傳遞,這個與Dart調(diào)用Android里面的這個步驟看起來是一樣的讼育,值得一提的是這里把response_id帐姻,jni_facade_,task_runners_.GetPlatformTaskRunner封裝成一個PlatformMessageResponseAndroid對象用于參數(shù)的傳遞窥淆,這里與Dart調(diào)用Android思路也是一致的
PlatformMessageResponseAndroid::PlatformMessageResponseAndroid(
int response_id,
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
fml::RefPtr<fml::TaskRunner> platform_task_runner)
: response_id_(response_id),
jni_facade_(jni_facade),
platform_task_runner_(std::move(platform_task_runner)) {}
PlatformMessageResponseAndroid::~PlatformMessageResponseAndroid() = default;
// |flutter::PlatformMessageResponse|
void PlatformMessageResponseAndroid::Complete(
std::unique_ptr<fml::Mapping> data) {
platform_task_runner_->PostTask(
fml::MakeCopyable([response_id = response_id_, //
data = std::move(data), //
jni_facade = jni_facade_]() mutable {
jni_facade->FlutterViewHandlePlatformMessageResponse(response_id,
std::move(data));
}));
}
我們接著往下看最后面會到PlatformConfiguration的DispatchPlatformMessage方法:
void PlatformConfiguration::DispatchPlatformMessage(
std::unique_ptr<PlatformMessage> message) {
std::shared_ptr<tonic::DartState> dart_state =
dispatch_platform_message_.dart_state().lock();
if (!dart_state) {
FML_DLOG(WARNING)
<< "Dropping platform message for lack of DartState on channel: "
<< message->channel();
return;
}
tonic::DartState::Scope scope(dart_state);
Dart_Handle data_handle =
(message->hasData()) ? ToByteData(message->data()) : Dart_Null();
if (Dart_IsError(data_handle)) {
FML_DLOG(WARNING)
<< "Dropping platform message because of a Dart error on channel: "
<< message->channel();
return;
}
int response_id = 0;
if (auto response = message->response()) {
response_id = next_response_id_++;
pending_responses_[response_id] = response;
}
tonic::LogIfError(
tonic::DartInvoke(dispatch_platform_message_.Get(),
{tonic::ToDart(message->channel()), data_handle,
tonic::ToDart(response_id)}));
}
代碼片段
Dart_Handle library = Dart_LookupLibrary(tonic::ToDart("dart:ui"));
dispatch_platform_message_.Set(
tonic::DartState::Current(),
Dart_GetField(library, tonic::ToDart("_dispatchPlatformMessage")));
最后面通過dispatch_platform_message_.Get()得到了hook.dart的_dispatchPlatformMessage方法引用卖宠,并且通過tonic::DartInvoke去調(diào)用這個Dart方法,并且把參數(shù)傳過去
Dart_Handle DartInvoke(Dart_Handle closure,
std::initializer_list<Dart_Handle> args) {
int argc = args.size();
Dart_Handle* argv = const_cast<Dart_Handle*>(args.begin());
Dart_Handle handle = Dart_InvokeClosure(closure, argc, argv);
LogIfError(handle);
return handle;
}
C++里面的DartInvoke里面通過Dart_InvokeClosure去調(diào)用Dart方法忧饭,但是Dart_InvokeClosure目前源碼已經(jīng)查找不到了扛伍,沒有繼續(xù)跟蹤了C++到底是怎么調(diào)用到Dart方法的了,讓我們再看看上面提到的hook.dart的_dispatchPlatformMessage方法:
@pragma('vm:entry-point')
void _dispatchPlatformMessage(String name, ByteData? data, int responseId) {
PlatformDispatcher.instance._dispatchPlatformMessage(name, data, responseId);
}
PlatformDispatcher._dispatchPlatformMessage
void _dispatchPlatformMessage(String name, ByteData? data, int responseId) {
if (name == ChannelBuffers.kControlChannelName) {
try {
channelBuffers.handleMessage(data!);
} finally {
_respondToPlatformMessage(responseId, null);
}
} else if (onPlatformMessage != null) {
_invoke3<String, ByteData?, PlatformMessageResponseCallback>(
onPlatformMessage,
_onPlatformMessageZone,
name,
data,
(ByteData? responseData) {
_respondToPlatformMessage(responseId, responseData);
},
);
} else {
channelBuffers.push(name, data, (ByteData? responseData) {
_respondToPlatformMessage(responseId, responseData);
});
}
}
void _invoke3<A1, A2, A3>(void Function(A1 a1, A2 a2, A3 a3)? callback, Zone zone, A1 arg1, A2 arg2, A3 arg3) {
if (callback == null) {
return;
}
assert(zone != null);
if (identical(zone, Zone.current)) {
callback(arg1, arg2, arg3);
} else {
zone.runGuarded(() {
callback(arg1, arg2, arg3);
});
}
}
_invoke3會調(diào)用參數(shù)傳過來的callback方法词裤,并且把后面幾個參數(shù)當(dāng)做他的參數(shù)傳進(jìn)去刺洒,所以重點看看這個callback是什么,也就是上面的onPlatformMessage是什么吼砂,因為調(diào)用棧比較多我就不貼代碼了他其實就是
代碼片段
window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
_defaultBinaryMessenger = createBinaryMessenger();
BinaryMessenger createBinaryMessenger() {
return const _DefaultBinaryMessenger._();
}
所以onPlatformMessage就是運行_DefaultBinaryMessenger.handlePlatformMessage方法:
@override
Future<void> handlePlatformMessage(
String channel,
ByteData? data,
ui.PlatformMessageResponseCallback? callback,
) async {
ByteData? response;
try {
final MessageHandler? handler = _handlers[channel];
if (handler != null) {
response = await handler(data);
} else {
ui.channelBuffers.push(channel, data, callback!);
callback = null;
}
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('during a platform message callback'),
));
} finally {
if (callback != null) {
callback(response);
}
}
}
這里_handlers[channel]通過channel名字取出來了MessageHandler handler逆航,然后進(jìn)行handler調(diào)用,這個_handlers[channel]是什么時候存放進(jìn)去的呢渔肩,上面已經(jīng)說過了是在setMessageHandler時候放進(jìn)去的因俐,大家可以往上翻翻,最后面我們再來說說回調(diào)是怎么處理的
Android端向Dart端發(fā)送消息以后Android端的回調(diào)處理:
大家應(yīng)該還記得我們Android端調(diào)用Dart的時候是可以設(shè)置回調(diào)函數(shù)的周偎,finally里面通過callback(response)調(diào)用(response是上面handler調(diào)用的返回值)抹剩,而callback則是_dispatchPlatformMessage里面的_respondToPlatformMessage方法,responseId是調(diào)用前傳進(jìn)來的ID蓉坎,responseData就是調(diào)用的返回值
_invoke3<String, ByteData?, PlatformMessageResponseCallback>(
onPlatformMessage,
_onPlatformMessageZone,
name,
data,
(ByteData? responseData) {
_respondToPlatformMessage(responseId, responseData);
},
);
/// Called by [_dispatchPlatformMessage].
void _respondToPlatformMessage(int responseId, ByteData? data)
native 'PlatformConfiguration_respondToPlatformMessage';
_respondToPlatformMessage是一個C++的方法澳眷,這里又回到了C++層了,看看他對應(yīng)的是哪個C++方法
{"PlatformConfiguration_respondToPlatformMessage",
_RespondToPlatformMessage, 3, true},
代碼片段對應(yīng)的是_RespondToPlatformMessage方法
void _RespondToPlatformMessage(Dart_NativeArguments args) {
tonic::DartCallStatic(&RespondToPlatformMessage, args);
}
void RespondToPlatformMessage(Dart_Handle window,
int response_id,
const tonic::DartByteData& data) {
if (Dart_IsNull(data.dart_handle())) {
UIDartState::Current()
->platform_configuration()
->CompletePlatformMessageEmptyResponse(response_id);
} else {
// TODO(engine): Avoid this copy.
const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
UIDartState::Current()
->platform_configuration()
->CompletePlatformMessageResponse(
response_id,
std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()));
}
}
最后面會調(diào)用CompletePlatformMessageResponse方法回調(diào)到Android端
void PlatformConfiguration::CompletePlatformMessageResponse(
int response_id,
std::vector<uint8_t> data) {
if (!response_id) {
return;
}
auto it = pending_responses_.find(response_id);
if (it == pending_responses_.end()) {
return;
}
auto response = std::move(it->second);
pending_responses_.erase(it);
response->Complete(std::make_unique<fml::DataMapping>(std::move(data)));
}
先從pending_responses_按照response_id取出response蛉艾,我們從Android調(diào)用Dart的時候設(shè)置過這個值钳踊,他的對象為PlatformMessageResponseAndroid,去看看的Complete方法:
// |flutter::PlatformMessageResponse|
void PlatformMessageResponseAndroid::Complete(
std::unique_ptr<fml::Mapping> data) {
platform_task_runner_->PostTask(
fml::MakeCopyable([response_id = response_id_, //
data = std::move(data), //
jni_facade = jni_facade_]() mutable {
jni_facade->FlutterViewHandlePlatformMessageResponse(response_id,
std::move(data));
}));
}
準(zhǔn)備通過JNI再回到Android端
void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessageResponse(
int responseId,
std::unique_ptr<fml::Mapping> data) {
// We are on the platform thread. Attempt to get the strong reference to
// the Java object.
JNIEnv* env = fml::jni::AttachCurrentThread();
auto java_object = java_object_.get(env);
if (java_object.is_null()) {
// The Java object was collected before this message response got to
// it. Drop the response on the floor.
return;
}
if (data == nullptr) { // Empty response.
env->CallVoidMethod(java_object.obj(),
g_handle_platform_message_response_method, responseId,
nullptr);
} else {
// Convert the vector to a Java byte array.
fml::jni::ScopedJavaLocalRef<jobject> data_array(
env, env->NewDirectByteBuffer(const_cast<uint8_t*>(data->GetMapping()),
data->GetSize()));
env->CallVoidMethod(java_object.obj(),
g_handle_platform_message_response_method, responseId,
data_array.obj());
}
FML_CHECK(fml::jni::CheckException(env));
}
g_handle_platform_message_response_method = env->GetMethodID(
g_flutter_jni_class->obj(), "handlePlatformMessageResponse",
"(ILjava/nio/ByteBuffer;)V");
g_flutter_jni_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
env, env->FindClass("io/flutter/embedding/engine/FlutterJNI"));
關(guān)鍵的代碼片段我貼出來了勿侯,一目了然的調(diào)用到了FlutterJNI的handlePlatformMessageResponse方法拓瞪,最后再看看他
// Called by native to respond to a platform message that we sent.
// TODO(mattcarroll): determine if reply is nonull or nullable
@SuppressWarnings("unused")
private void handlePlatformMessageResponse(int replyId, byte[] reply) {
if (platformMessageHandler != null) {
platformMessageHandler.handlePlatformMessageResponse(replyId, reply);
}
// TODO(mattcarroll): log dropped messages when in debug mode
// (https://github.com/flutter/flutter/issues/25391)
}
platformMessageHandler 其實就是 DartMessenger 上面已經(jīng)說過了
@Override
public void handlePlatformMessageResponse(int replyId, @Nullable byte[] reply) {
Log.v(TAG, "Received message reply from Dart.");
BinaryMessenger.BinaryReply callback = pendingReplies.remove(replyId);
if (callback != null) {
try {
Log.v(TAG, "Invoking registered callback for reply from Dart.");
callback.reply(reply == null ? null : ByteBuffer.wrap(reply));
} catch (Exception ex) {
Log.e(TAG, "Uncaught exception in binary message reply handler", ex);
} catch (Error err) {
handleError(err);
}
}
}
這里大家應(yīng)該很熟悉了通過pendingReplies.remove取出了callback,然后進(jìn)行調(diào)用即可助琐,至于什么時候存放的環(huán)節(jié)大家往上翻翻就明白了是在send的時候就已經(jīng)注冊了吴藻,好了到這里Android調(diào)用Dart以及Dart回調(diào)Android整個步驟我們已經(jīng)也介紹完了
最后想說的話:
如果大家仔細(xì)看完的話我相信你對于整個流程的調(diào)用已經(jīng)明白了,本著通俗易懂的原則我算是用大白話以及邊附上代碼邊解釋的方式帶領(lǐng)大家去理解了弓柱,相信你如果從來都沒了解過Flutter底層通信的也能很容易的去了解到他的原理以及步驟沟堡,順便提一句如果你能一口氣看到這里并且內(nèi)容大致都能夠理解的話那么我覺得你的耐心還是不錯的呢侧但,我寫到這里確實寫了很久,??最后希望大家關(guān)注我航罗,并且留言或給個點贊吧禀横,你的關(guān)注是我持續(xù)寫作的動力,下一篇我們會介紹從Platform到Dart通信原理分析之iOS篇(我是不會拋棄iOS小伙伴的粥血,??誰讓我是全棧呢)柏锄,小伙伴們一起期待一下吧···