【Flutter】FlutterChannel详解

1 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 的主线程)中执行的。

2 FlutterChannel使用

2.1 BasicMessageChannel使用

BasicMessageChannel主要用于传递字符串和半结构化信息。如果需要监听消息,则调用setMessageHandler,如果要发送消息,则调用send

2.1.1 Flutter发送消息给原生
  • 在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")
        }
    }

}
  • 在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),
      ), //
    );
  }

}

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

2.1.1 原生发送消息给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
        )
        //发送数据
        mChannel.send("dddddd");
    }

}

Flutter端

static const _channel = BasicMessageChannel("myflutterfragment/searchscandata", StandardMessageCodec());

	_channel.setMessageHandler((message){
      print('$message')
      return Future(() => "");
    });

2.2 MethodChannel使用

2.2.1 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")
            }
        }
    }
  • 在flutter端创建MethodChannel,注意method名称和native那边的一致。
  void getNativeMethod() async{
    String result = await _platform.invokeMethod("flutterMethod");
    print("flutterMethod:$result");
  }

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

2.2.2 Native调用Flutter的方法

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

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

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

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

2.3 EventChannel

待续…

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flutter开发实战详解PDF》是一本介绍如何使用Flutter进行实际开发的书籍。Flutter是由谷歌开发的一款跨平台框架,可以用来开发iOS、Android、Web和桌面应用程序。这本书涵盖了从Flutter基础知识到高级开发技巧的各个方面。 《Flutter开发实战详解PDF》首先介绍了Flutter的基本概念和工具,帮助读者快速入门。接着,书中详细讲解了Flutter的布局和UI组件,包括文本、按钮、图片等常用控件的使用方法。读者可以通过学习这些内容,了解如何构建一个漂亮、流畅的用户界面。 在基础知识介绍之后,书中通过实例介绍了如何进行网络请求、与后台进行数据交互。读者可以学习到如何使用Flutter的Http库来进行网络请求,并将获取到的数据展示在应用程序中。此外,书中还介绍了如何使用Flutter与数据库进行交互,以及如何处理用户输入和使用设备传感器。 《Flutter开发实战详解PDF》还提供了一些高级开发技巧和实践经验,例如如何进行状态管理、如何优化性能等。这些内容对于有一定Flutter开发经验的开发者来说尤为重要。 总的来说,这本书通过实例和案例的方式,详细讲解了Flutter的开发实践。无论是初学者还是有一定经验的开发者,都可以从中学到很多实用的技巧和知识。如果你想深入学习Flutter的开发,这本书是一个不错的选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值