(原创)Flutter与Native通信的方式:EventChannel和BasicMessageChannel
前言
上一篇博客主要介绍了MethodChannel的使用方式
Flutter与Native通信的方式:MethodChannel
这篇博客接着讲另外两种通信方式
EventChannel和BasicMessageChannel
EventChannel用于从native向flutter发送通知事件,例如flutter通过其监听Android的重力感应变化等。与MethodChannel不同,EventChannel是native到flutter的单向调用,调用是多播(一对多)的,可以类比成Android的Brodcast。
BasicMessageChannel用于在flutter和native互相发送消息,一方给另一方发送消息,收到消息之后给出回复。它和MethodChannel的区别重在一个消息的回复
EventChannel
Android端调用Flutter端
首先是Flutter端代码,创建一个EventChannel并约定好字段:
static const EventChannel _channel = EventChannel('tofluttereventchannel');
然后写好被调用的方法:
void _enableEventReceiver() {//延时3s,先让 Android 端的 EventChannel 进行初始化 , 然后在 Flutter 端注册 EventChannel 监听//这样才能确保连接成功Future.delayed(const Duration(milliseconds: 5000), () {_streamSubscription =_channel.receiveBroadcastStream().listen((dynamic event) {print('收到消息 event: $event');setState(() {mMessage = event;});}, onError: (dynamic error) {print('出现错误 error: ${error.message}');setState(() {errmMessage = error.message;});});});}
_enableEventReceiver方法可以放到Widget的initState()中初始化
在dispose()中调用以下取消监听的方法:
void _disableEventReceiver() {if (_streamSubscription != null) {print("flutter断开连接");//断开连接,这里也会触发android端的onCancel方法_streamSubscription?.cancel();_streamSubscription = null;}}
然后来到Android端,定义两个对象
一个是EventChannel,一个是EventSink:
private lateinit var channel: EventChannelvar eventSink: EventChannel.EventSink? = null
继续在configureFlutterEngine方法中做处理:
channel = EventChannel(flutterEngine.dartExecutor, "tofluttereventchannel")channel.setStreamHandler(object : EventChannel.StreamHandler {override fun onListen(arguments: Any?, events: EventChannel.EventSink) {Log.d("MyFlutterActivity", "已建立连接")eventSink = events}override fun onCancel(arguments: Any?) {Log.d("MyFlutterActivity", "已断开连接")}})
可以看到,其实就是在建立连接后对EventSink对象进行赋值
当eventSink 赋值后,就可以拿他进行消息的发送了
比如:
override fun onResume() {super.onResume()//这里延时执行是为了模拟eventSink初始化后,我们在业务里面进行消息的发送Handler().postDelayed({eventSink?.success("这是来自安卓的消息")//执行了endOfStream后,再发送消息就无效了,所以这行代码要放到endOfStream上面执行eventSink?.error("error code", "这是来自安卓的错误消息", "error details")//结束通信,这时候onCancel会被调用eventSink?.endOfStream()}, 6000)}
这样EventChannel的使用就介绍完了
注意
在实际运行时,可能会发现不起作用
归根结底是注册和调用顺序问题
所以最好在Flutter先延迟一下注册监听
让 Android 端的 EventChannel 先建立连接,
然后在 Flutter 端注册 EventChannel 监听
这样才能确保连接成功
所以用 Future.delayed 进行延时操作
具体可以参考这篇博客:
Flutter 混合开发报错
MessageChannel
MessageChannel重在回调后的消息回复
相对与其他Channel类型的创建,MessageChannel的创建除了channel名以外,还需要指定编码方式。
因为发送的消息会以二进制的形式进行处理,所以要针对不同类型的数进行二进制编码
主要方式有:

下面看具体使用
Flutter端
Flutter端,首先定义BasicMessageChannel
static const messageChannel = BasicMessageChannel('tofluttemessagechannel', StringCodec());
发送消息这样写:
///发送MessageChannel消息,延时一下,确保安卓端先注册了监听才能收到void _sendMessage() {Future.delayed(const Duration(milliseconds: 6000), () async {final String? result = await messageChannel.send('来自flutter主动发送的消息');print("收到安卓端的返回值:${result}");});}
可以看到发送后会拿到返回值result
注册回调,也就是接受消息这样写:
//注册MessageChannel消息监听messageChannel.setMessageHandler((message) async {print('收到安卓端的MessageChannel消息 = $message');setState(() {forNativeMsg = message ?? "";});return '来自flutter返回的消息';});//发送MessageChannel消息
可以看到接收到后也会给到Android端一个返回值
利用BasicMessageChannel,我们就很快的完成了消息的发送和接收
并且每一个操作都可以接受或者传送返回值
Android端
Android端其实和Flutter端几乎一样
首先是定义BasicMessageChannel
//先注册MessageChannelval messageChannel = BasicMessageChannel(flutterEngine.dartExecutor,"tofluttemessagechannel",StringCodec.INSTANCE)
发送消息:
//发送消息Handler().postDelayed({messageChannel.send("来自安卓端主动发送的消息") { result ->Log.d("MyFlutterActivity", "收到flutter端的返回值:$result")}}, 500)
注册回调,也就是接受消息
//先注册监听messageChannel.setMessageHandler { message, reply ->Log.d("MyFlutterActivity", "收到flutter端的MessageChannel消息:"+message)reply.reply("来自安卓端返回的消息")}
注意
这里其实也要注意一个顺序问题
总结起来就是:先注册,后发送
先让被回调的那一端注册监听完成后
再去跨端调用,也就是发送消息
总结
最后来总结一下三种方式的区别:
| 通信方式 | 双端通信 | 指定编码 | 注册顺序 | 使用场景 |
|---|---|---|---|---|
| MethodChannel | 支持 | 否 | 不需要延时注册 | 方法调用 |
| EventChannel | Native单向调用Flutter | 否 | 先建立连接再监听 | 广播通知 |
| BasicMessageChannel | 支持 | 是 | 先注册,再监听 | 用于传递字符串和半结构化的消息 |
源码
源码地址:
EventChannel和BasicMessageChannel
相关资料
这是一份全面 & 详细的Android Native与Flutter的通信方式 学习指南
相关文章:
(原创)Flutter与Native通信的方式:EventChannel和BasicMessageChannel
前言 上一篇博客主要介绍了MethodChannel的使用方式 Flutter与Native通信的方式:MethodChannel 这篇博客接着讲另外两种通信方式 EventChannel和BasicMessageChannel EventChannel用于从native向flutter发送通知事件,例如flutter通过其监听Android的重…...
【解决】el-tree报Cannot read property ‘getCheckedKeys‘ of undefined
如果你报错 Cannot read property getCheckedKeys of undefined 或者 Cannot read property getCheckedNodes of undefined 只要在你的在<el-tree>上加个这个,就可以了 ref"tree"...
车载软件架构 —— 信息安全与基础软件
车载软件架构 —— 信息安全与基础软件 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无需有人关注你。你必须承认自己的价值,你不能站在他人的角度来反对自己。人生在世,最怕…...
C\C++内存管理
目录 1.C/C内存分布2.C语言中动态内存管理方式3.C中动态内存管理3.1new/delete内置类型3.2new和delete操作自定义类型 4.operator new与operator delete函数4.2重载operator new与operator delete(了解) 5.new和delete的实现原理5.1内置类型5.2 自定义类…...
会议室预约系统-检验是否被预约核心SQL
会议室预约时,判断能否被预约,即查询是否已经有预约记录,存在不能被预约。 s,e;表示已经预约的开始结束时间; ns,ne,表示表单提交的预约时间; 只需要(ns,ne)与(s,e)区间没有交集,可…...
C++11类模板
类模板是用来生成类的蓝图,与函数模板的不同之处是,编译器不能为类模板推断模板参数类型。 所以我们在使用类的时候要带上<>并且指定类型如下 vector<int> v; // 需要带上<int> 哦定义类模板 如下,和函数模板差不多都是…...
SpiderFlow爬虫平台(爬虫学习)
申明 作为自己学习的记录,方面后期查阅 官网 SpiderFlow官网 简介 spider-flow 是一个爬虫平台,以图形化方式定义爬虫流程,无需代码即可实现一个爬虫 是使用springboot开发的项目,后端代码直接运行即可使用...
Rime输入法配置
Rime输入法在我电脑上,删了装,装了删,已经反复好几次了。就像是Vim,用它的时候,感觉各种配置太麻烦,想要的功能不知道怎么实现。转用其它编辑器的时候,却又念着它的快捷键和可定制性,…...
R语言学习笔记--列表list、数据框
列表 1-列表 列表可以包含不同类型的对象,也就是说,列表不是将某些具体的值组织起来,而是组织R对象。列表将数据组织在一个一维集合中。 列表非常好用,因为它可以装任何类型的对象,不要求数据之间是同质的。 创建列…...
电磁波定义、特性以及信道相关知识
文章目录 前言一、电磁波的定义、特性、波谱1、电磁波的特性2、电磁波谱的划分及用途 二、地球大气层的结构三、电磁波的传播方式1、地波(ground-wave)2、天波(sky-wave)3、视线传播(line-of-sight)①、相关…...
TCP KeepAlive与HTTP Keep-Alive
TCP KeepAlive与HTTP Keep-Alive TCP KeepAliveHTTP Keep-AliveTCP服务器怎么检测客户端断开连接 TCP KeepAlive TCP连接建立之后,如果应用程序或者上层协议一直不发送数据,或者隔很长时间才发送一次数据,那么TCP需要判断是应用程序掉线了还…...
SkyWalking链路追踪-Agent (代理人)
基础概念: SkyWalking链路追踪代理(SkyWalking Tracing Agent)是一种用于收集和传输链路追踪数据的工具。它与应用程序一起部署,并通过自动或手动方式来收集关于应用程序中的请求路径和操作的信息。该代理将收集到的数据发送到Sky…...
多线程案例 | 单例模式、阻塞队列、定时器、线程池
多线程案例 1、案例一:线程安全的单例模式 单例模式 单例模式是设计模式的一种 什么是设计模式? 设计模式好比象棋中的 “棋谱”,红方当头炮,黑方马来跳,针对红方的一些走法,黑方应招的时候有一些固定的…...
C++文件操作
1.写文件 //文件操作 #include<fstream> int main() {//写文件//路径 -- 此路径没有就生成给文件 string filePath R"(E:\项目\test.txt)";//打开文件 ios::app在后面追加内容 啥也不跟是覆盖写入ofstream fout(filePath, ios::app);//检查是否打开成功if (…...
overleaf(latex) 公式过大,需要调小字体,同时公式编号字体不变的方法
提问:用latex编辑的双列排版的论文中,如果一个包含矩阵的公式中,矩阵过大,导致超出列的范围,一般该如何调整呢? 回答:如果你在LaTeX中的双列排版中遇到了一个矩阵过大而导致超出列范围的问题&a…...
flink采用thrift读取tablets一个天坑
原先的配置 [INFO] StarRocksSourceBeReader [open Scan params.mem_limit 8589934592 B] [INFO] StarRocksSourceBeReader [open Scan params.query-timeout-s 600 s] [INFO] StarRocksSourceBeReader [open Scan params.keep-alive-min 100 min] [INFO] StarRocksSourceBeRea…...
Android 面试题 异常捕获 四
🔥 为什么要捕获奔溃 🔥 因为在开发或者测试阶段不能做到100%的问题解决,因为 app 上线之后会有你想不到的各种各样的使用的场景,而发生问题时用户只能描述一下怎么怎么怎么就出现了问题。也许反馈到开发这边可以100%复现那就可以…...
自动化测试:让软件测试更高效更愉快!
谈谈那些实习测试工程师应该掌握的基础知识(一)_什么时候才能变强的博客-CSDN博客https://blog.csdn.net/qq_17496235/article/details/131839453谈谈那些实习测试工程师应该掌握的基础知识(二)_什么时候才能变强的博客-CSDN博客h…...
SpringCloud学习—Feign负载均衡
Feign简介 Feign是声明式Web Service客户端,它让微服务之间的调用变得更简单,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供负载均衡的http客户端 只需要创建一个接口,然后添加注解即可。使用…...
5G时代的APP开发:机遇与挑战
APP开发是互联网行业中的重要组成部分,随着5G时代的到来,移动 APP开发也迎来了新的机遇和挑战。 5G时代不仅会为移动 APP开发带来新的发展机遇,也会给移动 APP开发带来新的挑战。对于企业和开发者而言,5G时代带来的机遇和挑战是并…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
