(原创)Flutter与Native通信的方式:MethodChannel

前言

随着Flutter混合开发的项目越来越多,我们也有了实际的一个场景,
那就是Flutter如何与原生(Native)端进行通信
目前看来,大概有三种方式,分别是:
MethodChannel
EventChannel
MessageChannel
这三种方式实现起来其实大同小异,基本的代码都差不多
但为了让大家更清楚的知道三者的区别,所以有了这篇博客
本篇主要讲MethodChannel方式
这也是实际开发中最常用的方式。
其他的两种方式可以看下一篇博客:
EventChannel和BasicMessageChannel
那么现在正式开始

实现

FlutterActivity

首先我们要知道,所谓的Flutter的一个个page页面,其实归根结底也是跑在Activity上面的
这有点像我们的WebView,最终承载页面的,还是一个Activity
而在Flutter中,承载页面的,其实是一个叫做FlutterActivity的类
于是我们的交互,其实是Flutter的Page和这个FlutterActivity进行交互
首先我们新建一个普通的Activity,也就是首页

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)findViewById<TextView>(R.id.textview).setOnClickListener {startActivity(MyFlutterActivity.withCachedEngine("your_engine_id").build(this))}}}

这个首页就是我们最基础的AppCompatActivity
它不是重点。
点击按钮进入我们承载Flutter的页面:MyFlutterActivity
它继承的是一个叫做FlutterFragmentActivity的类
这个页面就可以正式和他自己页面里的Flutter页面交互了
相关交互的代码也是写在这里

Flutter端调用Android端

先看Flutter端我们如何实现
首先我们可以新建一个ForNativePlugin.dart的文件
这个文件用来定义要调用Android端的方法

class ForNativePlugin {MethodChannel methodChannel = const MethodChannel("ForNativePlugin");/// 调用安卓,得到当前时间Future<String> getTime() async {var nowTime = await methodChannel.invokeMethod("getTime");return nowTime;}/// 显示安卓土司showAndroidToast(String msg) async {try {await methodChannel.invokeMethod('toast', {'msg': msg});} on PlatformException catch (e) {print(e.toString());}}
}

可以看到,创建了一个MethodChannel类
这个就是交互的关键类
MethodChannel的name属性要双端开发约定好
这里约定的是一个ForNativePlugin的字符串
然后定义了两个方法
方法的实现其实就是用methodChanneld.invokeMethod去触发安卓端的方法
invokeMethod的一个参数写安卓端的方法名,第二个写入参的名字,入参可以有多个

写好后,我们Flutter就可以创建这个类

ForNativePlugin forNativePlugin = ForNativePlugin();

然后在需要的时候使用我们写的这个工具类去触发Android端的方法了
比如:

forNativePlugin.showAndroidToast("当前时间为:${forNativePlugin.getTime()}");

这样就可以调用安卓端,获取时间,然后再让安卓端帮我们把时间返回后
通过Toast的方法弹出来
那么Android端要怎么写呢?
也很简单,Android端也要定义一个类
实现MethodCallHandler接口的onMethodCall方法

class MyMethodCallHandler(var context: Context) : MethodCallHandler {override fun onMethodCall(methodCall: MethodCall, result: MethodChannel.Result) {when (methodCall.method) {"getTime" -> {result.success(SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(System.currentTimeMillis()))}"toast" -> {if (methodCall.hasArgument("msg") && !TextUtils.isEmpty(methodCall.argument<Any>("msg").toString())) {Toast.makeText(context, methodCall.argument<Any>("msg").toString(), Toast.LENGTH_LONG).show()} else {
//          result.error()Toast.makeText(context, "msg 不能为空", Toast.LENGTH_SHORT).show()}}else -> {// 表明没有对应实现result.notImplemented()}}}
}

onMethodCall方法就用来处理我们要被触发的逻辑了
然后来到我们继承了FlutterFragmentActivity的类下面
首先也定义一个MethodChannel

private lateinit var flutterMethodChannel: MethodChannel

然后让我们Activity去实现configureFlutterEngine方法

  override fun configureFlutterEngine(flutterEngine: FlutterEngine) {super.configureFlutterEngine(flutterEngine)//通过MethodChannel与原生通信,ForNativePlugin为约定字段flutterMethodChannel = MethodChannel(flutterEngine.dartExecutor, "ForNativePlugin")flutterMethodChannel.setMethodCallHandler(MyMethodCallHandler(this))}

可以看到,这里其实就是一个注册环节
把我们的MyMethodCallHandler类注册到MethodChannel里面
至此,Flutter端调用Android端代码就完成了

补充一点:
在Android端被触发时
可以通过result类告知Flutter请求结果是否成功
result.success() 成功
result.error() 失败
result.notImplemented() 该方法没有对应实现

Android端调用Flutter端

Android端调用Flutter端其实也差不多
首先是Android端:
我们可以通过调用getFlutterEngine方法获得一个FlutterEngine
然后拿这个FlutterEngine的getDartExecutor进行操作

  fun toFlutter(num1: Int, num2: Int) {flutterEngine?.dartExecutor?.let {nativeMethodChannel = MethodChannel(it, "ForFlutterPlugin")nativeMethodChannel.invokeMethod("callFlutterSum",listOf<Int>(num1, num2),object : MethodChannel.Result {override fun success(result: Any?) {Log.d("MyFlutterActivity", "计算结果为 = $result")}override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {Log.d("MyFlutterActivity", "出错了:$errorCode, $errorMessage, $errorDetails")}override fun notImplemented() {Log.d("MyFlutterActivity", "notImplemented")}})}}

这里可以看到,也是定义了一个MethodChannel,约定字段为:ForFlutterPlugin
然后调用Flutter端的callFlutterSum方法获取计算的返回值
这里需要注意一点,调用Fluter代码要在主线程

然后来到Flutter端
定义好Flutter端的MethodChannel:

MethodChannel methodChannel = const MethodChannel("ForFlutterPlugin");

并执行注册和回调监听,可以在initState方法中注册:

  void initState() {// TODO: implement initStatesuper.initState();methodChannel.setMethodCallHandler((call) {switch (call.method) {case 'callFlutterSum':print('call callMe : arguments = ${call.arguments}');List<Object?> numbers = call.arguments;var num1=numbers[0] as int;var num2=numbers[1] as int;//触发Android端的success方法return Future.value(num1+num2);//触发Android端的error方法,errorCode为error,errorMessage为:调用出错,不能传details// return Future.error("调用出错");//触发Android端的error方法,可以额外传details对象throw PlatformException(code: 'errorCode', message: 'Error occurred',details: "出错了");default:print('Unknowm method ${call.method}');//触发Android端的notImplemented方法throw MissingPluginException();}},);}

至此,Flutter端的工作也已完成
可以看到,两端的互相调用,基本分为三个步骤:
1:被调用端先写好被调用的处理逻辑
2:被调用端创建好MethodChannel,调用setMethodCallHandler进行注册
3:调用端创建MethodChannel,约定好字段,然后使用invokeMethod主动去调用方法

注意

在你写双端通信的时候,如果发现不触发调用,可以关注以下几个原因:
1:是否是继承了FlutterFragmentActivity或者FlutterActivity
2:约定字段是否一致
3:方法名称和参数是否一致

源码

本篇博客源码地址:
MethodChannel

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/9243.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis配置与优化

目录 一、关系数据库与非关系型数据库 1、关系型数据库 2、非关系型数据库 3、关系型数据库和非关系型数据库区别 1、数据存储方式不同 2、扩展方式不同 3、对事务性的支持不同 二、Redis 1、简介 2、优点 3、缺点 4、使用场景 5、哪些数据适合放入缓存中 6、为什…

vue-cli脚手架创建创建的项目打包后无法正常打开报 Failed to load resource: net::ERR_FILE_NOT_FOUND错误

亲爱的小伙伴们&#xff0c;你们最近是否有遇到用使用最新的脚手架打包项目后index.html文件无法正常打开&#xff0c;然后控制台报错的情况呢&#xff0c;不要担心&#xff0c;这个坑今天被我踩到了并且被我解决了&#xff0c;下边就让我来给大家分享一下经验吧&#xff01; …

D. Maximum Subarray

Problem - 1796D - Codeforces 思路&#xff1a;想了个假dp做法推了半天&#xff0c;果然是dp。考虑用dp[i][j]表示以i结尾的&#xff0c;并且选择j个&#xff0b;x的最长连续子序列&#xff0c;那么如果我不选择第i位&#xff0c;那么会有f[i][j]max(w[i]-x,f[i-1][j]w[i]-x)&…

Kubernetes 的核心概念:Pod、Service 和 Namespace 解析

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Linux共享库库+例子

1.什么是共享库&#xff1f;有什么优点&#xff1f;和静态库有什么区别&#xff1f; Linux动态库&#xff08;Dynamic Link Library&#xff0c;缩写为DLL&#xff09;是一种在Linux系统中使用的共享库&#xff08;Shared Library&#xff09;。与静态库不同&#xff0c;动态库…

飞机乘坐流程/怎么坐飞机

飞机乘坐流程/怎么坐飞机 编写原因对象人员经历背景飞机乘坐流程流程梗概订票去往机场办理登记牌/托运行李安检登机转机 飞行中下机 后记 编写原因 从上家单位裸辞&#xff0c;大概率下次不会找频繁出差的工作了&#xff0c;而日常出行应该也不会考虑飞机这种交通工具&#xf…

结构型设计模式之外观模式【设计模式系列】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 设计模式系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everythi…

剑指YOLOv8改进最新MPDIoU损失函数:超越现有多种G/D/C/EIoU,23年7月首发论文,高效准确的边界框回归的损失

💡本篇内容:剑指YOLOv8改进最新MPDIoU损失函数:超越现有多种G/D/C/EIoU,23年7月首发论文,高效准确的边界框回归的损失 💡🚀🚀🚀本博客 改进源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 💡:重点:该专栏《剑指YOLOv8原创改进》只更新改进 YOLO…

雷达信号处理自学总结(持续更新)

傅里叶变换的频率分辨率 频率分辨率 采样频率 信号长度 频率分辨率 \frac{采样频率 }{信号长度} 频率分辨率信号长度采样频率​ 可用numpy模块的fft.fftfreq函数求出傅里叶变换的频率分辨率。 https://numpy.org/doc/stable/reference/generated/numpy.fft.fftfreq.html

若依vue -【 44】

44 服务监控讲解 1 需求 显示CPU、内存、服务器信息、Java虚拟机信息、磁盘状态的信息 2 前端 RuoYi-Vue\ruoyi-ui\src\views\monitor\server\index.vue <script> import { getServer } from "/api/monitor/server";export default {name: "Server&quo…

JS(es6)同时给多个变量赋值

在ES6中&#xff0c;可以使用解构赋值语法同时给多个变量赋值。解构赋值语法可以从数组或对象中提取值&#xff0c;并将其赋给多个变量。 1. 数组解构赋值&#xff1a; const [var1, var2, var3] [1, 2, 3] console.log(var1); // 输出 1 console.log(var2); // 输出 2 cons…

前端技术搭建(动态图片)拖拽拼图!!(内含实现原理)

文章目录 前端技术搭建&#xff08;动态图片&#xff09;拖拽拼图(内含实现原理)导言功能介绍效果演示链接&#xff08;觉得不错的&#xff0c;请一键三连嘤嘤嘤&#xff09;项目目录页面搭建css样式设置工具函数游戏实现逻辑 开源地址总结 前端技术搭建&#xff08;动态图片&a…

什么是tcp rst以及什么时候产生?

rst包是仅在header control bits设置rst的空payload包&#xff0c;用于强制关闭tcp连接。常在以下场景发送 远程主机没有监听该端口 远程主机强迫关闭了一个现有连接。比如服务端进程崩溃后重启会向之前连接发送rst 相比于四次挥手的fin&#xff0c;rst是在异常情况下的无条…

SpringBoot整合JavaMail

SpringBoot整合JavaMail 简单使用-发送简单邮件 介绍协议 导入坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>添加配置 spring:mail:host: smtp.qq.co…

企业邮箱搭建费用,smtp邮件系统怎么搭建?验证码邮件群发,有哪些推荐邮件群发系统?

您是否为没法发smtp群发邮件而苦恼&#xff0c;别担心&#xff0c;这里将给大家介绍一下什么是企业邮箱&#xff0c;邮局系统怎么搭建&#xff0c;验证码邮件群发&#xff0c;有哪些推荐邮件群发系统&#xff1f; 企业邮箱搭建&#xff1a;成本和考量因素 在如今数字化的商业…

Wonderful Sql

Wonderful Sql 一. 初识数据库 练习题 1.1 编写一条 CREATE TABLE 语句&#xff0c;用来创建一个包含表 1-A 中所列各项的表 Addressbook &#xff08;地址簿&#xff09;&#xff0c;并为 regist_no &#xff08;注册编号&#xff09;列设置主键约束 表1-A 表 Addressbook…

java代码审计6之ssrf

文章目录 1、java支持的网络请求协议&#xff1a;2、Java 中能发起⽹络请求的类2.1、仅⽀持 HTTP/HTTPS 协议的类2.2、⽀持 sun.net.www.protocol 所有协议的类2.3、审计关键词 3、靶场3.1、漏洞代码13.2、ftp协议读取技巧3.3、无回显之探测内网3.4、无回显之探测文件 之前的文…

el-input 文本框 输入数字校验

目录 1. 输入整数 2. 输入整数和小数 3. 输入两位小数 1. 输入整数 <el-inputv-model"scopeRows.row.inWarehouseRow.Quantity"type"number"blur"getRowData(scopeRows.row.inWarehouseRow)"oninput"valuevalue.replace(/^0|[^0-9]/g…

【前缀和】238. 除自身以外数组的乘积

238. 除自身以外数组的乘积 解题思路 前缀与后缀的思路对于给定索引i&#xff0c;将它左边的所有数字乘积乘以右边所有数字的乘积初始化两个数组L R计算L[i] L[i - 1] * nums[i - 1] 也就是左侧所有数字的乘积计算R[i] R[i 1] * nums[i 1] 也就是右侧所有数字的成绩计算L…

Ceph概述、准备ceph部署环境、cephadm概述、安装Ceph集群、ceph块存储、存储池、rbd镜像管理、ceph客户端配置

day03 day03ceph概述部署Ceph节点准备cephadm准备基础环境安装ceph实现块存储块存储基础存储池镜像ceph客户端 ceph概述 ceph可以实现的存储方式&#xff1a; 块存储&#xff1a;提供像普通硬盘一样的存储&#xff0c;为使用者提供“硬盘”文件系统存储&#xff1a;类似于NFS…