【融云分析】Flutter Platform Channel深度解析

【融云分析】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层。

       

标签: , ,