【Flutter跨平台插件开发】如何实现kotlin跟C++的相互调用
【Flutter跨平台插件开发】如何实现kotlin跟C++的相互调用
kotlin 调 c++
在 Kotlin 中,可以使用 JNI (Java Native Interface) 来调用 C++ 代码
调用步骤:
- 创建 C++ 文件并实现函数。
// example.cpp
#include <jni.h>extern "C" JNIEXPORT jstring JNICALL
Java_com_example_MyClass_myFunction(JNIEnv* env, jobject /* this */) {return env->NewStringUTF("Hello from C++");
}
- 在 Kotlin 中声明需要调用的 native 函数并加载 native 库。
class MyClass {external fun myFunction(): Stringcompanion object {init {System.loadLibrary("example") // example是库的名字}}
}
- 调用示例
val myClass = MyClass()
println(myClass.myFunction()) // 输出 "Hello from C++"
Flutter 插件项目的例子
在 Flutter 插件中引用已有的 C++ 源码需要以下步骤:
- 首先,在 Flutter 插件的 android 目录下创建一个 CMakeLists.txt 文件,这个文件会告诉 CMake 如何编译你的 C++ 代码。
cmake_minimum_required(VERSION 3.4.1)add_library( # Specifies the name of the library.native-lib# Sets the library as a shared library.SHARED# Provides a relative path to your source file(s).src/main/cpp/native-lib.cpp )
- 然后,在插件的 build.gradle 文件中启用 CMake 并指定 CMakeLists.txt 文件的位置。
android {// ...defaultConfig {// ...externalNativeBuild {cmake {cppFlags ""}}}externalNativeBuild {cmake {path "CMakeLists.txt"}}
}
- 在 Kotlin 代码中,可以使用
System.loadLibrary来加载库,并使用external关键字来声明 native 方法。
class MyPlugin: FlutterPlugin, MethodCallHandler {// ...external fun myNativeMethod(): Stringinit {System.loadLibrary("native-lib")}// ...
}
- 最后,在 C++ 代码中实现函数。
#include <jni.h>extern "C" JNIEXPORT jstring JNICALL
Java_com_example_MyPlugin_myNativeMethod(JNIEnv* env, jobject /* this */) {// 你的代码...
}
注意
- 需要使用
ndk-build或者 CMake 来编译 C++ 代码,并将生成的库放到 Android 项目的jniLibs目录下。 - C++ 函数的名称必须遵循特定的格式:
Java_包名_类名_方法名。在这个例子中,Java_com_example_MyClass_myFunction对应于com.example.MyClass类的myFunction方法。
c++ 调 kotln
在 Kotlin 中,可以使用 JNI (Java Native Interface) 来设置回调到 C++ 代码。
同步调用(这个需要kotlin先调到cpp,cpp再调回来,都是同步操作)
- 在 Kotlin 中创建一个接口,该接口将被 C++ 代码调用。
interface Callback {fun onEvent(event: String)
}
- 创建一个 native 函数,kotlin 的回调函数将通过这个native函数,传给cpp
class MyClass {private var callback: Callback? = nullfun setCallback(callback: Callback) {this.callback = callback}external fun triggerEvent()private fun onEvent(event: String) {callback?.onEvent(event)}companion object {init {System.loadLibrary("example")}}
}
- 在 C++ 代码中实现
triggerEvent函数,从参数中获取onEvent方法并调用。
#include <jni.h>extern "C" JNIEXPORT void JNICALL
Java_com_example_MyClass_triggerEvent(JNIEnv* env, jobject instance) {jclass cls = env->GetObjectClass(instance);jmethodID mid = env->GetMethodID(cls, "onEvent", "(Ljava/lang/String;)V");if (mid == nullptr) return; // method not foundjstring message = env->NewStringUTF("Hello from C++");env->CallVoidMethod(instance, mid, message);
}
在这个例子中,triggerEvent 函数在 C++ 代码中被调用,然后它调用 Kotlin 中的 onEvent 方法,该方法然后调用 Callback 接口的 onEvent 方法。
方法签名
在 JNI (Java Native Interface) 中,“(Ljava/lang/String;)V” 是一个方法签名,用于描述方法的参数类型和返回值类型
这个签名可以被分解为以下部分:
-
括号 “(” 和 “)”:括号内的内容描述了方法的参数类型。在这个例子中,“Ljava/lang/String;” 表示方法有一个参数,类型为
java.lang.String。 -
“V”:这是方法的返回值类型。在 JNI 中,“V” 表示 void,也就是说这个方法没有返回值。
所以,“(Ljava/lang/String;)V” 这个签名表示的是一个接受一个 java.lang.String 参数并且没有返回值的方法。
其他一些常见的 JNI 类型签名包括:
- “I”:表示 int
- “J”:表示 long
- “S”:表示 short
- “B”:表示 byte
- “C”:表示 char
- “D”:表示 double
- “F”:表示 float
- “Z”:表示 boolean
- “[I”:表示 int 数组
- “Lfully/qualified/ClassName;”:表示 fully.qualified.ClassName 类型的对象
你可以在 JNI 文档中找到更多关于类型签名的信息。
异步回调
在 JNI 中,JNIEnv* 和 jobject 通常不能直接保存起来用于异步回调。
这是因为:
JNIEnv*是线程相关的,每个线程都有一个不同的JNIEnv*。如果你在一个线程保存了JNIEnv*,然后在另一个线程使用它,可能会导致问题。- 同样,
jobject是一个局部引用,它只在当前的 JNI 调用中有效,调用结束后就会被自动删除。
如果你需要在异步回调中使用这些对象,你需要做一些额外的步骤:
-
对于
JNIEnv*,你需要在回调的线程中通过JavaVM*获取一个新的JNIEnv*。你可以在保存JNIEnv*的同时保存JavaVM*,通过调用JNIEnv->GetJavaVM(&jvm)获取。 -
对于
jobject,你需要创建一个全局引用,这样它就可以跨越多个 JNI 调用。你可以通过调用JNIEnv->NewGlobalRef(jobject)来创建一个全局引用。记住在你不再需要这个全局引用时,需要调用JNIEnv->DeleteGlobalRef(jobject)来删除它,防止内存泄漏。
以下是一个简单的例子:
JavaVM* jvm;
jobject globalObj;JNIEXPORT void JNICALL Java_MyClass_init(JNIEnv* env, jobject obj) {env->GetJavaVM(&jvm);globalObj = env->NewGlobalRef(obj);
}void asyncCallback() {JNIEnv* env;jvm->AttachCurrentThread(&env, NULL);// 有了env跟obj后,这里参考上面同步调用的例子的实现jvm->DetachCurrentThread();
}
在这个例子中,Java_MyClass_init 是一个 JNI 方法,它保存了 JavaVM* 和一个全局引用。然后在 asyncCallback 中,我们获取了一个新的 JNIEnv*,并使用了全局引用。注意我们在回调结束时调用了 DetachCurrentThread,这是因为我们之前调用了 AttachCurrentThread。如果你在一个已经被附加到 JVM 的线程中调用回调,你不需要调用这两个方法。
相关文章:
【Flutter跨平台插件开发】如何实现kotlin跟C++的相互调用
【Flutter跨平台插件开发】如何实现kotlin跟C的相互调用 kotlin 调 c 在 Kotlin 中,可以使用 JNI (Java Native Interface) 来调用 C 代码 调用步骤: 创建 C 文件并实现函数。 // example.cpp #include <jni.h>extern "C" JNIEXPORT jstring J…...
Apache SeaTunnel社区荣获“2023快速成长开源项目”奖项
在这个开源理念推动技术创新和全球协同发展的时代,SeaTunnel社区在开放原子开源基金会举办的2023年开源项目评选中脱颖而出,荣获“2023快速成长开源项目”殊荣。 这个奖项不仅仅是对Apache SeaTunnel社区过去一年发展速度和质量的认可,更是对…...
Unity 桥接模式(实例详解)
文章目录 示例1:角色与装备系统示例2:UI控件库示例3:渲染引擎模块示例4:AI决策树算法示例5:物理模拟引擎 在Unity游戏开发中,桥接模式(Bridge Pattern)是一种设计模式,它…...
Xftp连接不上Linux虚拟机的原因解决方法
前言: 在当今数字化时代,远程连接到Linux虚拟机是许多开发者和系统管理员日常工作的一部分。然而,有时候,面对Xftp连接不上Linux虚拟机的问题,我们可能感到困惑和无措。这个看似小问题可能导致工作中断,因…...
代码随想录刷题笔记 DAY12 | 二叉树的理论基础 | 二叉树的三种递归遍历 | 二叉树的非递归遍历 | 二叉树的广度优先搜索
Day 12 01. 二叉树的理论基础 1.1 二叉树的种类 满二叉树:除了叶子节点以外,每个节点都有两个子节点,整个树是被完全填满的完全二叉树:除了底层以外,其他部分是满的,底部可以不是满的但是必须是从左到右连…...
Linux问题 apt-get install时 无法解析域名“cn.archive.ubuntu.com”
问题描述: 在安装程序时会出现无法解析域名的错误 解决办法: 1、编辑文件 sudo vim /etc/resolv.conf 2、在最后加上(按键 i 进入编辑模式) nameserver 8.8.8.8 3、保存退出(:wq)...
蓝桥--鸡哥的购物挑战OJ(4169)
题目: 思路: 暴力: 直接枚举所有得偶数区间,找最大值,n2超时 优化: 分类讨论,只要醉倒不重不漏得分类不出意外就能AC了 图中的选择方式很简单了,不做解释了。 AC代码(我的代码可…...
MySQL--删除数据表(6)
MySQL中删除数据表是非常容易操作的,但是你在进行删除表操作时要非常小心,因为执行删除命令后所有数据都会消失。 语法 以下为删除 MySQL 数据表的通用语法: DROP TABLE table_name ; -- 直接删除表,不检查是否存在 或 DROP…...
常用界面设计组件 —— 时间日期与定时器
2.7 时间日期与定时器2.7.1 时间日期相关的类2.7.2 日期时间数据与字符串之间的 转换2.7.3 QCalendarWidget日历组件2.7.4 定时器 2.7 时间日期与定时器 2.7.1 时间日期相关的类 时间日期是经常遇到的数据类型,Qt中时间日期类型的 类如下: QTime &…...
GO 中高效 int 转换 string 的方法与高性能源码剖析
文章目录 使用 strconv.Itoa使用 fmt.Sprintf使用 strconv.FormatIntFormatInt 深入剖析1. 快速路径处理小整数2. formatBits 函数的高效实现 结论 Go 语言 中,将整数(int)转换为字符串(string)是一项常见的操作。 本文…...
YOLOv7调用摄像头检测报错解决
yolov7detect.py文件调用本地摄像头,把source参数设为0 parser.add_argument(--source, typestr, default0, helpsource) # file/folder, 0 for webcam 报错:cv2.error: OpenCV(3.4.2) 一堆地址:The function is not implemented. Rebuild the library…...
Git学习 -- 分支合并、版本修改相关
目录 learn GIT Learn Git Branching merge和rebase的使用 基础命令 版本回退 工作区和暂存区 管理修改 撤销修改 删除修改 learn GIT Learn Git Branching 这是Gitee上的Git学习教程 Learn Git Branching Git Rebase Learn Git Branching 最终的实操 merge和rebase的…...
【小呆的力学笔记】弹塑性力学的初步认知二:应力应变分析(2)
文章目录 1.4 主应力空间、八面体应力1.5 应变分析1.6 特殊应力、应变定义 1.4 主应力空间、八面体应力 一点的应力状态不论如何变化,其主应力和主方向一致的话,该点的应力状态就是唯一确定的。因此,我们用主应力方向建立一个三维坐标系来描…...
【学网攻】 第(6)节 -- 三层交换机实现VLAN间路由
文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻】 第(4)节 -- 交换机划分Vlan【学网攻】 第(5)节 -- Cisco VTP的使用 前言 网络已经成为了我们生活中不可或缺的一部分,它连接了…...
C++之内联函数
函数调用在执行时,首先要在栈中为形参和局部变量分配存储空间,然后还要将实参的值复制给形参,接下来还要将函数的返回地址(该地址指明了函数执行结束后,程序应该回到哪里继续执行)放入栈中,最后…...
【Bugku-web】alert
1.打开场景 2.按"CtrlU"查看源代码 3.翻到页面最末尾会有一个HTML实体编码,用在线工具在线Html实体编码解码后,得到flag值。...
QQ数据包解密
Windows版qq数据包格式: android版qq数据包格式: 密钥:16个0 算法:tea_crypt算法 pc版qq 0825数据包解密源码: #include "qq.h" #include "qqcrypt.h" #include <WinSock2.h> #include…...
腾讯云上linux系统使用nginx,flask构建个人网站SSL证书过期换证书的操作步骤
ssl证书过期的时候,一般腾讯云提前一段时间给通知,让更换ssl证书,现在一般都可以免费更换,一般是一年期的,审核通过之后,需要下载nginx版本的证书,我的是4个文件,替换到nginx/cert文…...
git-clone的single-branch操作回退
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu) 最近使用git越来越多,一些git的功能使用也更熟悉了一些。 之前使用了single-branch下载分支,后来想取消掉,但怎么做呢,查了一些资料之后,了解到了怎么做&#x…...
03 SpringBoot实战 -微头条之首页门户模块(跳转某页面自动展示所有信息+根据hid查询文章全文并用乐观锁修改阅读量)
1.1 自动展示所有信息 需求描述: 进入新闻首页portal/findAllType, 自动返回所有栏目名称和id 接口描述 url地址:portal/findAllTypes 请求方式:get 请求参数:无 响应数据: 成功 {"code":"200","mes…...
从磁力线到最小磁阻:手把手拆解一个微型直流电机的内部‘磁路战争’
从磁力线到最小磁阻:手把手拆解一个微型直流电机的内部‘磁路战争’ 拆开一枚硬币大小的玩具电机,你会看到一场无声的物理博弈——磁力线像急于回家的士兵,不断寻找最短路径;而转子则是这场战役的指挥官,通过精确的旋…...
终极指南:3分钟掌握原神圣遗物扫描工具Amenoma的完整使用技巧 [特殊字符]
终极指南:3分钟掌握原神圣遗物扫描工具Amenoma的完整使用技巧 🎯 【免费下载链接】Amenoma A simple desktop application to scan and export Genshin Impact Artifacts and Materials. 项目地址: https://gitcode.com/gh_mirrors/am/Amenoma 还…...
避坑指南:uniapp调用支付宝授权时常见的5个错误及解决方案
Uniapp支付宝授权实战:5个高频错误与深度解决方案 移动应用开发中,第三方授权登录是提升用户体验的关键环节。作为国内主流支付平台,支付宝授权在电商、生活服务类App中应用广泛。但许多Uniapp开发者在实现支付宝授权功能时,总会遇…...
【Serverless架构生死线】:Java函数冷启动超时率>17%?2024最新CNCF基准测试下的3层防御体系构建
第一章:Serverless架构下Java函数冷启动的生死挑战在Serverless平台(如AWS Lambda、阿里云函数计算、腾讯云SCF)中,Java函数因JVM初始化、类加载、字节码验证及Spring等框架启动开销,常面临数百毫秒至数秒级的冷启动延…...
从DataBinding到Compose:一个老Android的UI数据绑定演进思考
从DataBinding到Compose:一个老Android的UI数据绑定演进思考 作为一名从Eclipse时代走过来的Android开发者,我见证了UI开发方式的多次变革。从最初手工调用findViewById的繁琐,到ButterKnife的注解简化,再到DataBinding带来的声明…...
手把手教你配置:用微型纵向加密搞定IEC-104协议的风光数据安全上传
新能源场站IEC-104协议安全传输实战:微型纵向加密配置全指南 在新能源场站的自动化系统中,IEC-104协议作为电力行业标准通信规约,承担着风机、光伏逆变器与升压站之间关键运行数据传输的重任。然而,传统光纤环网中的明文传输方式存…...
1985–2024年武汉大学CLCD中国土地利用/覆被数据集(逐年30米栅格)|高精度长时序LUCC产品
🔍 数据简介 CLCD(China Land Cover Dataset) 是由武汉大学测绘遥感信息工程国家重点实验室李熙教授、李德仁院士团队基于Landsat系列卫星影像,结合深度学习与多源辅助数据(如夜间灯光、POI、道路网等)&…...
CIC-IDS-2018数据集 代码预处理
CIC-IDS-2018数据集 预处理 数据集的获取地址在 https://aistudio.baidu.com/datasetdetail/60692 第一次登陆,注册就行,内容随便填就能注册 create_sample_data() 在代码中被注释,没有添加数据之前,可以跑一下这个函数&…...
Tao-8k辅助学术研究:从研究想法到LateX论文草稿
Tao-8k辅助学术研究:从研究想法到LateX论文草稿 作为一名研究生或科研人员,你是否经常被这样的场景困扰:脑子里有个模糊的研究想法,却不知如何系统化地展开;面对海量文献,梳理综述耗时耗力;实验…...
别再手动复制粘贴了!用CubeMX一键生成FreeRTOS工程(STM32F4 HAL库实战)
告别繁琐配置:STM32CubeMXFreeRTOS全自动工程生成指南 在嵌入式开发领域,时间就是竞争力。传统FreeRTOS移植需要手动复制文件、配置路径、修改中断向量表,稍有不慎就会陷入头文件缺失、链接错误的泥潭。现在,STM32CubeMX的图形化…...
