Flutter在Android中的应用

    技术2022-07-11  104

    对于Flutter 混合开发比较多,通信必不可少。

    一、Channel:

    Android与Flutter之间的通信可以通过三种Channel:

    EventChannel 仅支持数据单向传递,无返回值。用于数据流的通信,持续通信,收到消息后无法回复此次消息。通常用于 Native 向 Dart 的通信。

    MethodChannel支持数据双向传递,有返回值。用于传递方法调用,一次性通信。通常用于 Dart 调用 Native 的方法。

    BasicMessageChannel支持数据双向传递,有返回值。

    三种Channel之间互相独立,各有用途,但它们在设计上却非常相近。每种Channel均有三个重要成员变量:

    参数:

    name: String类型,代表Channel的名字,也是其唯一标识符。messager:BinaryMessenger类型,代表消息信使,是消息的发送与接收的工具。codec: MessageCodec类型或MethodCodec类型,代表消息的编解码器。

    (一) channel name 唯一标识

    需要两段一致,且唯一。具体用处见下面

    (二)  BinaryMessenger 消息快递员

    定义:三种channel与Flutter通信的工具,都是BinaryMessager

    可接纳数据:二进制格式数据

    端上表现形式: Android:FlutterNativeView 接口;   Ios:FlutterBinaryMessenger协议

    运行流程:

    初始化Channel,向Channel注册处理消息的Handler时,会生成一个与之对应的BinaryMessageHandler,并以channel name(上文提到的)为key,注册到BinaryMessenger中。

    当Flutter端发送消息到BinaryMessenger时,BinaryMessenger会根据其入参channel找到对应的BinaryMessageHandler,并交由其处理。

    意义:

    Channel和BinaryMessageHandler一一对应的,Binarymessenger并不知道Channel的存在,它只和BinaryMessageHandler打交道。

    实现:

    Android:BinaryMessenger是一个接口,在FlutterView中实现了该接口,在BinaryMessenger的方法中通过JNI来与系统底层沟通。

    Flutter:BinaryMessenger是一个类,该类的作用就是与类window沟通,而类window才真正与系统底层沟通。

    (三)  解码器(codec):消息包装器

    原理:​ 由于Channel从BinaryMessageHandler接收到的消息是二进制格式数据,无法直接使用,故Channel会将该二进制消息通过Codec(消息编解码器)解码为能识别的消息并传递给Handler进行处理。

    当Handler处理完消息之后,会通过回调函数返回result,并将result通过编解码器编码为二进制格式数据,通过BinaryMessenger发送回Flutter端。

    定义:MessageCodec、MethodCodec;

    存在意义:将BinaryMessager流通的二进制类型数据 转换成 Handler可识别的数据。

     

    1、MessageCodec

    Android中,MessageCodec是一个接口,定义了两个方法:encodeMessage 接收一个特定的数据类型T,并将其编码为二进制数据ByteBuffer;decodeMessage 接收二进制数据ByteBuffer,将其解码为特定数据类型T。

    iOS中,FlutterMessageCodec,是一个协议,定义了两个方法:encode 接收一个类型为id的消息,将其编码为NSData类型;decode 接收NSData类型消息,将其解码为id类型数据。

    有多种不同的实现:

    *BinaryCodec

    最简单,返回值类型和入参的类型相同,均为二进制格式(Android中为ByteBuffer,iOS中为NSData),看似透传。 but某些情况下它非常有用,比如使用BinaryCodec可以使传递内存数据块时在编解码阶段免于内存拷贝。

    *StringCodec

    字符串与二进制数据之间的编解码,其编码格式为UTF-8。

    *JSONMessageCodec

    基础数据与二进制数据之间的编解码,支持基础数据类型以及列表、字典。

    iOS端使用了NSJSONSerialization作为序列化的工具;

    Android端则使用了其自定义的JSONUtil与StringCodec作为序列化工具。

    *StandardMessageCodec

    BasicMessageChannel的默认编解码器,其支持基础数据类型、二进制数据、列表、字典

     

    2、MethodCodec(常用)

    用于二进制数据与方法调用(MethodCall)和返回结果之间的编解码。

    用于【MethodCall】对象的编解码。一个MethodCall对象代表一次从Flutter端发起的方法调用。

    MethodCall组成:String 方法名称 (代表需要调用method)、通用类型arguments代表需要调用的方法入参。

    相比于MessageCodec,MethodCodec多了对调用结果的处理。

    当方法调用成功时,使用encodeSuccessEnvelope将result编码为二进制数据,而当方法调用失败时,则使用encodeErrorEnvelope将error的code、message、detail编码为二进制数据。

    实现方式: *JSONMethodCodec

    *StandardMethodCodec

     

    ##### Flutter默认的编解码器是StandardMessageCodec,其支持的数据类型如下:

     

    总结下流程:

     

    (四). 消息处理器:Handler

    ​ 当我们接收二进制格式消息并使用Codec将其解码为Handler能处理的消息后,就该Handler上场了。Flutter定义了三种类型的Handler,与Channel类型一一对应。我们向Channel注册一个Handler时,实际上就是向BinaryMessager注册一个与之对应的BinaryMessageHandler。当消息派分到BinaryMessageHandler后,Channel会通过Codec将消息解码,并传递给Handler处理。

    1. MessageHandler

    ​ MessageHandler用户处理字符串或者半结构化的消息,其onMessage方法接收一个T类型的消息,并异步返回一个相同类型result。MessageHandler的功能比较基础,使用场景较少,但是其配合BinaryCodec使用时,能够方便传递二进制数据消息。

    2. MethodHandler

    ​ MethodHandler用于处理方法的调用,其onMessage方法接收一个MethodCall类型消息,并根据MethodCall的成员变量method去调用对应的API,当处理完成后,根据方法调用成功或失败,返回对应的结果。

    3. StreamHandler

    StreamHandler与前两者稍显不同,用于事件流的通信,最为常见的用途就是Platform端向Flutter端发送事件消息。当我们实现一个StreamHandler时,需要实现其onListen和onCancel方法。而在onListen方法的入参中,有一个EventSink(其在Android是一个对象,iOS端则是一个block)。我们持有EventSink后,即可通过EventSink向Flutter端发送事件消息。

    ​ 实际上,StreamHandler工作原理并不复杂。当我们注册了一个StreamHandler后,实际上会注册一个对应的BinaryMessageHandler到BinaryMessager。而当Flutter端开始监听事件时,会发送一个二进制消息到Platform端。Platform端用MethodCodec将该消息解码为MethodCall,如果MethodCall的method的值为"listen",则调用StreamHandler的onListen方法,传递给StreamHandler一个EventSink。而通过EventSink向Flutter端发送消息时,实际上就是通过BinaryMessager的send方法将消息传递过去。

     

    二、问题解析

    1、 Platform Channel的代码运行在什么线程

    Flutter Engine自己不创建线程,其线程的创建于管理是由enbedder提供的,并且Flutter Engine要求Embedder提供四个Task Runner,分别是Platform Task Runner,UI Task Runner,GPU Task Runner和IO Task Runner。

    ​ 实际上,在Platform侧执行的代码运行在Platform Task Runner中,而在Flutter app侧的代码则运行在UI Task Runner中。在Android和iOS平台上,Platform Task Runner跑在主线程上。因此,不应该在Platform端的Handler中处理耗时操作。

     

    2、Platform Channel是否线程安全

    ​非线程安全的,这一点在官方的文档也有提及。Flutter Engine中多个组件是非线程安全的,故跟Flutter Engine的所有交互(接口调用)必须发生在Platform Thread。故我们在将Platform端的消息处理结果回传到Flutter端时,需要确保回调函数是在Platform Thread(也就是Android和iOS的主线程)中执行的。

     

    Processed: 0.022, SQL: 9