Flutter与Native通信原理剖析与实践

2023-10-30

通信原理

我们分几种场景来介绍Flutter和Native之间的通信。

  • Native发送数据给Flutter
  • Flutter发送数据给Native
  • Flutter发送数据给Native,然后Native回传数据给Flutter

在这里插入图片描述

Flutter与Native通信机制

在讲解Flutter与Native之间是如何传递数据之前,我们先了解下Flutter与Native的通信机制,Flutter和Native的通信是通过Channel来完成的。

消息使用Channel(平台通道)在客户端(UI)和主机(平台)之间传递,如下图所示:
在这里插入图片描述

  • Channel所支持的数据类型对照表

在这里插入图片描述

  • Flutter定义了三种不同类型的Channel:
    1. BasicMessageChannel:用于传递字符串和半结构化的信息,持续通信,收到消息后可以回复此次消息,如:Native将遍历到的文件信息陆续传递到Flutter,在比如:Flutter将从服务端陆陆续续获取到信息交给Native加工,Native处理完返回等;
    2. MessageChannel:用于传递方法调用,一次性通信:如Flutter调用Native拍照;
    3. EventChannel:用于数据流的通信,持续通信,通常用于Native向Flutter的通信,如:手机电量变化,网络连接变化等;

这三种类型的Channel都是全双工通信,即A<=>B,Flutter可以主动发送消息给Native端,并且Native接收到消息后可以做出回应,同样,Native端可以主动发送消息给Flutter端,Flutter端接收到数据后返回给Native。

通信原理

在这里插入图片描述

  • 无论是哪一种类型的Channel,它能和Flutter进行通信主要是借助BinaryMessenger来实现的。
  • 三种类型的Channel在Flutter侧都有对应的实现。

实践

  • flutter主动发送数据给native,native接受到消息后回信给flutter
    1. Android端
class MainActivity : FlutterActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "HiFlutterBridge")//HiFlutterBridge需要和flutter端的对应

        channel.setMethodCallHandler { call, result ->
            Log.e("HiFlutterBridge", "argus is ${call.arguments}")
            if (call.method == "goToNative") {
                val data = "Hello from native!"
                result.success(data)
            } else {
                result.notImplemented()
            }
        }
    }
  1. Flutter端
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';

class HiFlutterBridge {
  static HiFlutterBridge _instance = HiFlutterBridge._();
  final MethodChannel _bridge = const MethodChannel("HiFlutterBridge");//需要和原生端的MethodChannel方法的第二个参数一致
  var _listener = {};

  HiFlutterBridge._() {
    _bridge.setMethodCallHandler((MethodCall call) {
      String method = call.method;
      if (_listener[method] != null) {
        return _listener[method](call);
      }
      return Future(() => null);
    });
  }

  static HiFlutterBridge getInstance() {
    return _instance;
  }

  register(String method, Function(MethodCall) callBack) {
    _listener[method] = callBack;
  }

  unRegister(String method) {
    _listener.remove(method);
  }

  goToNative(Map params) async {
    String result = await _bridge.invokeMethod("goToNative", params);
    debugPrint("HiFlutterBridge result is $result");
  }

  MethodChannel bridge() {
    return _bridge;
  }
}

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        resizeToAvoidBottomInset: false, // 设置为false以避免在打开软键盘时widget被顶上去
        body: HideKeyboard(
            child: Stack(
          children: <Widget>[
            Align(
              alignment: Alignment.center,
              child: ElevatedButton(
                onPressed: () => {
                  //flutter向native端通信

                  HiFlutterBridge.getInstance()
                      .goToNative({"test": "hello world"})
                },
                // style: ElevatedButton.styleFrom(
                //     minimumSize: const Size(100, 50),
                //     maximumSize: const Size(100, 50),
                //     shape:
                //     RoundedRectangleBorder(borderRadius: BorderRadius.circular(30))),
                child: const Text('login'),
              ),
            )
          ],
        )));
  }
  • native主动发送数据给flutter,flutter接受到消息后回信给native
    1. Android端
class MainActivity : FlutterActivity() {

    override fun onResume() {
        super.onResume()
        sendDataToFlutter()
    }

    private fun sendDataToFlutter() {
        val channel = MethodChannel(flutterEngine!!.dartExecutor.binaryMessenger, "test")
        channel.invokeMethod(" sendData ", "Hello Flutter", object : MethodChannel.Result {
            override fun success(o: Any?) {
                Log.d("Native", "Received back: " + o.toString())
            }

            override fun error(s: String, s1: String?, o: Any?) {
                Log.e("Native", "Error: $s1")
            }

            override fun notImplemented() {}
        })
    }
}
  1. Flutter端
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';

class HiFlutterBridge {
  static HiFlutterBridge _instance = HiFlutterBridge._();
  final MethodChannel _bridge = const MethodChannel("test");
  var _listener = {};

  HiFlutterBridge._() {
    _bridge.setMethodCallHandler((MethodCall call) async{
      debugPrint("test ===> ${call}");
      return "flutter ===> native";
      String method = call.method;
      if (_listener[method] != null) {
        return _listener[method](call);
      }
      return Future(() => null);
    });
  }

  static HiFlutterBridge getInstance() {
    return _instance;
  }

  register(String method, Function(MethodCall) callBack) {
    _listener[method] = callBack;
  }

  unRegister(String method) {
    _listener.remove(method);
  }

  goToNative(Map params) async {
    String result = await _bridge.invokeMethod("goToNative", params);
    debugPrint("HiFlutterBridge result is $result");
  }

  MethodChannel bridge() {
    return _bridge;
  }
}

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    HiFlutterBridge.getInstance();
  }
  • 运行结果
I/flutter (27181): test ===> MethodCall( sendData , Hello Flutter)
D/Native  (27181): Received back: flutter ===> native
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter与Native通信原理剖析与实践 的相关文章

  • Android中将JSON数据存储到本地数据库

    好的 我创建了一个应用程序 它使用 JSON 从我的服务器检索数据 现在我想将检索到的数据存储在手机的本地存储 数据库中 我该怎么做 我是android编程新手 这是我从服务器收到的 JSON messages id 44 issender
  • Cordova - 启动后出现白屏,控制台中没有例外

    我已经离开我的 Cordova 应用程序一段时间了 但昨天刚刚进行了一次新的克隆 发现它出现了 死机白屏 症状 启动画面显示 程序加载 然后我就得到一个空白屏幕 更多细节 CLI 科尔多瓦 6 1 1 安卓 5 1 1 ios 4 1 1
  • 使用 proguard 混淆文件名

    我正在使用 proguard 和 Android Studio 混淆我的 apk 当我反编译我的apk时 我可以看到很多文件 例如aaa java aab java ETC 但我项目中的所有文件都有原始名称 有没有办法混淆我的项目的文件名
  • 当我单击“完成”键时,Android OnEditorActionListener() actionId 给出 0

    我创建了一个键盘 当用户输入数字时 它会输入特定的 EditText 但是当用户单击Done关键 它没有去setOnEditorActionListener但它关闭了键盘 这是我的代码 final EditText txtQty new E
  • CoordinatorLayout 和 ImageView 在滚动时调整宽度的问题

    我正在尝试放置一个ImageView in a CollapsingToolbarLayout它在加载时占据整个屏幕 并且当您滚动内容时 16x9 分辨率图像宽度会调整大小 直到图像占据屏幕的整个宽度 那时 我希望图像具有视差app lay
  • 如何在Android中的DataBinding的ViewModel类中获取R.string

    我目前正在使用databinding对于我的 Android 应用程序项目 我想设置error留言在我的CustomTextView from R string txtOldPassWordError并从另一个名为的类中进行设置ViewMo
  • ListView 和快照 - 错误 - 错误状态:DocumentSnapshotPlatform 中不存在字段[重复]

    这个问题在这里已经有答案了 我对快照和 ListView 有一个小问题 到目前为止 它运行得很好 但自从我更新了 flutter 和 Dart 后 我 收到了一个错误 构建 StreamBuilder gt 时抛出以下 StateError
  • 在光标所在行强制关闭!

    嘿 我正在尝试创建一个应用程序来查找存储在 SQlite 数据库中的 GPS 数据 但我面临一个问题 我构建了一个 DbAdapter 类来创建数据库 现在我尝试使用以下函数从另一个类获取所有数据上的光标 public Cursor fet
  • Android:WebView/BaseInputConnection 中的退格键

    我在 Android 4 2 中遇到软键盘退格问题 我在 WebView CodeMirror 中有一个自定义编辑器 它使用一个空的
  • Android 认为我没有关闭数据库!为什么?

    我有一个 SQLiteDatabase 数据成员 我在 onCreate 中初始化它 并在 onPause onStop 和 onDestroy 中调用 close 它在 onResume 中重新初始化 它似乎运行得很好 但当我查看调试器时
  • 如何在同一设备上运行的 Android 应用程序之间传输文件?

    我正在编写一个与 RESTful 服务交互的 Android 应用程序 该 Web 服务本质上是一个文件系统 并提供元数据以及对文件的 CRUD 访问 我的应用程序检索元数据 并通过ContentProvider 我需要添加与我的应用程序在
  • BottomAppBar浮动操作按钮凹口/插入不透明

    我添加了一个BottomAppBar到材质应用程序中的脚手架 并且我添加了一个在中心带有插图的工厂 代码看起来有点像这样 Scaffold bottomNavigationBar BottomAppBar color Theme of co
  • Android Google Map V2:如何在单击另一个标记时更改先前单击的标记的图标

    更新 我通过添加 previousMarker 对象解决了性能问题 因此 只有先前单击的标记将被删除并替换为默认图标 但是 当我单击标记时 信息窗口仍然不显示 我有一个地图视图并在上面设置了一些标记 我想要的是 当我单击一个标记时 它将其图
  • Android - 存储对ApplicationContext的引用

    我有一个静态 Preferences 类 其中包含一些应用程序首选项和类似的内容 可以在那里存储对 ApplicationContext 的引用吗 我需要该引用 以便我可以在不继承 Activity 的类中获取缓存文件夹和类似内容 你使用的
  • 文本视图不显示全文

    我正在使用 TableLayout 和 TableRow 创建一个简单的布局 其中包含两个 TextView 这是代码的一部分
  • TextView.setMaxLines 不起作用?

    在我的应用程序中 我有一个屏幕 其中显示一些文本 然后显示一张照片 文本的长度是可变的 有时根本没有 有时很多 所以我想对其进行设置 以便文本永远不会占用超过几行 但可以滚动 为下面的图像留下足够的空间 我这部分的视图组件是以编程方式创建的
  • 如何知道我的应用程序的活动计数?

    我的应用程序中有多项活动 请考虑以下案例 Activity A 调用 Activity B B 调用 C 当用户按后退键时 C 生成通知并转到 B 现在再次按后退 因此将显示 A 再次按后退键也会终止 A 并显示通知 现在 当用户按下通知图
  • XML 配置中的 screenName 不起作用

    我刚刚在我的应用程序中添加了对 Google Analytics 分析 的支持 但我无法
  • 如何正确处理 ListView 内的 Android EditText 输入?

    在我的应用程序中 我有一个在 a 中添加 删除 编辑记录的活动SortedMap 该活动作为以下活动的延伸实施ListActivity 我已经实现了自定义ArrayAdapter对于收藏品 Every ListView项目 对应于基础记录
  • Android 的代码覆盖率[重复]

    这个问题在这里已经有答案了 可能的重复 Android测试代码覆盖率 Eclipse https stackoverflow com questions 3282702 android test code coverage eclipse

随机推荐

  • Latex多个子图进行组合

    20210413 0 引言 最近在用latex写论文 这种半路出家的 很多内容都要现场查 没办法 谁让平时用的少呢 本篇文章针对的内容是放置子图 也就是在文章中放置多个图片 这几个图片本质上同属于一个大图片 假设是3个 那就是3个子图 横向
  • websocket 发送内容长度设置(默认8192字节)

    https blog csdn net zhaotian19871204 article details 84801915
  • 2020年7月6日-7月26日(算每天1小时,合计215小时,剩9785小时)

    主要进行了二次开发 熟练度提高 新东西不多 大象无形也看过一些 但是没定计划磨洋工了 就算每天1小时 合计215小时 剩9785小时
  • Centos7下安装无头浏览器(headless Chrome) puppeteer 截图

    目录 第一步 添加repo源 第二步 安装chrome 第三步 安装驱动chromedriver puppeteer 是一个基于nodejs 调用chrome进行网页截图的库 chrome并不需要UI界面 一般访问网页 模拟点击操作等 在自
  • stable diffusion实践操作-大模型介绍-SDXL1大模型

    系列文章目录 大家移步下面链接中 里面详细介绍了stable diffusion的原理 操作等 本文只是下面系列文章的一个写作模板 stable diffusion实践操作 提示 写完文章后 目录可以自动生成 如何生成可参考右边的帮助文档
  • 在Unity中使用OOP

    以Main Camera 为例 所有组件 Transform Camera Audio Listener Scirpts 在Unity中都是类 单击Play按钮时 这些组件都会成为内存中的对象 1 获取组件 使用GameObject类的Ge
  • Scala简介与安装

    目录 一 Scala简介 一 Scala概述 二 函数式编程 三 Scala特性 1 一切都是对象 2 一切都是函数 3 一切都是表达式 四 在线运行Scala 二 选择Scala版本 三 Windows上安装Scala 一 到Scala官
  • /var/run/yum.pid 已被锁定,PID 为 xxxx 的另一个程序正在运行的问题解决

    问题 解决 root localhost rm f var run yum pid
  • openGL阴影实现(软阴影)

    openGL系列文章目录 文章目录 openGL系列文章目录 前言 一 现实世界中的柔和阴影 二 生成柔和阴影 百分比邻近滤波 PCF 1 引入库 代码 运行效果 源码下载 前言 目前我们所展示的阴影生成方法都仅限于生成硬阴影 即带锐边的阴
  • R语言绘制箱线图并添加相关显著性

    箱线图 又称盒须图 通过绘制连续型变量的五数总括 即最小值 下四分位数 第25百分位数 中位数 第50百分位数 上四分位数 第75百分位数 以及最大值 描述了连续型变量 的分布 它主要用于反映原始数据分布的特征 还可以进行多组数据分布特征的
  • 网络爬虫CSS选择器详细讲解

    网络爬虫CSS选择器详细讲解 前言 使用步骤 1 解析的HTML代码 2 逐层选择节点 3 获取文本 string和get text 4 获取节点的属性值 5 选择单个和多个节点 6 通过class和id选择节点 class id 7 选择
  • PLY 模型文件简析

    PLY 模型文件简析 参考链接 wiki需要FFFQQQ TIPS 主要是一些英文的简析 但是一句话 网上讲的不清楚 特此说明property list uchar int vertex indices 应该是面的顶点数量使用 uchar
  • 苹果 / Apple iCloud 教育版 200GB 云盘账号自助注册教程

    因为教育机构的管理式 Apple ID 可以单点登录 SSO 登录 因此自助注册苹果 Apple iCloud 教育版 200GB 云盘账号就可以顺利进行了 自助注册苹果 Apple iCloud 教育版 200GB 云盘账号分为两步 自助
  • STM32速成笔记—IWDG

    文章目录 一 IWDG简介 二 STM32的IWDG 2 1 STM32的IWDG简介 2 2 喂狗 2 3 IWDG框图 三 IWDG配置步骤 四 IWDG配置程序 4 1 IWDG初始化程序 4 2 喂狗 五 应用实例 一 IWDG简介
  • 恶意代码的分类

    计算机病毒 注意这是狭义上的定义 和网络蠕虫都可以进行自我传播 那他们的本质区别是什么 计算机病毒 一组能进行自我传播 需要用户干预来触发执行的破坏性程序或代码 网络蠕虫 一组能进行自我传播 不需要用户干预即可触发执行的破坏性程序或代码 1
  • [007]爬虫系列

    一 找到首次加载的js 用源码面板打开 二 第一行打断点 格式化 三 刷新网页 成功断点 执行hook 代码如下 function use strict var cookieTemp Object defineProperty docume
  • 前端实现流程图效果_微前端在58商业的探索实践

    导读 商业FE部门分四个业务组 每个组内迭代着多个中后台应用 其中有跨组协作项目 这些项目的特点是UI UE相似 有较多的组件 逻辑复用场景 技术栈统一为VUE 且项目在不断迭代中 实践微前端架构能提高业务复用性 让各团队更高效的分治项目
  • npm,webpack学习中遇到的各种问题

    问题 打包的时候报错 Uncaught ReferenceError regeneratorRuntime is not defined 解决 详见babel plugin transform runtime babel pollyfill
  • Python字典操作方法--items()

    d items 返回字典中的所有键值对信息 返回结果是Python的一种内部数据类型dict items 如果希望更好的使用返回结果 可以将其转换为列表类型 键值对以元组类型 即括号形式 表示 gt gt gt d 2018 小明 2019
  • Flutter与Native通信原理剖析与实践

    通信原理 我们分几种场景来介绍Flutter和Native之间的通信 Native发送数据给Flutter Flutter发送数据给Native Flutter发送数据给Native 然后Native回传数据给Flutter Flutter