Dart层的消息传递分析
static const MethodChannel _channel = const MethodChannel('kwl_native');
final int result = await _channel.invokeMethod('getBatteryLevel');
在与原生交互时,首先创建MethodChannel
对象,接着调用invokeMethod()
方法并传入原生方法名。接着查看invokeMethod()
源码。
@optionalTypeArgs
Future<T> invokeMethod<T>(String method, [dynamic arguments]) async {
assert(method != null);
final ByteData result = await BinaryMessages.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;
}
从里层往外分析,首先MethodCall(method, arguments)
将方法名和参数进行封装成MethodCall
对象便于传递。codec
是MethodCodec
对象,而MethodCodec
是抽象类,所以是其实现类的对象,在MethodChannel
创建时候默认创建StandardMethodCodec
对象。
class MethodChannel {
/// Creates a [MethodChannel] with the specified [name].
///
/// The [codec] used will be [StandardMethodCodec], unless otherwise
/// specified.
///
/// Neither [name] nor [codec] may be null.
const MethodChannel(this.name, [this.codec = const StandardMethodCodec()]);
/// The logical channel on which communication happens, not null.
final String name;
/// The message codec used by this channel, not null.
final MethodCodec codec;
接着看StandardMethodCodec
源码
/// Creates a [MethodCodec] using the Flutter standard binary encoding.
const StandardMethodCodec([this.messageCodec = const StandardMessageCodec()]);
/// The message codec that this method codec uses for encoding values.
final StandardMessageCodec messageCodec;
@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 dynamic method = messageCodec.readValue(buffer);
final dynamic arguments = messageCodec.readValue(buffer);
if (method is String && !buffer.hasRemaining)
return MethodCall(method, arguments);
else
throw const FormatException('Invalid method call');
}
......
列了主要的编码和解码的方法,将MethodCall
对象通过StandardMessageCodec
进行读写,转为ByteData
与C++层进行传输。查看writeValue()
方法可以知道传输支持的类型。
void writeValue(WriteBuffer buffer, dynamic value) {
if (value == null) {
buffer.putUint8(_valueNull);
} else if (value is bool) {
buffer.putUint8(value ? _valueTrue : _valueFalse);
} 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 double) {
buffer.putUint8(_valueFloat64);
buffer.putFloat64(value);
} else if (value is String) {
buffer.putUint8(_valueString);
final List<int> 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 dynamic item in value) {
writeValue(buffer, item);
}
} else if (value is Map) {
buffer.putUint8(_valueMap);
writeSize(buffer, value.length);
value.forEach((dynamic key, dynamic value) {
writeValue(buffer, key);
writeValue(buffer, value);
});
} else {
throw ArgumentError.value(value);
}
}
再回到invokeMethod()
中,接着看BinaryMessages
,它用于处理二进制消息,用于发送消息到插件或从插件接受消息。
final ByteData result = await BinaryMessages.send(
name,
codec.encodeMethodCall(MethodCall(method, arguments)),
);
查看send()
方法,发送到指定渠道名的插件中,渠道名需保证唯一。
/// Send a binary message to the platform plugins on the given channel.
///
/// Returns a [Future] which completes to the received response, undecoded, in
/// binary form.
static Future<ByteData> send(String channel, ByteData message) {
final _MessageHandler handler = _mockHandlers[channel];
if (handler != null)
return handler(message);
return _sendPlatformMessage(channel, message);
}
这里_mockHandlers[channel]
模拟处理器拦截并相应消息,一般为空,所以会走到_sendPlatformMessage ()
方法。
static Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
final Completer<ByteData> completer = Completer<ByteData>();
// ui.window is accessed directly instead of using ServicesBinding.instance.window
// 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.window because the Window may be dependency injected elsewhere with
// a different instance. However, static access at this location seems to be
// the least bad option.
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;
}
最终调用ui.window. sendPlatformMessage ()
,跟进查看
void sendPlatformMessage(String name,
ByteData data,
PlatformMessageResponseCallback callback) {
final String error =
_sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data);
if (error != null)
throw new Exception(error);
}
String _sendPlatformMessage(String name,
PlatformMessageResponseCallback callback,
ByteData data) native 'Window_sendPlatformMessage';
可以看到最后调用一个native方法,类似java中定义的native方法一样,将渠道名、数据和处理回调传去C++层。
至此,Dart层的消息传递分析完毕。
网友评论