Flutter与android之间的通讯

2023-11-14

Platform Channel简介

Flutter引入Platform Channel机制来支持不同平台的API调用。在Flutter中,提供了三种Platform Channel用来支持和平台之间数据的传递:

  • BasicMessageChannel:支持字符串和半结构化的数据传递,可以通过BasicMessageChannel来获取Native项目的图标等资源
  • MethodChannel:支持传递方法调用,Flutter主动调用Native的方法,并获取相应的返回值。既可以从Flutter发平台发起方法调用,也可以从平台代码向Flutter发起调用
  • EventChannel:支持数据流通信,传递事件。收到消息后无法回复此次消息,通常用于Native向Dart的通信

使用方法

BasicMessageChannel

Android端:

BasicMessageChannel mBasicMessageChannel = new BasicMessageChannel(getFlutterView(), "basic_channel", StringCodec.INSTANCE);
mBasicMessageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler() {
    //接受消息
    @Override
    public void onMessage(Object o, BasicMessageChannel.Reply reply) {
        Log.e("basic_channel", "接收到来自flutter的消息:"+o.toString());
        reply.reply("回馈消息");
    }
});
//发送消息
mBasicMessageChannel.send("向flutter发送消息");
//发送消息并接受flutter的回馈
mBasicMessageChannel.send("向flutter发送消息", new BasicMessageChannel.Reply() {
            @Override
            public void reply(Object o) {
                
            }
});

Flutter端:

const basicMessageChannel = const BasicMessageChannel('basic_channel', StringCodec());
//接受并回复消息
basicMessageChannel.setMessageHandler(
      (String message) => Future<String>(() {
            setState(() {
              this.message = message;
            });
            return "回复native消息";
      }),
);
//发送消息
basicMessageChannel.send("来自flutter的message");
//flutter并没有发送并接受回复消息的`send(T message, BasicMessageChannel.Reply<T> callback)`方法

MethodChannel

Android端:

MethodChannel mMethodChannel = new MethodChannel(getFlutterView(), "method_channel");
mMethodChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
    //响应flutter端的调用
    @Override
    public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
        if (methodCall.method.equals("noticeNative")) {
            todo()
            result.success("接受成功");
        }
    }
});
//原生调用flutter
mMethodChannel.invokeMethod("noticeFlutter", "argument", new MethodChannel.Result() {
            @Override
            public void success(Object o) {
                //回调成功
            }
            @Override
            public void error(String s,String s1, Object o) {
                //回调失败
            }
            @Override
            public void notImplemented() {

            }
});

Flutter端:

const methodChannel = const MethodChannel('method_channel');
Future<Null> getMessageFromNative() async {
    //flutter调原生方法
    try {
      //回调成功
      final String result = await methodChannel.invokeMethod('noticeNative');
      setState(() {
        method = result;
      });
    } on PlatformException catch (e) {
      //回调失败
    }
  }
methodChannel.setMethodCallHandler(
      (MethodCall methodCall) => Future<String>(() {
            //响应原生的调用
          if(methodCall.method == "noticeFlutter"){
            setState(() {
              
            });
          }
      }),
); 

EventChannel

Android端:

EventChannel eventChannel = new EventChannel(getFlutterView(),"event_channel");
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
    @Override
    public void onListen(Object o, EventChannel.EventSink eventSink) {
        eventSink.success("成功");
        //eventSink.error("失败","失败","失败");
    }
    @Override
    public void onCancel(Object o) {
        //取消监听时调用
    }
});

Flutter端:

const eventChannel = const EventChannel('event_channel');
eventChannel.receiveBroadcastStream().listen(_onEvent,onError:_onError);
void _onEvent(Object event) {
    //返回的内容
}
void _onError(Object error) {
    //返回的回调
}

其中:Object args是传递的参数,EventChannel.EventSink eventSink是Native回调Dart时的会回调函数,eventSink提供success、error与endOfStream三个回调方法分别对应事件的不同状态

源码初探

Platform Channel基本结构

首先了解一下这三种Channel的代码:

BasicMessageChannel
class BasicMessageChannel<T> {
  const BasicMessageChannel(this.name, this.codec);
  final String name;
  final MessageCodec<T> codec;
  Future<T> send(T message) async {
    return codec.decodeMessage(await BinaryMessages.send(name, codec.encodeMessage(message)));
  }
  void setMessageHandler(Future<T> handler(T message)) {
    if (handler == null) {
      BinaryMessages.setMessageHandler(name, null);
    } else {
      BinaryMessages.setMessageHandler(name, (ByteData message) async {
        return codec.encodeMessage(await handler(codec.decodeMessage(message)));
      });
    }
  }
  void setMockMessageHandler(Future<T> handler(T message)) {
    if (handler == null) {
      BinaryMessages.setMockMessageHandler(name, null);
    } else {
      BinaryMessages.setMockMessageHandler(name, (ByteData message) async {
        return codec.encodeMessage(await handler(codec.decodeMessage(message)));
      });
    }
  }
}
MethodChannel
class MethodChannel {
  const MethodChannel(this.name, [this.codec = const StandardMethodCodec()]);
  final String name;
  final MethodCodec codec;
  void setMethodCallHandler(Future<dynamic> handler(MethodCall call)) {
    BinaryMessages.setMessageHandler(
      name,
      handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler),
    );
  }
  void setMockMethodCallHandler(Future<dynamic> handler(MethodCall call)) {
    BinaryMessages.setMockMessageHandler(
      name,
      handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler),
    );
  }
  Future<ByteData> _handleAsMethodCall(ByteData message, Future<dynamic> handler(MethodCall call)) async {
    final MethodCall call = codec.decodeMethodCall(message);
    try {
      return codec.encodeSuccessEnvelope(await handler(call));
    } on PlatformException catch (e) {
      returun ...
    } on MissingPluginException {
      return null;
    } catch (e) {
      return ...
    }
  }
  Future<T> invokeMethod<T>(String method, [dynamic arguments]) async {
    assert(method != null);
    final ByteData result = await BinaryMessages.send(
      name,
      codec.encodeMethodCall(MethodCall(method, arguments)),
    );
    if (result == null) {
      throw MissingPluginException('No implementation found for method $method on channel $name');
    }
    final T typedResult = codec.decodeEnvelope(result);
    return typedResult;
  }
}
EventChannel
class EventChannel {
  const EventChannel(this.name, [this.codec = const StandardMethodCodec()]);
  final String name;
  final MethodCodec codec;
  Stream<dynamic> receiveBroadcastStream([dynamic arguments]) {
    final MethodChannel methodChannel = MethodChannel(name, codec);
    StreamController<dynamic> controller;
    controller = StreamController<dynamic>.broadcast(onListen: () async {
      BinaryMessages.setMessageHandler(name, (ByteData reply) async {
        ...
      });
      try {
        await methodChannel.invokeMethod<void>('listen', arguments);
      } catch (exception, stack) {
        ...
      }
    }, onCancel: () async {
      BinaryMessages.setMessageHandler(name, null);
      try {
        await methodChannel.invokeMethod<void>('cancel', arguments);
      } catch (exception, stack) {
        ...
      }
    });
    return controller.stream;
  }
}

这三种Channel都有两个成员变量:

  • name:表示Channel名字,用于区分不同Platform Channel的唯一标志,每个Channel使用唯一的name作为其唯一标志
  • codec: 表示消息的编解码器,Flutter采用了二进制字节流作为数据传输协议:发送方需要把数据编码成二进制数据,接受方再把数据解码成原始数据.而负责编解码操作的就是Codec。
    每个Channel中都使用到了BinaryMessages,它起到了信使的作用,负责将信息进行跨平台的搬运,是消息发送和接受的工具。
setMessageHandler

在创建好BasicMessageChannel后,让其接受来自另一平台的消息,BinaryMessenger调用它的setMessageHandler方法为其设置一个消息处理器,配合BinaryMessenger完成消息的处理以及回复;

send

在创建好BasicMessageChannel后,可以调用它的send方法向另一个平台传递数据。

setMethodCallHandler

设置用于在此MethodChannel上接收方法调用的回调

receiveBroadcastStream

设置广播流以接收此EventChannel上的事件

Handler

Flutter使用Handler处理Codec解码后的消息。三种Platform Channel相对应,Flutter中也定义了三种Handler:

  • MessageHandler: 用于处理字符串或者半结构化消息,定义在BasicMessageChannel中.
  • MethodCallHandler: 用于处理方法调用,定义在MethodChannel中.
  • StreamHandler: 用于事件流通信,定义在EventChannel中

使用Platform Channel时,需要为其注册一个对应BinaryMessageHandler为其设置对应的Handler。二进制数据会被BinaryMessageHanler进行处理,首先使用Codec进行解码操作,然后再分发给具体Handler进行处理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter与android之间的通讯 的相关文章

  • Google 云端硬盘身份验证异常 - 需要许可吗? (v2)

    我一直在尝试将 Google Drive v2 添加到我的 Android 应用程序中 但无法获得授权 我收到 UserRecoverableAuthIOException 并显示消息 NeedPermission 我感觉 Google A
  • 如何纠正流警告:解构(缺少注释)

    我正在编写一个小型 React Native 应用程序 并且正在尝试使用 Flow 但我无法在任何地方真正获得有关它的正确教程 我不断收到错误 destructuring Missing annotation 有关 station 这段代码
  • Chrome 扩展程序在代码中使用 client_secret

    我正在开发具有自己的 oAuth 授权的 Google Chrome 扩展 当然 我必须使用 client id 和 client secret 作为请求令牌 有什么办法可以向用户隐藏这些数据吗 由于此请求只是 javascript 源代码
  • 如何默认在 ActionOpenDocument 意图中显示“内部存储”选项

    我需要用户选择一个自定义文件类型的文件 并将其从 Windows 文件资源管理器拖到 Android 设备上 但默认情况下内部存储选项不可用 当我使用以下命令启动意图时 var libraryIntent new Intent Intent
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • 在 android DatePickerDialog 中将语言设置为法语

    有什么办法可以让日期显示在DatePickerDialog用法语 我已经搜索过这个但没有找到结果 这是我的代码 Calendar c Calendar getInstance picker new DatePickerDialog Paym
  • 使用 CSS 或 Javascript 填充动画

    我只是想知道是否可以使用 CSS 或 javascript 创建填充动画 基本上我想创建一个填充动画 如下图所示 http i40 tinypic com eit6ia png http i40 tinypic com eit6ia png
  • 有没有办法在 onclick 触发时禁用 iPad/iPhone 上的闪烁/闪烁?

    所以我有一个有 onclick 事件的区域 在常规浏览器上单击时 它不会显示任何视觉变化 但在 iPad iPhone 上单击时 它会闪烁 闪烁 有什么办法可以阻止它在 iPad iPhone 上执行此操作吗 这是一个与我正在做的类似的示例
  • 可以设置标题样式吗? (并且使用CSS或js?)[重复]

    这个问题在这里已经有答案了 我想知道是否可以设计一个title a href title This is a title Hello a 样式问题有两个方面 文本格式 编码 我猜这是可能的 所以在问题中这样做 工具提示样式 你能把它弄大一点
  • AppLifeCycleState.detached 未被调用

    import package flutter material dart void main gt runApp MyApp class MyApp extends StatelessWidget override Widget build
  • 在 Javascript 中连接空数组

    我正在浏览一些代码 我想知道这有什么用处 grid push concat row 根据我的理解 它等同于 grid push row 为什么要大惊小怪 连接 你想使用 concat当您需要展平数组并且没有由其他数组组成的数组时 例如 va
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 实现滚动选择 ListView 中的项目

    我想使用 ListView 您可以在其中滚动列表来选择一个项目 它应该像一个 Seekbar 但拇指应该是固定的 并且您必须使用该栏来调整它 我面临的一个问题是 我不知道这种小部件是如何调用的 这使得我很难搜索 所以我制作了下面这张图片 以
  • 空安全 AppLocalization 字符串的最佳方法

    Question 我在用AppLocalizations of context myString在我的 null safe flutter 应用程序中国际化字符串 我的 IDE 告诉我AppLocalizations of context
  • Javascript Replace() 和 $1 问题

    我正在尝试创建一个脚本来搜索文本中的模式并在它找到的字符串周围包裹一个标签 shop attributes td each function this html function i html return html replace E 0
  • android sdk 的位置尚未在 Windows 操作系统的首选项中设置

    在 Eclipse 上 我转到 windows gt Android SDK 和 AVD Manager 然后弹出此消息 Android sdk 的位置尚未在首选项中设置 进入首选项 在侧边栏找到 Android 然后会出现一个 SDK 位
  • 从 FileReader 设置背景图像样式

    我正在寻找一种解决方案 允许我从文件上传输入中获取文件并通过设置 document body style backgroundImage 来预览它 以下代码用于在 Image 元素中显示预览 function setImage id tar
  • 如何将 google+ 登录集成到我的 Android 应用程序中?

    大家好 实际上我需要通过我的应用程序从 google 登录人们 现在我阅读了 google 上的文档 其中指出 要允许用户登录 请将 Google Sign In 集成到您的应用中 初始化 GoogleApiClient 对象时 请求 PL
  • 如何使用asm.js进行测试和开发?

    最近我读到asm js规范 看起来很酷 但是是否有任何环境 工具来开发和测试这个工具 这还只是处于规范阶段吗 您可以尝试使用 emscripten 和 ASM JS 1 并从侧分支在 firefox 构建中运行它 有关 asm js 的链接
  • 如何在react-highcharts中使用图表工具提示格式化程序?

    如何使用图表工具提示格式化程序 我正在使用高图表的反应包装器 我有这样的配置 const CHART CONFIG tooltip formatter tooltip gt var s b this x b each this points

随机推荐

  • 前端面试题(一)

    目录 一 解答题 1 样式表以及选择器的优先级 权重 2 浮动特点 3 元素 标签 类型的分类 4 水平垂直居中方法集锦 5 定位模式和定位的特点 6 画个三角形 7 BFC 块级格式化上下文 的特点和触发规则 8 宽高自适应 9 什么是高
  • C语言 一维数组

    一维数组的存储 一维数组在内存中是一段连续的存储区域 格局如下 验证代码如下 include
  • 如何自己开发一个Android APP(6)——程序与操作系统合作

    系统的事件处理 响应系统设置的事件Configuration类 获取系统的Configuration对象 Configuration cfg getResources getConfiguration Configuration类的常用方法
  • JavaScript函数七重关之函数定义

    JavaScript函数七重关的第一关是函数定义 函数定义需要用到function关键字 function myFunction 函数体 document write hello javascrept br 这是函数定义的第一种方法 也可以
  • Cisco Packet Tracer中配置DHCP服务器

    转载于 https blog csdn net qq 41745698 article details 85019218 DHCP介绍 DHCP Dynamic Host Configuration Protocol 动态主机配置协议 通常
  • 感谢CSDN平台记录了我6年的点点滴滴

    感谢CSDN平台记录了我6年的点点滴滴 我的新博客如下 博客园https www cnblogs com ztguang
  • Mysql基本语法

    1 创建数据库 CREATE DATABASE语句用于创建一个新的数据库 语法是 SQL gt CREATE DATABASE DATABASE NAME 例子 创建一个名为 EXAMPLE 数据库 SQL gt CREATE DATABA
  • uni-app this 传递的问题

    最近在使用uni app做个小程序的尝试 因为很久没有做前端了 对这块有点陌生了 毕竟这个和之前的 web的还是有点区别的 上传logo的一个小功能 想法是上传之后 用临时文件替换src的值
  • BART 文本摘要示例

    采用BART进行文本摘要 首先从transformers library导入BartTokenizer进行分词 以及BartForConditionalGeneration进行文本摘要 from transformers import Ba
  • 【HJ96】表示数字

    题目描述 将一个字符中所有的整数前后加上符号 其他字符保持不变 连续的数字视为一个整数 注意 本题有多组样例输入 数据范围 字符串长度满足 1 100 输入描述 输入一个字符串 输出描述 字符中所有出现的数字前后加上符号 其他字符保持不变
  • 中软国际教育科技集团送给参赛选手的专属福利,悟道之巅大赛参与就有奖励

    一 大赛背景 悟道2 0是北京智源人工智能研究院开发的大规模人工智能模型 和一般的人工智能模型不同 开发者可以在不掌握人工智能算法的情况下 仅仅调用大模型的接口 就可以使用人工智能的性能 悟道之巅大赛邀请开发者利用悟道2 0大模型开发自己的
  • C语言基础,数据类型与宏定义

    C基础 1 include
  • 如何使EndNoteX9支持GB/T 7714-2015格式参考文献&解决作者名字全为大写&去掉文章标题中的%J

    文章目录 问题描述 一 如何找到GB T 7714 2015格式 二 解决导入文献中文章标题里有 J 三 如何解决GB T 7714 2015格式导出时作者名字全是大写的问题 总结 问题描述 从学校数据库下载好EndNoteX9后 从谷歌学
  • 火狐调试接口必备 插件 Firefox httprequester

    太难找 要不是之前电脑保存有 还真用不上了 新版本不支持 自行下载旧版本浏览器 本人用56 0 64位 版本
  • C++中i--与--i的区别

    结论 i i 0 i i 1 i i i 1 i 0 while i 代表着先判断后自减并输出自减的值 include
  • QCC512x/302x笔记(3)-- 只改一行代码,实现串口输出调试log

    哈喽大家好 这是该系列博文的第一篇 篇 lt lt 系列博文索引 快速通道 gt gt 上一篇我们知道了如何安装电脑USB驱动 方便后续的调试和烧录 这一篇我们就来打通串口的调试吧 当然通过MDE里面的pydbg调试也是可以的 串口除了可以
  • python3 中使用 kubernetes模版操纵k8s集群

    本文介绍kubernetes模块在k8s集群中的使用 其实就是将对kube apiserver的http访问封装成python可用的对象 详细文档参考官方链接 https github com kubernetes client pytho
  • png的图片四通道,jpg为三通道

    import cv2 img cv2 imread sample jpg cv2 IMREAD UNCHANGED cv2 imshow jpg img cv2 waitKey 0 print img shape img2 cv2 imre
  • 打造高效企业网站系统,助力业务发展!

    企业网站在今天的商业世界中扮演着至关重要的角色 随着市场竞争的日益激烈 打造一个高效的企业网站系统已经成为了实现业务发展和增长的必要条件 本文将分享一些打造高效企业网站系统的关键步骤和技巧 并结合一个案例为读者深入分析 案例 设计公司打造高
  • Flutter与android之间的通讯

    Platform Channel简介 Flutter引入Platform Channel机制来支持不同平台的API调用 在Flutter中 提供了三种Platform Channel用来支持和平台之间数据的传递 BasicMessageCh