flutter插件开发需要了解的EventChannel与MethodChannel
- 2020 年 1 月 8 日
- 筆記
在flutter插件开发中,EventChannel
与MethodChannel
是两个不可避免的类。我们要了解它,最好先记住它通常用来干嘛。
MethodChannel用通俗的语言来描述它的作用就是,当你像在flutter端调用native功能的时候,可以用它。
EventChannel用通俗的语言来描述就是,当native想通知flutter层一些消息的时候,可以用它。
这两个channel是如何打通的
要用这两个桥梁,首先要明白它是怎么打通的,我们应该对这段代码不陌生:
public static void registerWith(Registrar registrar) { TipFlutterImageViewPlugin plugin = new TipFlutterImageViewPlugin(registrar, registrar.context()); final MethodChannel channel = new MethodChannel(registrar.messenger(), "com.tencent.igame/flutter_image_view_method"); final EventChannel eventChannel = new EventChannel(registrar.messenger(), "com.tencent.igame/flutter_image_view_event"); channel.setMethodCallHandler(plugin); eventChannel.setStreamHandler(plugin); }
在你create一个插件工程的时候,flutter脚手架是会为你生成一个名字为XXXPlugin的类,里面就有这么一个registerWith
的方法。两个Channel都是在这里注册的。那么,这段代码在何处被调用的呢?我们可以看看插件代码的android工程;
public final class GeneratedPluginRegistrant { public static void registerWith(PluginRegistry registry) { if (alreadyRegisteredWith(registry)) { return; } XXXPlugin.registerWith(registry.registrarFor("com.tencent.igame.tip_flutter_image_view.TipFlutterImageViewPlugin")); } private static boolean alreadyRegisteredWith(PluginRegistry registry) { final String key = GeneratedPluginRegistrant.class.getCanonicalName(); if (registry.hasPlugin(key)) { return true; } registry.registrarFor(key); return false; } }
然后这个静态方法在MainActivity的onCreate中被调用了。
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); }
到registerWith被调用为止,两个Channel被注册了而已,它还并没有和flutter关联起来,此时我们也不急,先看看,我们可以了解到的是registerWith被调用了一次,因此XXXPlugin只有一个实例,MethodChannel和EventChannel是其成员,也只有一个。好,接下来,flutter关联上这了两个Channel。
flutter连接上Channel
eventChannel = new EventChannel('com.tencent.igame/flutter_image_view_event') .receiveBroadcastStream(url) .map((dynamic event) => _parseState(event)); methodChannel = new MethodChannel('com.tencent.igame/flutter_image_view_method');
一般可以放在flutter页面的initState做。
此时,我们flutter调用原生可以使用
//flutter端 _channel.invokeMethod('method',{}) //原生端 public void onMethodCall(MethodCall call, Result result) { if (call.method.equals("create")) { //xxxx } }
此时,原生发送消息到flutter可以
//原生端发送消息 public void onListen(Object args, EventChannel.EventSink eventSink) { eventSink.success() //eventSink.error(); } //flutter端接收消息 eventChannel.listen((data) { //xxxx });
至此,整个流程打通了,如果就这样完了的话,这篇文章可以改名叫做《EventChannel与MethodChannel的使用》了。
EventChannel的猫腻
EventChannel其实是基于MethodChannel实现的,不信,我们可以看源码:
Stream<dynamic> receiveBroadcastStream([ dynamic arguments ]) { final MethodChannel methodChannel = MethodChannel(name, codec); StreamController<dynamic> controller; controller = StreamController<dynamic>.broadcast(onListen: () async { defaultBinaryMessenger.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<void>('listen', arguments); } catch (exception, stack) { //xxx/ }, onCancel: () async { defaultBinaryMessenger.setMessageHandler(name, null); try { await methodChannel.invokeMethod<void>('cancel', arguments); } catch (exception, stack) { //xxxx }); return controller.stream; } }
说的没错把,这里就是通过methodChannel去调用在原生那边实现的方法:
onListen(Object args, EventChannel.EventSink eventSink) onCancel(Object args)
好的,我们的认识更进了一步,那么,在问一个问题,如果多次注册同一个EventChannel并listen,那么每个都有效吗?
就直接说答案了,并不是每个都有效,有效的只是最后注册的那一个。
还记得我们的plugin的实例只有一个吗?还记得其中的成员EventChannel也只有一个吗?那么,在flutter端调用多次
eventChannel = new EventChannel('com.tencent.igame/flutter_image_view_event') .receiveBroadcastStream(url) .map((dynamic event) => _parseState(event));
显然只有最后一次会生效,其他是收不到消息的。
EventChannel可以有多个吗?
这个当然是没问题的,多个EventChannel只需要在registerWith方法中注册一一进行注册就OK了。