• 【Flutter】FlutterChannel详解


    FlutterChannel原理

    Flutter定义了三种不同类型的Channel,分别用于传递字符串和半结构化信息的BasicMessageChannel、用于传递方法调用(method invocation)的MethodChannel以及用于数据流(event streams)通信的EventChannel,如图所示:
    在这里插入图片描述

    三种Channel之间相互独立,各有用途,但在设计上非常相似。每种Channel 均有三个重要的成员变量:String 类型的 name,代表 Channel 的名字,也是其唯一的标识符;BinaryMessenger 类型的 messager,代表消息信使,是消息的发送与接收的工具;MessageCodec 类型或 MethodCodec 类型的 Codec,代表消息的编解码器。

    它们的通信工具都是BinaryMessagerBinaryMessengerPlatform端与Flutter端通信的工具,其通信使用的消息格式为二进制格式数据。当初始化一个 Channel,并向该 Channel注册处理消息的 Handler 时,实际上会生成一个与之对应的 BinaryMessageHandler,并 以 channel name Key,注册到 BinaryMessenger 中。 当Flutter端将消息发送到BinaryMessenger时,BinaryMessenger会根据其入参Channel找到对应的BinaryMessageHandler,并交由其处理。

    BinaryMessenger 并不知道 Channel 的 存 在, 它 只 和 BinaryMessageHandler 打交 道。 而 Channel BinaryMessageHandler 则 是 一 一 对 应 的。由 于 Channel BinaryMessageHandler 接收到的消息是二进制格式数据,无法直接使用,故 Channel 会将该二进制消息通过 Codec(消息编解码器)解码为能识别的消息,并传递给 Handler 处理。

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

    另外,在使用 Platform Channel 时,还需要牢记以下两点:

    • Platform 侧的代码运行在主线程Flutter Engine 自己不创建线程,其线程的创建与管理是由 Embedder 提供的,并且 Flutter Engine 要求 Embedder 提供四个 Task Runner,分别是 Platform Task RunnerUI Task RunnerGPU Task RunnerI/O Task RunnerPlatform 侧执行的代码运行在 Platform Task Runner 中, 而在Flutter App 侧的代码运行在 UI Task Runner 中。在 Android 端和 iOS 端上,Platform Task Runner 运行在主线程上。因此,不应该在 Platform 端的 Handler 中处理耗时操作
    • Platform Channel 并非是线程安全的。这一点在 Flutter 官方文档中也有提及。FlutterEngine 中的多个组件是非线程安全的,故与 FlutterEngine 的所有交互(接口调用)必须发生在 Platform Thread。故在将 Platform 端的消息处理结果回传到Flutter 端时,需要确保回调函数是在 Platform Thread(也就是 AndroidiOS 的主线程)中执行的。

    FlutterChannel使用

    BasicMessageChannel使用

    BasicMessageChannel主要用于传递字符串和半结构化信息。

    • 在FlutterActivity中创建BasicMessageChannel对象,并通过该对象与Flutter侧交互
    class MyFlutterActivity : FlutterActivity() {
    
        companion object{
            fun startActivity(activity: Activity){
                val intent = Intent(activity,MyFlutterActivity::class.java)
                activity.startActivity(intent)
            }
        }
    
        override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
            val channel = BasicMessageChannel(
                flutterEngine.dartExecutor.binaryMessenger,
                "myflutter/testbasicmessagechannel",
                JSONMessageCodec.INSTANCE
            )
    
            channel.setMessageHandler { message, reply ->
                Log.d("MessageChannelTest", "in android Received message = $message")
                reply.reply("Reply from Android")
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 在Flutter侧创建BasicMessageChannel对象,并通过该对象调用send向原生发送数据,并通过它的返回值获取native原生那边返回的数据。
    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    class BasicMessageChannelPage extends StatefulWidget{
      @override
      State<StatefulWidget> createState() => _BasicMessageChannelPage();
    
    }
    
    class _BasicMessageChannelPage extends State<BasicMessageChannelPage>{
    
      static const _channel = BasicMessageChannel("myflutter/testbasicmessagechannel", JSONMessageCodec());
      int i = 0;
      
      void _sendMessage() async{
        final String reply = await _channel.send('hello world $i') as String;
        print('MessageChannelTest in dart $reply');
        setState(() {
          i++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("BasicMessageChannelPage"),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text("You have pushed the button this many times:"),
                Text(
                  '$i',
                  style: Theme.of(context).textTheme.headline4,
                )
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed:_sendMessage,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ), //
        );
      }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    运行结果:
    在这里插入图片描述

    MethodChannel使用

    Flutter调用Native方法

    • 在MyFlutterActivity中创建一个MethodChannel对象,然后通过setMethodCallHandler来处理flutter端调用请求。
    class MyFlutterActivity : FlutterActivity() {
    
        companion object {
            fun startActivity(activity: Activity) {
                val intent = Intent(activity, MyFlutterActivity::class.java)
                activity.startActivity(intent)
            }
        }
    
        override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
            val methodChannel = MethodChannel(
                flutterEngine.dartExecutor.binaryMessenger,
                "methodchannel"
            )
    
            methodChannel.setMethodCallHandler { call, result ->
                if (call.method == "flutterMethod"){
                    Log.d("flutterMethod", "flutter调用native方法")
                    result.success("native传递数据到flutter")
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 在flutter端创建MethodChannel,注意method名称和native那边的一致。
      void getNativeMethod() async{
        String result = await _platform.invokeMethod("flutterMethod");
        print("flutterMethod:$result");
      }
    
    • 1
    • 2
    • 3
    • 4

    结果:
    在这里插入图片描述

    Native调用Flutter的方法

    native调用Flutter方法,如果在FlutterActivity里面调用Flutter页面的方法,此时是无法调用到的,因为Flutter页面还没初始化,没加载进来。所以如果要在native的FlutterActivity里面加载Flutter页面里面的方法,则需要保证Flutter页面已经初始化且加载了。可以考虑:

    • FlutterActivity页面延迟调用Flutter方法
    • 通过Flutter调用原生方法,在原生方法里面实现调用Flutter方法。

    以下是Flutter调用原生,并在原生里面调用flutter,此时flutter一定已经初始化并加载了。

    完整代码请看原生Android调用Flutter的dart方法

    EventChannel

    待续…

  • 相关阅读:
    四川易点慧电子商务抖音小店打造便捷生活新体验
    Java到底能干什么?
    为什么要使用零知识证明来开发跨链协议
    JVM相关知识
    线性调频雷达回波仿真+脉冲压缩仿真
    MacOS - ToDesk 无法远程操控鼠标键盘解决方案
    接口测试工具的实验,Postman、Swagger、knife4j(黑马头条)
    普罗米修斯
    StarRocks从入门到精通系列五:导入数据
    CSS基础选择器总结
  • 原文地址:https://blog.csdn.net/u013293125/article/details/125491116