Flutter Platform Channel深度解析

一、简介


Platform Channel 是 Flutter 端与 Platform 端制定的通信机制,由官方提供用于 Dart 和平台之间的相互通信。


分为以下 3 种

(1)BaseMessageChannel :用于传递字符串和半结构化的信息(在大内存数据块传递的情况下使用)

(2)MethodChannel:用于传递方法调用(Method Invocation)

(3)EventChannel: 用于数据流(Event Streams)的通信


二、消息传递与编码器


Flutter 的消息传递工具是 BinaryMessager ,通过它与 Platform 建立起通信关系,消息以二进制的格式进行传递。


dc5d306b795b9a717514783f7a90a758.png


如图所示 BinaryMessager 的传递需要经过 BinaryMessageHandler,BinaryMessagerHandler 是以 Channel Name 作为键值生成出来再被注册到 BinaryMessager 上的,BinaryMessageHandler 和 BinaryMessager 是一一对应的,二进制格式的消息通过消息编码器(Codec)解码为可识别的信息,并传递给 Handler 进行处理。Handler 处理完后,会把结果编码为二进制格式,再通过回调函数返回结果并发送回 Flutter 端。


1.编码器分类


(1)MessageCodec:BinaryCodec、StringCodec、JSONMessageCodec、StandardMessageCodec

(2)MethodCodec:JSONMethodCodec、StandardMessageCodec


5386494ecf1a673dd15edcce15503484.png


经过消息编码器处理后,消息就可以被 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 ,支持的数据类型如下:



F3.png

三、MethodChannel


MethodChannel 是 Flutter 与 Platform 之间传递信息的一种,其传递过程是:BinaryMessager > BinaryMessagerHandler > MethodChannel。


e581b38a71d71ff5d9f3f0b0185c4799.png


如上图: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 方法在不同平台有不同的实现,但是其基本原理是相同的。


88d495138178518104bb77218c8e9cb5.png


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 发起的方法调用就完整结束了。


五、具体使用


88301e6218156a4f9be6a81a0ad446f5.png


1.Flutter 端调用 Android 方法


2.Android 端代码


(1)继承 MethodCallHandler 并设置 Handler ,MethodChannel 需要保存在对象一会调用回调时需要使用,onMethodCall 为 Flutter 层回调的方法这边用 RCIMFlutterWrapper 承接处理。


db72968a6a663c7ff2443e602da5fd4f.png


(2)RCIMFlutterWrapper 类中处理, MethodCall 的 Method,对应 Flutter 层调用 invokeMethod 方法的传入的第一个参数,两端需完全对应一致。


spacer.gifF8.png

74623466ba75ade42664448af9198c94.png


(3)直接通过 result 对象回调回去,这样就能将结果回调。


3.关于 Android 回调 Flutter 的使用


6e48682b7dc657ce12721485dcef8f7f.png


(1)Flutter 端回调监听,设置监听 Key 两端对应。


0e48e8f25e554965e8b2b84e8b0bb9d7.png


(2)Android 端代码回调,mChannel.invokeMethod 方法将数据回调给 Flutter 层。


猜你喜欢

转载自blog.51cto.com/14206262/2619015