掌握DevEco Studio这一功能,高效实现ArkTS与C++胶水代码
1、背景介绍
HarmonyOS 主要提供了ArkTS与C++作为开发语言:
- ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,保持了TS的基本风格,同时通过规范定义强化开发期静态检查和分析,提升程序执行稳定性和性能。ArkTS适合用在高效UI界面开发场景。
- C++以NDK(Native Development Kit)工具集的方式提供支持,NDK是HarmonyOS SDK提供的Native API、相应编译脚本和编译工具链的集合,方便开发者使用C或C++语言实现应用的关键功能。NDK只覆盖了HarmonyOS一些基础的底层能力,如C运行时基础库libc、图形库、窗口系统、多媒体、压缩库、面向ArkTS/JS与C跨语言的Node-API等,并没有提供ArkTS/JS API的完整能力。C++语言适合下方这些场景:
- 性能敏感的场景,如游戏、物理模拟等计算密集型场景。
- 需要复用已有C或C++库的场景。
- 需要针对CPU特性进行专项定制库的场景,如Neon加速。
有一些能力HarmonyOS只提供了C++接口支持,比如音视频编解码等,而且我们注意到最新发布的HarmonyOS 5.0.1版本,新增的能力主要是C API,所以要挖掘HarmonyOS更多能力成为一个资深HarmonyOS工程师,ArkTS与C++混合开发是必不可少的。
ArkTS调用C++需要经过一系列复杂流程,本文主要介绍DevEco Studio提供的一键生成跨语言"胶水"代码工具帮助大家提升开发效率。
2、ArkTS调用C++方法流程
类似于Android JNI,HarmonyOS 中ArkTS调用C++方法主要是NAPI提供能力。本节以DevEco Studio新建的Native C++工程Demo为例介绍ArkTS调用C++方法流程。下图是创建Native C++工程后的代码结构图:
主要有三大部分组成:
- types:
- Index.d.ts:主要包含对ArkTS暴露的C++接口。
- oh-package.json5:指定动态库名称和上面Index.d.ts文件路径。
- CMakeLists.txt:C++代码构建脚本。
- napi_init.cpp:C++实现代码
开发Native模块一般流程就是要实现上述对应模块。
2.1 Index.d.ts中声明C++接口
声明的函数供C++实现和ArkTS中调用
typescript
export const add: (a: number, b: number) => number;
2.2 C++中注册和实现声明方法
首先在NAPI的Init方法中注册Index.d.ts中声明的方法:
arduino
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
{ "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
napi_property_descriptor是一个数组,可以实现多个方法。示例中字符串"add"表示Index.d.ts中声明的add方法,第三个参数Add表示C++中实现的方法名。接下来就需要实现Add方法:
ini
static napi_value Add(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
napi_valuetype valuetype0;
napi_typeof(env, args[0], &valuetype0);
napi_valuetype valuetype1;
napi_typeof(env, args[1], &valuetype1);
double value0;
napi_get_value_double(env, args[0], &value0);
double value1;
napi_get_value_double(env, args[1], &value1);
napi_value sum;
napi_create_double(env, value0 + value1, &sum);
return sum;
}
NAPI的实现方法结构是固定的,返回值必须是napi_value,参数必须是两个napi_env与napi_callback_info,方法中解析napi_callback_info具体参数信息实现具体功能。
2.3 CMakelist.txt中配置编译的动态库名称与C++源码列表
add_library指定编译输出的库名称和参与编译的C++代码列表:
scss
add_library(entry SHARED napi_init.cpp)
这方面知识可以参考CMake构建工具相关文档:cmake.org/
2.4 ArkTS中调用声明的方法
最后,实现好后就可以在ArkTS中调用对应的方法:
csharp
//首先导入动态库:
import testNapi from 'libentry.so';
//调用对应add方法
hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.add(2, 3));
3、DevEco Studio 快速生成胶水代码
从上面ArkTS调用C++方法流程看流程还是有点繁琐,需要在两个文件三处地方做处理,有没有便捷的方法呢?别着急,接下来介绍今天的重头戏,DevEco Studio IDE 提供的跨语言代码编辑。
DevEco Studio IDE提供了两种创建方式:
- Index.d.ts中编写函数声明,一键生成C++函数
- C++头文件编写C++函数声明,一键生成注册代码
下面分别进行详细介绍。
3.1 Index.d.ts中编写函数声明,一键生成C++函数
在Index.d.ts中声明方法后,IDE会提示错误,鼠标悬停后会有下图提示:
点击"Generate native implementation"后即可快捷生成C++中的注册代码与实现代码:
这样三处手动实现变成了一处,功能还是非常实用,提效不止三分之二。
3.2 C++头文件编写C++函数声明,一键生成注册代码
通过C++函数声明一键创建的方式,需要我们先创建一个头文件,然后在头文件中声明方法:
右键该方法,点击生成:
继续点击NAPI:
注册函数中,以及对应NAPI函数实现已经帮助我们完成生成:
Index.d.ts中的声明方法也已经帮助我们生成:
通过IDE的版主,跨语言之间的"胶水"代码编写极大的提高了效率,不得不说,DevEco Studio 提供的这块功能还是相当不错的,很为广大程序员考虑。
这里面需要注意的有三点:
- 快捷生成代码的头文件支持类型:.hpp,.hxx,.hh,.h;
- 声明的快捷生成NAPI的函数当前支持bool,int,string,void,float,double,std::array,std::vector等参数类型;
- 如果工程中已经创建napi_init.cpp,则会在文件的Init中追加,如果没有创建,IDE会帮助我们自动创建。
4、借助AI提升C++代码中NAPI类型转换代码书写
有了IDE提供的自动生成跨语言胶水代码已经极大的帮助我们进行Native 代码开发,但是可能还有小伙伴感觉生成的TODO中的代码也很繁琐,很多ArkTS与C++的跨语言转换代码也很模版和繁琐,有没有对应的提效办法呢? 以自动生成的add代码为例:
ini
static napi_value Add(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
napi_valuetype valuetype0;
napi_typeof(env, args[0], &valuetype0);
napi_valuetype valuetype1;
napi_typeof(env, args[1], &valuetype1);
double value0;
napi_get_value_double(env, args[0], &value0);
double value1;
napi_get_value_double(env, args[1], &value1);
napi_value sum;
napi_create_double(env, value0 + value1, &sum);
return sum;
}
需要从napi_callback_info解析两个int类型参数,完成运算后还要继续生成napi_value返回。
因为这种跨语言数据类型转换时NAPI协议,DevEco CodeGenie插件也提供了不错的支持,可以在DevEco Studio 中安装Genie插件帮助我们生成快速生成C++实现代码:
这样,几次"TAB"键后就帮我们生成差不多了,再根据我们业务逻辑实现自己代码即可。
5、总结
本文主要介绍了Native C++代码的实现步骤,以及DevEco Studio IDE提供的跨语言代码编辑工具,实现只写函数声明一键帮助我们生成对应初始化注册方法与C++实现方法,希望大家多多体验,通过工具提升我们开发效率。