【融云分析】Flutter Platform Channel深度解析
一、简介
Platform Channel 是Flutter端与Platform端制定的通信机制,由官方提供用于Dart和平台之间的相互通信。
分为以下3种
(1)BaseMessageChannel:用于传递字符串和半结构化的信息(在大内存数据块传递的情况下使用)
(2)MethodChannel:用于传递方法调用(Method Invocation)
(3)EventChannel:用于数据流(Event Streams)的通信
二、消息传递与编码器
Flutter 的消息传递工具是BinaryMessager,通过它与Platform建立起通信关系,消息以二进制的格式进行传递。
如图所示BinaryMessager的传递需要经过BinaryMessageHandler,BinaryMessagerHandler是以ChannelName 作为键值生成出来再被注册到BinaryMessager上的,BinaryMessageHandler和BinaryMessager是一一对应的,二进制格式的消息通过消息编码器(Codec)解码为可识别的信息,并传递给Handler进行处理。Handler处理完后,会把结果编码为二进制格式,再通过回调函数返回结果并发送回Flutter端。
1.编码器分类
(1)MessageCodec:BinaryCodec、StringCodec、JSONMessageCodec、StandardMessageCodec
(2)MethodCodec:JSONMethodCodec、StandardMessageCodec
经过消息编码器处理后,消息就可以被Handler进行处理了。
2.消息编码过程
Android 端的返回值是java.lang.Integer类型的,而 iOS 端返回值则是一个NSNumber类型的(通过NSNumber numberWithInt:获取)。而到了 Flutter 端时,这个返回值自动“变成 ”了 Dart 语言的 Int 类型。
standard platform channels使用standard messsage codec对message和response进行序列化和反序列化,message与response可以是booleans,numbers,Strings,byte buffers,List,Maps等等,而序列化后得到的则是二进制格式的数据。
Flutter 默认的消息编码器是StandardMessageCodec,支持的数据类型如下:
三、MethodChannel
MethodChannel 是Flutter与Platform 之间传递信息的一种,其传递过程是:BinaryMessager > BinaryMessagerHandler > MethodChannel。
如上图:Native端(iOS和Android)为宿主端(host),Flutter 则是客户端(client),Flutter调用Native方法时,需要传递的信息是通过平台通道传递到宿主端的,Native收到调用的信息后方可执行指定的操作。如有返回的数据,则Native会将数据再通过平台通道一并传递给Flutter,其中数据传递是异步的,这样就能确保消息传递时用户界面不会被阻塞。
1.Flutter 层(Dart层)
Flutter 端使用MethodChannel的invokeMethod方法发起一次方法调用时,开始了消息传递流程。invokeMethod方法会将其入参 message 和arguments封装成一个MethodCall对象,并使用MethodCodec将其编码为二进制格式数据,再通过BinaryMessages将消息发出。(注意,此处提到的类名与方法名均为Dart 层的实现)
上述过程最终会调用到ui.Window的_sendPlatformMessage方法,该方法是一个 Native 方法,其实现在 Native 层,这与Java的 JNI 技术非常类似。我们向Native 层发送了三个参数:
• name,String类型,代表 Channel 名称
• data,ByteData 类型,即之前封装的二进制数据
• callback,Function类型,用于结果回调
2.Native 层
到Native 层后,window.cc的SendPlatformMessage方法接受了来自 Dart 层的三个参数,并对它们做了一定的处理:Dart 层的回调callback封装为 Native 层的PlatformMessageResponseDart类型的response;dart层的二进制数据data转化为std::vector<uint8t>类型数据data;根据response, data以及Channel名称name创建一个PlatformMessage对象,并通过 dartstate->window()->client()->HandlePlatformMessage 方法处理PlatformMessage对象。
dart_state->window()->client() 是一个WindowClient,而其具体的实现为RuntimeController,RuntimeController会将消息交给其代理RuntimeDelegate处理。
RuntimeDelegate 的实现为Engine,Engine在处理Message时,会判断该消息是否是为了获取资源(channel等于”flutter/assets”),如果是,则走获取资源逻辑,否则调用Engine::Delegate的OnEngineHandlePlatformMessage方法。
Engine::Delegate 的具体实现为 Shell,其OnEngineHandlePlatformMessage接收到消息后,会向PlatformTaskRunner添加一个 Task,该Task会调用PlatformView的HandlePlatformMessage方法。值得注意的是,Task中的代码执行在Platform Task Runner中,而之前的代码均执行在UI Task Runner中。
四、消息处理
PlatformView 的HandlePlatformMessage方法在不同平台有不同的实现,但是其基本原理是相同的。
1.PlatformView
AndroidPlatformViewAndroid 是Platformview的子类,也是其在Android端的具体实现。当PlatformViewAndroid接收到 PlatformMessage 类型的消息时,如果消息中有response(类型为PlatformMessageResponseDart),则生成一个自增长的 responseid,并以responseid为 key,response为value存入字典pendingresponses中。接着,将channel和data均转化为Java可识别的数据,通过 JNI 向 Java 层发起调用,将response_id、channel和data传递过去。
Java 层中,被调用的代码为FlutterNativeView (BinaryMessager的具体实现)的handlePlatformMessage,该方法会根据channel找到对应的BinaryMessageHandler并将消息传递给它处理。
BinaryMessageHandler 处理完成后,FlutterNativeView会通过JNI调用native的方法,将responsedata和responseid传递到 native 层。
Native 层,PlatformViewAndroid的InvokePlatformMessageResponseCallback接收到了respondid和responsedata。其先将responsedata转化为二进制结果,并根据responseid,从pandingresponses中找到对应的PlatformMessageResponseDart对象,调用其Complete方法将二进制结果返回。
2.PlatformViewIOS
PlatformViewIOS 是PlatformView的子类,也是其在iOS端的具体实现,当PlatformViewIOS接收到message时会交给 PlatformMessageRouter 处理。
PlatformMessageRouter 通过PlatformMessage中的channel找到对应的FlutterBinaryMessageHandler,并将二进制消息其处理,消息处理完成后,直接调用PlatformMessage对象中的PlatformMessageResponseDart对象的Complete方法将二进制结果返回。
3.结果回传
PlatformMessageResponseDart 的Complete方法向UI Task Runner添加了一个新的Task,这个Task的作用是将二进制结果从 native 的二进制数据类型转化为Dart的二进制数据类型response,并调用 Dart 的callback将response传递到Dart层。
Dart 层接收到二进制数据后,使用MethodCodec将数据解码,并返回给业务层。至此,一次从Flutter发起的方法调用就完整结束了。
五、具体使用
1.Flutter 端调用Android方法
2.Android 端代码
(1)继承MethodCallHandler并设置Handler,MethodChannel需要保存在对象一会调用回调时需要使用,onMethodCall为Flutter层回调的方法这边用RCIMFlutterWrapper承接处理。
(2)RCIMFlutterWrapper类中处理, MethodCall的 Method,对应Flutter层调用invokeMethod 方法的传入的第一个参数,两端需完全对应一致。
(3)直接通过result对象回调回去,这样就能将结果回调。
3.关于Android回调Flutter的使用
(1)Flutter端回调监听,设置监听Key两端对应。
(2)Android端代码回调, mChannel.invokeMethod方法将数据回调给Flutter层。