flutter图片点击跳转_Flutter系列之Platform Channel使用详解

2023-11-13

18419ba0cb29960055be718cc761b1ee.png

PS:逐渐体会到关键少数原则的重要性,接下来就是付诸实践了,另外科创50ETF明天开始限额销售,可以适当关注或入手一点。

前面几篇文章介绍了 Navigator 组件、Flex 布局、图片加载、Widget 生命周期、混合开发等 Flutter 开发基础知识, 链接如下:

  • Flutter系列之Navigator使用详解

  • Flutter系列之Flex布局详解

  • Flutter系列之图片加载详解

  • Flutter系列之Widget生命周期

  • Flutter系列之混合开发Android篇

下面介绍一下 Flutter 混合开发中 Platform Channel 的使用,主要内容如下:

  1. 平台通道介绍

  2. 平台数据类型对照

  3. BasicMessageChannel

  4. MethodChannel

  5. EventChannel

平台通道介绍

Platform Channel 是一个异步消息通道,消息在发送之前会编码成二进制消息,接收到的二进制消息会解码成 Dart 值,其传递的消息类型只能是对应的解编码器支持的值,所有的解编码器都支持空消息,其 Native 与 Flutter 通信架构如下图所示:

c9873f9f27bd9c0c6da1992fa947cf95.png

Flutter 中定义了三种不同类型的 PlatformChannel,主要有三种如下:

  • BasicMessageChannel:用于数据传递;

  • MethodChannel:用于传递方法调用;

  • EventChannel:用于传递事件;

其构造方法都需指定一个通道标识、解编码器以及 BinaryMessenger,BinaryMessenger 是一个 Flutter 与平台的通信工具,用来传递二进制数据、设置对应的消息处理器等。

解编码器有两种分别是 MethodCodec 和 MessageCodec,前者对应方法后者对应消息,BasicMessageChannel 使用的是 MessageCodec,MethodChannel 和 EventChannel 使用的是 MethodCodec。

平台数据类型对照

Platform Channel 提供不同的消息解码机制,如 StandardMessageCodec 提供基本数据类型的解编码、JSONMessageCodec 支持 Json 的解编码等,在平台之间通信时都会自动转换,各平台数据类型对照如下:

1a18cc3e33daee8ed500791d0654a2fd.png

BasicMessageChannel

BasicMessageChannel 主要用来数据传递,包括二进制数据,借助 BasicMessageChannel 可以实现 MethodChannel 和 EventChannel 的功能,这里用 BasicMessageChannel 实现 Android 项目使用 Flutter 资源文件的案例,关键流程如下:

  1. Flutter 端获得图片资源对应的二进制数据,这里使用 BinaryCodec,则数据格式为 ByteData;

  2. 使用 BasicMessageChannel 发送图片对应的数据;

  3. 在 Android 端使用 ByteBuffer 接收,并将其转换成 ByteArray,然后解析成 Bitmap 显示出来。

Flutter 端关键代码如下:

1// 创建BasicMessageChannel  2_basicMessageChannel = BasicMessageChannel("com.manu.image", BinaryCodec()); 3 4// 获取assets中的图片对应的ByteData数据 5rootBundle.load('images/miao.jpg').then((value) => { 6  _sendStringMessage(value) 7}); 8 9// 发送图片数据10_sendStringMessage(ByteData byteData) async {11  await _basicMessageChannel.send(byteData);12}

Android 端关键代码如下:

1override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 2    super.configureFlutterEngine(flutterEngine) 3    Log.i(tag, "configureFlutterEngine") 4    // 设置消息处理器 5    BasicMessageChannel( 6        flutterEngine.dartExecutor, "com.manu.image", BinaryCodec.INSTANCE 7    ).setMessageHandler { message, reply -> 8        Log.i(tag, "configureFlutterEngine > message:$message") 9        // 数据转换:ByteBuffer->ByteArray10        val byteBuffer = message as ByteBuffer11        imageByteArray = ByteArray(byteBuffer.capacity())12        byteBuffer.get(imageByteArray)13    }1415    // 用于设置Flutter跳转Android的方法处理器16    MethodChannel(flutterEngine.dartExecutor, channel).setMethodCallHandler { call, result ->17        Log.i(tag, "configureFlutterEngine > method:${call.method}")18        if ("startBasicMessageChannelActivity" == call.method) {19            // 携带图片数据20            BasicMessageChannelActivity.startBasicMessageChannelActivity(this,imageByteArray)21        }22    }23}2425// 显示来自Flutter assets中的图片26val imageByteArray = intent.getByteArrayExtra("key_image")27val bitmap = BitmapFactory.decodeByteArray(imageByteArray,0,imageByteArray.size)28imageView.setImageBitmap(bitmap)

另外,BasicMessageChannel 结合 BinaryCodec 是支持大内存数据块的传递的。

MethodChannel

MethodChannel 主要用来方法的传递,自然可以传递 Native 方法和 Dart 方法,即可以通过 MethodChannel 在 Flutter 中调用 Android 原生方法,在 Android 中调用 Dart 方法,互相调用都是通过 MethodChannel 的 invokeMethod 方法调用的,通信时必须使用相同的通道标识符,具体如下:

  1. Flutter调用Android方法

下面通过 MethodChannel 实现从 Flutter 跳转到 Android 原生界面 MainActivity,Android 端如下:

1/** 2 * @desc FlutterActivity 3 * @author jzman 4 */ 5val tag = AgentActivity::class.java.simpleName; 6 7class AgentActivity : FlutterActivity() { 8    val tag = AgentActivity::class.java.simpleName; 9    private val channel = "com.manu.startMainActivity"10    private var platform: MethodChannel? = null;1112    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {13        super.configureFlutterEngine(flutterEngine)14        Log.d(tag,"configureFlutterEngine")15        platform = MethodChannel(flutterEngine.dartExecutor, channel)16        // 设置方法处理器17        platform!!.setMethodCallHandler(StartMethodCallHandler(this@AgentActivity))18    }1920    companion object{21        /**22         * 重新创建NewEngineIntentBuilder才能保证生效23         */24        fun withNewEngine(): MNewEngineIntentBuilder? {25            return MNewEngineIntentBuilder(AgentActivity::class.java)26        }27    }2829    /**30     * 自定义NewEngineIntentBuilder31     */32    class MNewEngineIntentBuilder(activityClass: Class<out FlutterActivity?>?) :33        NewEngineIntentBuilder(activityClass!!)3435    /**36     * 实现MethodCallHandler37     */38    class StartMethodCallHandler(activity:Activity) : MethodChannel.MethodCallHandler{39        private val context:Activity = activity40        override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {41            if ("startMainActivity" == call.method) {42                Log.i(tag,"arguments:"+call.arguments)43                startMainActivity(context)44                // 向Flutter回调执行结果45                result.success("success")46            } else {47                result.notImplemented()48            }49        }50    }51}

如上还可以使用 MethodChannel.Result 对象向Flutter回调执行结果,Flutter 端如下:

1/// State 2class _PageState extends State<PageWidget> { 3  MethodChannel platform; 4 5  @override 6  void initState() { 7    super.initState(); 8    platform = new MethodChannel('com.manu.startMainActivity'); 9  }1011  @override12  Widget build(BuildContext context) {13    return Container(14      width: double.infinity,15      margin: EdgeInsets.fromLTRB(8, 8, 8, 0),16      child: RaisedButton(17        onPressed: () {18          _startMainActivity();19        },20        child: Text("Flutter to Android"),21      ),22    );23  }2425  /// 跳转到原生Activity26  void _startMainActivity() {27    platform.invokeMethod('startMainActivity', 'flutter message').then((value) {28      // 接收返回的数据29      print("value:$value");30    }).catchError((e) {31      print(e.message);32    });33  }34}

  1. Android调用Dart方法

下面通过 MethodChannel 调用 Flutter 中的 Dart 方法 getName,Android 端代码如下:

1/** 2 * @desc MainActivity 3 * @author jzman 4 */ 5class MainActivity : FlutterActivity() { 6    private val tag = MainActivity::class.java.simpleName; 7    private val channel = "com.manu.startMainActivity" 8    private var methodChannel: MethodChannel? = null 9    override fun onCreate(savedInstanceState: Bundle?) {10        super.onCreate(savedInstanceState)11        setContentView(R.layout.activity_main)1213        btnGetDart.setOnClickListener {14            getDartMethod()15        }16    }1718    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {19        super.configureFlutterEngine(flutterEngine)20        Log.i(tag,"configureFlutterEngine")21        methodChannel = MethodChannel(flutterEngine.dartExecutor,channel)22    }2324    private fun getDartMethod(){25        methodChannel?.invokeMethod("getName",null, object :MethodChannel.Result{26            override fun success(result: Any?) {27                Log.i(tag,"success: "+result.toString())28                Toast.makeText(this@MainActivity,result.toString(),Toast.LENGTH_LONG).show()29            }3031            override fun error(errorCode: String,errorMessage: String?,errorDetails: Any?) {32                Log.i(tag,"error")33            }3435            override fun notImplemented() {36                Log.i(tag,"notImplemented")37            }38        })39    }4041    companion object{42        fun startMainActivity(context: Context) {43            val intent = Intent(context, MainActivity::class.java)44            context.startActivity(intent)45        }46    }47}

Flutter 端如下:

1/// State 2class _PageState extends State<PageWidget> { 3  MethodChannel platform; 4 5  @override 6  void initState() { 7    super.initState(); 8    platform = new MethodChannel('com.manu.startMainActivity'); 910    // 监听Android调用Flutter方法11    platform.setMethodCallHandler(platformCallHandler);12  }1314  @override15  Widget build(BuildContext context) {16    return Container();17  }18  /// FLutter Method19  Future platformCallHandler(MethodCall call) async{20    switch(call.method){21      case "getName":22        return "name from flutter";23        break;24    }25  }26}

EventChannel

EventChannel 主要用于 Flutter 到原生之间的单向调用,其使用方式类似 Android 中的广播,原生界面负责 Event 的发送,Flutter 端注册监听即可,不多说直接看代码,Android 端代码如下:

1/// Android 2class MFlutterFragment : FlutterFragment() { 3    // 这里用Fragment,Activity也一样 4    override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 5        super.configureFlutterEngine(flutterEngine) 6        Log.d(tag,"configureFlutterEngine") 7        EventChannel(flutterEngine.dartExecutor,"com.manu.event").setStreamHandler(object: 8            EventChannel.StreamHandler{ 9            override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {10                Log.i(tag,"configureFlutterEngine > onListen")11                // EventSink发送事件通知12                events?.success("event message")13            }1415            override fun onCancel(arguments: Any?) {16                Log.i(tag,"configureFlutterEngine > onCancel")17            }18        })19    }2021    companion object{22        fun withNewEngine(): NewEngineFragmentBuilder? {23            return MNewEngineIntentBuilder(24                MFlutterFragment::class.java25            )26        }27    }2829    class MNewEngineIntentBuilder(activityClass: Class<out FlutterFragment?>?) :30        NewEngineFragmentBuilder(activityClass!!)31}

Flutter 端如下:

1/// State 2class EventState extends State<EventChannelPage> { 3  EventChannel _eventChannel; 4  String _stringMessage; 5  StreamSubscription _streamSubscription; 6 7  @override 8  void initState() { 9    super.initState();10    _eventChannel = EventChannel("com.manu.event");11    // 监听Event事件12    _streamSubscription =13        _eventChannel.receiveBroadcastStream().listen((event) {14      setState(() {15        _stringMessage = event;16      });17    }, onError: (error) {18      print("event error$error");19    });20  }2122  @override23  void dispose() {24    super.dispose();25    if (_streamSubscription != null) {26      _streamSubscription.cancel();27      _streamSubscription = null;28    }29  }3031  @override32  Widget build(BuildContext context) {33    return Scaffold(34        appBar: AppBar(35          title: Text("EventChannel"),36          centerTitle: true,37        ),38        body: Center(39          child: Text(_stringMessage == null ? "default" : _stringMessage),40        ));41  }42}

以上就是 Flutter 平台通道的使用,可以在公众号回复关键字【Channel】获取源码。

推荐阅读:
  • HTTPS及加密算法,看这一篇就够了
  • 自定义View实现一个日期选择器
  • Wireshark分析验证TCP协议

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

flutter图片点击跳转_Flutter系列之Platform Channel使用详解 的相关文章

  • shell 多个引号冲突_请教Linux shell命令中双引号与单引号嵌套的问题

    addr 192 168 0 111 echo addr 结果为 192 168 0 111 echo addr 结果为 addr 这两个我还可以理解 1 双引号内的单引号功能被关闭 反之亦然 2 双引号内的 功能被保留 单引号 addr
  • fatal: Authentication failed for ‘https://github.com

    记录在本地电脑建立与GitHub连接时遇到的错误 附上解决方案 git clone 遇到的错误 remote Support for password authentication was removed on August 13 2021
  • osx 常用defaults命令

    defaults命令用来对mac os x系统进行某些设置 常用命令 查看所使用的defaults命令 history grep defaults 分类查看defaults命令 history grep defaults write his
  • JavaScript数据结构——字典(Dictionary)

    概念和结构 字典里面的元素都是一个键 key 值 value 对 字典里面的元素的键 key 不能重复 值 value 可以重复 字典的操作 字典有八种常用操作 分别为 检查键是否存在 has key 添加元素 set key value
  • js 搜索模糊匹配

    searchvalue list keyWord if keyWord var reg new RegExp keyWord var arr for var i 0 i lt list length i if reg test list i
  • Java8-对List转换Map、分组、求和、过滤

    前言 在java8之后我们list转map再也不用循环put到map了 我们用lambda表达式 使用stream可以一行代码解决 下面我来简单介绍list转map的几种方式 和转为map后对map进行分组 求和 过滤等操作 正文 数据准备
  • C#实现百度地图附近搜索&调用JavaScript函数

    前一篇文章 C 调用百度地图API入门 解决BMap未定义问题 讲述了如何通过C 调用百度API显示地图 并且如何解决BMap未定义的问题 这篇文章主要更加详细的介绍百度地图的一些功能 包括附近搜索 城市搜索 路线规划 添加覆盖物等等 希望
  • ipv6的链路本地地址

    目录 简介 先决条件 要求 使用的组件 规则 配置 网络图 配置 验证 检验 OSPF 的配置 正在验证的链路本地地址可接通性 ping从远程网络的链路本地地址 直接ping从连接的网络的链路本地地址 相关信息 简介 本文目的将提供对在网络
  • Qt漂亮界面

    Qt漂亮界面 功能规划 一 去掉菜单栏和工具栏 二 顶部导航栏的设计 appinit h头文件 appinit cpp的文件 使用方式 三 阵列按钮的点击事件写法 四 重写缩写界面 放大界面和关闭程序事件 五 鼠标事件的处理 Qt大量同类控
  • mysql数据库内容导出,MySql数据库导出

    Navicat Premium Data Transfer Source Server 刘文鹏 Source Server Type MySQL Source Server Version 50540 Source Host 127 0 0
  • 关于X79主板至强E5 CPU安装ArchLinux的记录

    最近想在家里搭网站 打算弄两台服务器 一个是旧机器x79主板的 作为AI绘图和Chatglm部署用 一个新买的是带有N5095的小板子 装了CentOS7来当web服务器 当作前置服务器 主要为外网提供服务 装CentOS7比较简单容易 所
  • TransFusion:利用 Transformer 进行鲁棒性融合来进行 3D 目标检测

    Query 初始化 Input dependent 以往 Query 位置是随机生成或学习作为网络参数的 而与输入数据无关 因此需要额外的阶段 解码器层 来学习模型向真实对象中心移动的过程 论文提出了一种基于center heatmap 的
  • VC6.0使用教程

    使用之前我们先准备一段代码 include
  • C#将依赖的DLL文件集成到EXE内部

    使用场景 C 写的一些小程序 为了方便传播 减少传播文件数量 将依赖的DLL文件集成到EXE内部是必要的 解决方案 打开 管理NuGet程序包 在浏览中搜索 Costura Fody 点击 安装 按钮 等待下载依赖及安装完成 重新编译软件
  • 操作系统7-信号量与管程

    回顾一下 并发问题 多线程并发导致资源竞争 同步概念 1 协调多线程对共享数据的访问 2 任何时刻只能由一个线程执行临界区代码 确保同步正确的方法 底层硬件支持 高层次的编程抽象 锁 信号量是锁机制在同一层上的高层抽象编程方法 一 信号量s
  • html如何设置网页的背景图片

    div div

随机推荐

  • Web安全面试题之-信息搜集(1)

    1 信息收集如何处理子域名爆破的泛解析问题 根据一个不存在的子域名的解析IP 来记录获取黑名单 IP 在爆破字典时 如果解析的IP在这个黑名单中 则默认跳过 如果不存在 我们则入库处理 还有一种泛解析的爆破处理方式是根据TTL来做判断 我们
  • 【Linux基础及shell脚本】Shell脚本中变量的使用

    文章目录 1 Shell变量基础 1 1 什么是变量 1 2 如何在Shell中定义和使用变量 2 Shell环境变量 2 1 什么是环境变量 2 2 环境变量与普通变量的区别 2 3 如何查看 设置和删除环境变量 3 Shell位置参数
  • 串口通信及中断

    异步通信 发送和接收数据的双方用各自的时钟控制数据的发送和接收 为降低数据传输的错误率要求双方时钟尽可能一致 异步通信以帧为单位传送数据 由于每帧数据都具有起始位和停止位所以两帧数据之间的间隔时间不影响数据传送和接收的准确率 但是每帧数据内
  • Git 笔记 - git commit

    文章目录 01 git commit 02 git commit m 03 git commit a 04 git commit p 05 git commit C 06 git commit c 07 git commit n 08 gi
  • 关于Map、WeakMap、Set 、WeakSet

    在计算机程序中 弱引用与强引用相对 是指不能确保其引用的对象不会被垃圾回收器回收的引用 一个对象若只被弱引用所引用 则被认为是不可访问的 或弱访问的 并因此可能在任何时刻被回收 Map Map 它类似于对象 也是键值对的集合 并且能够记住键
  • 基于长短期记忆神经网络LSTM的预测模型(matlab实现)

    希望是附丽于存在的 有存在 便有希望 有希望 便是光明 鲁迅 1 普通循环神经网络 循环神经网络 Recurrent Neural Networks 简称RNN 是一种能够处理时间序列数据的神经网络模型 可以自然的拟合时间和数据之间的关系
  • go 接口作为方法参数传递 

    接口作为方法参数传递 在方法内部修改结构体 示例 type IUserService interface GenId type UserService struct id string func u UserService GenId ge
  • git:分支管理策略

    主分支Master 首先 代码库应该有一个 而且仅有一个主分支 所有提供给用户使用的正式版本 都在这个主分支上发布 Git主分支的名字 默认叫做Master 它是自动建立的 版本库初始化以后 默认就是在主分支在进行开发 主分支 也是用于部署
  • 微信订阅号和公众号的区别

    第一 定位不同 订阅号为用户提供信息和资讯 服务号主要为用户提供服务 第二 群发信息量不同 订阅号每天 24小时内 可以发送1条群发消息 最新公众平台 服务号1个月 30天 内仅可以发送4条群发消息 第三 用户收到信息提醒方式不同 群发信息
  • Golang如何配置国内镜像

    1 打开国内镜像官网 GOPROXY IO 一个全球代理 为 Go 模块而生 2 您只需通过简单设置 PowerShell Windows 配置 GOPROXY 环境变量 env GOPROXY https goproxy io direc
  • Django 快速搭建博客 第六节

    上节我们用模板弄出来第一个hello world 这节课 我们把数据库里面真正的数据跟单篇文章的详情页显示出来 一 模板的下载 这里的模板下载指的是 下载js和css文件 一个网站想要变得漂亮 变得可以稍微好看点 这里我们使用是bootst
  • vue 使用nuxt创建工程

    1 按回车确定项目名称 2 选择语法 3 选择npm 4 选择框架 5 选择请求方式 6 7 8 9 10 11 回车 12 显示下面提示则创建成功 13
  • 数字电路与系统学习笔记(戚金清)

    第一章 数字逻辑基础 1 1模拟信号 模拟电路 数字信号 数字电路 连续变化的物理量是模拟量 表示模拟量的信号是模拟信号 字符数量无限 离散变化的物理量是数字量 表示数字量的信号是数字信号 字符数量有限 构成模拟电路的元件是电子管 模拟计算
  • stm32F4修改时钟频率,更换为8MHz晶振

    stm32F4修改时钟的方法和stm32F103修改时钟的方法不大一样 毕竟库都换了嘛 一个F1的库一个F4的库 而且F1的库默认晶振时钟就是8MHz 大多数开发板也用的8MHz时钟 给我们提供了很多的方便 F1的库关于PLL的写法也很直观
  • access_token

    access token是公众号的全局唯一接口调用凭据 公众号调用各接口时都需使用access token 开发者需要进行妥善保存 access token的存储至少要保留512个字符空间 access token的有效期目前为2个小时 需
  • 【Maven】jar包冲突原因与最优解决方案

    Maven jar包冲突原因与最优解决方案 文章目录 前言 jar包冲突原因 依赖传递 冲突原因 jar包冲突解决方案 Maven默认处理策略 排除依赖 版本锁定 maven shade plugin插件 总结 前言 你是否经常遇到这样的报
  • 机械革命Z2如何Ubuntu安装

    机械革命Z2如何Ubuntu安装 准备 一个4G大的U盘下载了Ubuntu系统 1 首先要进入BIOS F2 关闭Security Boot 设置U盘启动第一启动顺序 2 这个时候将选项移动到此处不要按回车 按E 3 此时 进入编辑模式 大
  • 史上最难HelloWorld

    文章目录 Tomcat Servlet 创建一个项目 引入依赖 创建目录 编写代码 打包 部署 验证 优化一下打包和部署 Smart Tomcat Servlet常见的问题 Tomcat Tomcat就是一个HTTP服务器 HTTP协议是前
  • 语音识别-信号处理篇

    我的书 淘宝购买链接 当当购买链接 京东购买链接 连接前端和后端的语音识别 ASR 的关键是给到后端 根据特征判定词 句 系统的特征类型和特征质量 对于传统的语音识别系统常采用MFCC mel frequency ceptral coeff
  • flutter图片点击跳转_Flutter系列之Platform Channel使用详解

    PS 逐渐体会到关键少数原则的重要性 接下来就是付诸实践了 另外科创50ETF明天开始限额销售 可以适当关注或入手一点 前面几篇文章介绍了 Navigator 组件 Flex 布局 图片加载 Widget 生命周期 混合开发等 Flutte