-
概述
在《Flutter原生通信原理概述》一文中我们大概知道了Flutter是怎样和原生通信的,当时我们提到了EventChannel和MethodChannel,实际上还有一个Channel就是BasicMessageChannel。
它们彼此相互独立,并没有继承自什么共有的父类,但是它们的原理是差不多的。
-
BinaryMessenger
上述三个Channel都持有一个BinaryMessenger类型的messager对象,就是它负责原生向Flutter发送数据的。
BinaryMessenger本身是一个接口,实现它的类有DartExecutor、DartMessenger、DefaultBinaryMessenger,它里面有一个send方法,最终就是通过它来发送数据。
发送数据必然要通过FlutterEngine,在FlutterPlugin的onAttachedToEngine方法中有一个FlutterPlugin.FlutterPluginBinding类型的binding参数:
public FlutterPluginBinding( @NonNull Context applicationContext, @NonNull FlutterEngine flutterEngine, @NonNull BinaryMessenger binaryMessenger, @NonNull TextureRegistry textureRegistry, @NonNull PlatformViewRegistry platformViewRegistry, @NonNull FlutterAssets flutterAssets)
往Channel传递的就是它的binaryMessenger。
FlutterPlugin.FlutterPluginBinding在FlutterEngineConnectionRegistry的构造方法里初始化的:
FlutterEngineConnectionRegistry( @NonNull Context appContext, @NonNull FlutterEngine flutterEngine, @NonNull FlutterLoader flutterLoader) { this.flutterEngine = flutterEngine; pluginBinding = new FlutterPlugin.FlutterPluginBinding( appContext, flutterEngine, flutterEngine.getDartExecutor(), flutterEngine.getRenderer(), flutterEngine.getPlatformViewsController().getRegistry(), new DefaultFlutterAssets(flutterLoader)); }
可见,它的binaryMessenger就是flutterEngine的DartExecutor。
看一下DartExecutor的send方法:
public void send(@NonNull String channel, @Nullable ByteBuffer message) { binaryMessenger.send(channel, message); }
binaryMessenger是DefaultBinaryMessenger:
this.dartMessenger = new DartMessenger(flutterJNI); dartMessenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler); this.binaryMessenger = new DefaultBinaryMessenger(dartMessenger);
它的send方法是:
public void send(@NonNull String channel, @Nullable ByteBuffer message) { messenger.send(channel, message, null); }
可见其实就是调用了DartMessenger的send方法:
public void send(@NonNull String channel, @NonNull ByteBuffer message) { Log.v(TAG, "Sending message over channel '" + channel + "'"); send(channel, message, null); } @Override public void send( @NonNull String channel, @Nullable ByteBuffer message, @Nullable BinaryMessenger.BinaryReply callback) { Trace.beginSection("DartMessenger#send on " + channel); Log.v(TAG, "Sending message with callback over channel '" + channel + "'"); try { 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); } } finally { Trace.endSection(); } }
可见最后调用了FlutterJNI来发送数据。
在DartMessenger中还定义了一个方法:handleMessageFromDart,这个方法是在收到任何Channel的消息时就会被FlutterJNI调用。
@Override public void handleMessageFromDart( @NonNull final String channel, @Nullable ByteBuffer message, final int replyId, long messageData) { // Called from the ui thread. Log.v(TAG, "Received message from Dart over channel '" + channel + "'"); @Nullable final HandlerInfo handlerInfo = messageHandlers.get(channel); @Nullable final DartMessengerTaskQueue taskQueue = (handlerInfo != null) ? handlerInfo.taskQueue : null; Runnable myRunnable = () -> { Trace.beginSection("DartMessenger#handleMessageFromDart on " + channel); try { invokeHandler(handlerInfo, message, replyId); ... ... } finally { // This is deleting the data underneath the message object. flutterJNI.cleanupMessageData(messageData); Trace.endSection(); } }; @NonNull final DartMessengerTaskQueue nonnullTaskQueue = taskQueue == null ? platformTaskQueue : taskQueue; nonnullTaskQueue.dispatch(myRunnable); }
核心代码在invokeHandler中:
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); } }
到这一步为止,所有的Channel都会走上面的逻辑,从这里的handlerInfo.handler.onMessage开始有所不一样了,因为不同的Channel的handler不同。
-
EventChannel
EventChannel通过setStreamHandler方法设置handler:
@UiThread public void setStreamHandler(final StreamHandler handler) { if (taskQueue != null) { messenger.setMessageHandler( name, handler == null ? null : new IncomingStreamRequestHandler(handler), taskQueue); } else { messenger.setMessageHandler( name, handler == null ? null : new IncomingStreamRequestHandler(handler)); } }
可见,这里设置的handler其实是IncomingStreamRequestHandler,它的onMessage方法如下:
@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); } }
为什么这里会判断method的名字是“listen”和“cancel”呢?我们来看dart端发送的逻辑。
之前博文我们知道,dart监听的代码为:eventChannel.receiveBroadcastStream().listen(...),receiveBroadcastStream方法为:
Stream
receiveBroadcastStream([ dynamic arguments ]) { final MethodChannel methodChannel = MethodChannel(name, codec); late StreamController controller; controller = StreamController .broadcast(onListen: () async { binaryMessenger.setMessageHandler(name, (ByteData? reply) async { if (reply == null) { controller.close(); } else { try { controller.add(codec.decodeEnvelope(reply)); } on PlatformException catch (e) { controller.addError(e); } } return null; }); try { await methodChannel.invokeMethod ('listen', arguments); } catch (exception, stack) { FlutterError.reportError(FlutterErrorDetails( exception: exception, stack: stack, library: 'services library', context: ErrorDescription('while activating platform stream on channel $name'), )); } }, onCancel: () async { binaryMessenger.setMessageHandler(name, null); try { await methodChannel.invokeMethod ('cancel', arguments); } catch (exception, stack) { FlutterError.reportError(FlutterErrorDetails( exception: exception, stack: stack, library: 'services library', context: ErrorDescription('while de-activating platform stream on channel $name'), )); } }); return controller.stream; } broadcast方法会返回 _AsyncBroadcastStreamController ,它的stream在其父类 _BroadcastStreamController中实现,得到的是 _BroadcastStream,现在我们知道 _AsyncBroadcastStreamController中持有了onListen和onCancel回调,再来看 _BroadcastStream的listen方法,这个方法最终在 _StreamImpl中找到:
StreamSubscription
listen(void onData(T data)?, {Function? onError, void onDone()?, bool? cancelOnError}) { cancelOnError ??= false; StreamSubscription subscription = _createSubscription(onData, onError, onDone, cancelOnError); _onListen(subscription); return subscription; } _createSubscription方法在 _StreamImpl的上一级子类 _ControllerStream中重写:
StreamSubscription
_createSubscription(void onData(T data)?, Function? onError, void onDone()?, bool cancelOnError) => _controller._subscribe(onData, onError, onDone, cancelOnError); 我们知道 _BroadcastStream的 _controller就是前面的 _AsyncBroadcastStreamController, _subscribe方法在 _BroadcastStreamController中实现:
StreamSubscription
_subscribe(void onData(T data)?, Function? onError, void onDone()?, bool cancelOnError) { if (isClosed) { return new _DoneStreamSubscription (onDone); } var subscription = new _BroadcastSubscription ( this, onData, onError, onDone, cancelOnError); _addListener(subscription); if (identical(_firstSubscription, _lastSubscription)) { // Only one listener, so it must be the first listener. _runGuarded(onListen); } return subscription; } 这里会把创建的_BroadcastSubscription通过 _addListener方法添加到一个链表结构中:
void _addListener(_BroadcastSubscription
subscription) { assert(identical(subscription._next, subscription)); subscription._eventState = (_state & _STATE_EVENT_ID); // Insert in linked list as last subscription. _BroadcastSubscription ? oldLast = _lastSubscription; _lastSubscription = subscription; subscription._next = null; subscription._previous = oldLast; if (oldLast == null) { _firstSubscription = subscription; } else { oldLast._next = subscription; } } 然后执行_runGuarded方法,还记得onListen是什么吗,就是前面broadcast方法里传入的onListen回调函数, _runGuarded方法就是执行它:
void _runGuarded(void Function()? notificationHandler) { if (notificationHandler == null) return; try { notificationHandler(); } catch (e, s) { Zone.current.handleUncaughtError(e, s); } }
我们回过头来看onListen里面做了什么。
回看上面的receiveBroadcastStream方法的代码,我们发现,onListen中其实就是使用一个MethodChannel来invokeMethod的,方法名正是“listen”,调用invokeMethod方法之后会调用到原生绑定的同名EventChannel设置的StreamHandler的onListen方法中。
所以现在就可以理解IncomingStreamRequestHandler的onMessage方法的逻辑了,回到onMessage方法,接着会调用IncomingStreamRequestHandler的onListen方法:
private void onListen(Object arguments, BinaryReply callback) { final EventSink eventSink = new EventSinkImplementation(); final EventSink oldSink = activeSink.getAndSet(eventSink); if (oldSink != null) { // Repeated calls to onListen may happen during hot restart. // We separate them with a call to onCancel. try { handler.onCancel(null); } catch (RuntimeException e) { Log.e(TAG + name, "Failed to close existing event stream", e); } } try { handler.onListen(arguments, eventSink); callback.reply(codec.encodeSuccessEnvelope(null)); } catch (RuntimeException e) { activeSink.set(null); Log.e(TAG + name, "Failed to open event stream", e); callback.reply(codec.encodeErrorEnvelope("error", e.getMessage(), null)); } }
这里的callback.reply会回调到系统的Platform的Channel中,是系统级通知,和我们的业务不相关。可以看到,传到StreamHandler的eventSink是EventSinkImplementation,它对EventSink的实现如下:
@Override @UiThread public void success(Object event) { if (hasEnded.get() || activeSink.get() != this) { return; } EventChannel.this.messenger.send(name, codec.encodeSuccessEnvelope(event)); } @Override @UiThread public void error(String errorCode, String errorMessage, Object errorDetails) { if (hasEnded.get() || activeSink.get() != this) { return; } EventChannel.this.messenger.send( name, codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails)); } @Override @UiThread public void endOfStream() { if (hasEnded.getAndSet(true) || activeSink.get() != this) { return; } EventChannel.this.messenger.send(name, null); }
可见,EventChannel发送给Flutter端的方式也是通过内部的BinaryMessenger来完成的,只不过它的messenger是私有的且没提供任何方法可以直接操作它,这就使得EventChannel向Flutter端的发送基于Flutter的发送请求,也就是说,只有Flutter通过同名的EventChannel向原生发送数据之后,原生EventChannel才能在接收回调中通过EventSinkImplementation这个入口调用BinaryMessenger来完成向Flutter端的发送,这也是EventChannel区别于MethodChannel的关键所在。
这里调用EventChannel的messenger的send方法后,会回调到flutter端,前面我们知道broadcast方法设置的onListen回调函数中,binaryMessenger设置了MessageHandler回调函数。
回看代码可知,先看reply(即EventSink的messenger发送的数据)如果不为空的情况,会调用controller的add方法,参数是原生返回的数据,add逻辑绕了很大的一圈之后(感兴趣的可以自己看,太多了就不贴了)会走到_BufferingStreamSubscription的 _sendData 方法中,里面有一句:
_zone.runUnaryGuarded(_onData, data);
_onData就是Stream的listen方法传入的onData函数,最终runUnaryGuarded会执行onData函数,通常我们会在onData函数中更新UI或者其他的操作,比如:
eventChannel.receiveBroadcastStream().listen( (event) { onReceiveBatteryChange(event); }, onError: onReceiveBatteryWrong, onDone: onReceiveBatteryDone );
如果在add流程中出错了则会调用controller的addError方法走出错逻辑,这个时候会回调到上面的onError回调函数中,原理同add一样。当你不再需要时,原生端可以调用eventSink.endOfStream方法,这时发送的message就是null,从而在flutter端的MessageHandler中会走reply为null的逻辑,即会调用controller.close方法,最终会调用onDone回调。
这样完成了一次完整的EventChannel的通信过程。
小记.
上面的onError是一个Function类型,其并没有指定Function的参数和返回值,但是静态编译时会有警告,运行就会出错,经查,在应用过程中会有类型检查从而导致运行报错:
static Function _registerErrorHandler(Zone zone, Function? handleError) { // TODO(lrn): Consider whether we need to register the null handler. handleError ??= _nullErrorHandler; if (handleError is void Function(Object, StackTrace)) { return zone .registerBinaryCallback
(handleError); } if (handleError is void Function(Object)) { return zone.registerUnaryCallback (handleError); } throw new ArgumentError("handleError callback must take either an Object " "(the error), or both an Object (the error) and a StackTrace."); } 所以,Flutter不只是有方法定义处的Function限制,在运行流程中凡是用到的地方不符合都会报错,而编译时只是会提示警告而已。
-
MethodChannel
MethodChannel的大体流程和EventChannel是大致相同的,只不过有几点不太一样。
MethodChannel有公开方法invokeMethod,所以它可以主动随时发送数据,不像EventChannel需要Flutter端的listen发起。
EventChannel虽然也是调用的MethodChannel的invokeMethod方法回调到原生的onListen中,但是它的方法名固定是“listen”,而且不能传自定义参数,所以它本身是为了和原生建立起连接,告诉原生把有价值的数据传给哪个EventChannel,然后Flutter端会有回调来通过这个约定的EventChannel接收;而MethodChannel则可以用来调用两端的任何方法,传递任何参数。
-
MethodChannel通过setMethodCallHandler方法设置MethodCallHandler,BinaryMessenger的setMessageHandler方法传入的BinaryMessageHandler是IncomingMethodCallHandler,它的onMessage方法的逻辑是:
@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, getStackTrace(e))); } }
最终在onMethodCall中调用result的success、error或notImplemented方法来返回结果数据,以Fluter端发送给原生端为例,Flutter端会接收到一个Future实例,通过它可以取得返回数据:
Future result = await methodChannel.invokeMethod("getName");
-
BasicMessageChannel
同样,BasicMessageChannel也是一样的原理,不同的是:
和MethodChannel相比,它的公开发送数据的api方法是send。
-
它的BinaryMessageHandler设置的是IncomingMessageHandler,IncomingMessageHandler的onMessage方法是:
@Override public void onMessage(@Nullable ByteBuffer message, @NonNull final BinaryReply callback) { try { handler.onMessage( codec.decodeMessage(message), new Reply
() { @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); } } 可见,它的回调方法是MessageHandler的onMessage。
可以看到,其实BasicMessageChannel和MethodChannel很相似,只不过它这里接收到的“数据”就是数据,而MethodChannel接收到的“数据”是方法名,我们要根据方法名去调不同的方法。
-
总结
可见,这三种Channel的原理殊途同归,其实是一样的,内部都是通过DartMessenger来调用FlutterJNI的相关API完成通信的,只不过Flutter对他们做了不同的封装以适用不同的场景。
- EventChannel的作用是为了提供一个专门的通道,原生端通过这个专门的通道发送数据给Flutter端,从而Flutter端监听的位置可以及时响应这个变化,它需要dart端调用listen方法建立和原生的连接,只能是从原生端往Flutter端发送。
- MethodChannel是为了两端的方法调用,两端都可以发送和传输,传递的数据是方法的名字,在onMethodCall回调中根据方法名是什么来执行不同的操作。
- BasicMessageChannel是为了普通的数据传输,回调中获取的就是实际的数据,它代表的就是数据本身,同样可以两端互传和接收。