鸿蒙App是如何调用C++的?
前言
当我们开发鸿蒙应用时,ArkTs是当前界面和业务相关的主流代码。然而,在有些特定场景中,我们还是得请出C++——当涉及到计算密集型任务时,或者有些功能有成熟的C++库。那么,ArkTs是如何调用到C++的代码的呢?
新建工程
让我们结合实践,来分析一下ArkTs和C++的互通。首先使用DevEco Studio创建一个新工程,记得选模板时选择Native C++。 创建完成之后,我们可以看到,工程目录里多了一个和ets平级的cpp文件夹。
初步分析
这是IDE给我们的一个初始示例,我们先跟随模板工程来探寻调用的路径。 在Index.ets
中,点击文字触发onClick
事件。我们可以看到调用了testNapi.add(2, 3)
这个方法。 这个方法从
import testNapi from 'libentry.so';
导入包。 跳转到包的定义中,会跳向文件
cpp/types/libentry/Index.d.ts
。这里定义的方法,和我们在界面里onClick()
中调用的testNapi.add(2, 3)
定义相吻合。 然而,线索到这里之后,就没有那么直观了。再让IDE自动跳转方法定义,无法直接跳转。此时,还记得我们最初想要寻找什么吗?对了,ArkTs到C++的调用路径。 我们在cpp文件夹里直接寻找线索。
CMakeLists.txt
中声明了需要编译的cpp文件add_library(entry SHARED napi_init.cpp)
。我们直接看向napi_init.cpp
。 在这个文件中,有一个
Add
方法,哦不对,C++里叫函数。函数里的内容很多,但我们粗略寻找一下关键的字眼,能看到sum
变量,于是确定最终调用的函数在这里。 这中间还差一步,
Index.d.ts
中的方法定义是怎么和napi_init.cpp
中这个函数关联起来的?我们在C++中Add
函数上右键Go To -> Declaration or Usages
会发现这个函数指针在下面Init
函数中被用到。在如图划线处传入的参数,前方字符串和Index.d.ts
中定义的方法名需完全一致,后方函数指针为关联的函数的指针
这样我们初步分析出了,从ArkTs到C++的调用,先是从import的库中,遵循Index.d.ts
的定义,调用ts方法。在napi_init.cpp
的Init
函数中把ts方法名用字符串的形式和实际调用的C++函数关联了起来。最终调用到了C++里对应的函数。
传值
这个初始工程非常周到地把传值的示例也写了进去。在界面中调用ts方法时,传入了两个number类型的参数,返回了一个number类型的参数。我们记住这个前提,来分析一下C++中Add
函数如何入参和出参。直接上代码,我用注释的形式来解读一遍。
// 这里的入参不是ts实际的入参,出参需要包装为napi_value类型
static napi_value Add(napi_env env, napi_callback_info info)
{
// 声明入参个数
size_t argc = 2;
// 声明入参数组
napi_value args[2] = {nullptr};
// 获取入参,参数会被写入args
napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
// 声明第0个参数类型
napi_valuetype valuetype0;
// 获取第0个参数类型(案例中并未使用),因为传地址,获取到的值会被写入valuetype0
napi_typeof(env, args[0], &valuetype0);
// 获取第1个参数类型,同上
napi_valuetype valuetype1;
napi_typeof(env, args[1], &valuetype1);
// 声明第0个参数值
// 这里写double是因为ts方法定义的时候,对应的参数是number。这里具体定义什么类型,需要自己控制
double value0;
// 获取第0个参数值。同样使用了传指针的方式,获取到的值会写入value0
napi_get_value_double(env, args[0], &value0);
// 获取第1个参数值,同上
double value1;
napi_get_value_double(env, args[1], &value1);
// 声明返回值
napi_value sum;
// 创建一个double类型返回值,写入sum。这里不能直接返回C++的double类型,需要用此方法包成napi_value
napi_create_double(env, value0 + value1, &sum);
// napi_value作为返回值,从函数返回,使得ts方法获得number类型返回值
return sum;
}
可以看到不同语言之间传值的交互还是比较复杂的,解包和封包需要很多流程。尤其因为C++的语法步骤更多。 到这一步,我们从这个示例代码中就可以举一反三,学会了ts和C++之间如何互相传递其他基本类型的参数。
更多
更完整详细的文档推荐这两篇,囊括了几乎所有可能遇到的开发场景。 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/napi-use https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/napi-scenarios
- 0回答
- 0粉丝
- 3关注
- HarmonyOS的NDK开发实战(使用ASan检查c/c++代码内存问题)
- HarmonyOSNext性能核弹:用Node-API引爆ArkTS/C++跨语言
- 鸿蒙开发:父组件如何调用子组件中的方法?
- HarmonyOS NEXT父组件如何调用子组件的方法?
- HarmonyOS中如何在类中调用全局的弹窗
- 基于ArkUI-X的N-API跨平台开发实践:实现ArkTS与C++的双向通信(Harmony OS NETX 5)
- uni-app/uniappx 中调用鸿蒙原生扫码能力的实践
- 如何调用系统拍照并获取图片
- 鸿蒙开发:什么是ArkTs?
- 使用uts调用鸿蒙原生API
- HarmonyOS 5.0元服务原来是这样的(1)!!
- HarmonyOS 5.0元服务原来是这样的(2)!!
- 真正的纯血鸿蒙开发者是怎样开发应用的?纯血鸿蒙到底”纯“在哪里?
- 什么是Uniapp(初识Uniapp)一
- 【HarmonyOS】鸿蒙应用实现调用系统地图导航或路径规划