赞
踩
公司内部已经有现成的MQTT动态库,想在HarmonyOS平台上共享使用。查找官方指导后,发现可以通过NAPI方式,将MQTT C++库导入进来,然后封装一层ArkTS接口就可直接使用。
本篇内容是在按照官方指导下,自己做的一些调研性质的实践。
阅读完成后
将学会如何在已有的HarmonyOS应用工程中完成C++文件的添加以及TS与C++的交互
希望大家不用碰到类似的项目需求
NAPI(Native API)组件是一套对外接口基于Node.js N-API规范开发的原生模块扩展开发框架
在HarmonyOS中,C API中的N-API接口可以实现ArkTS/TS/JS与C/C++之间的交互。N-API提供的接口名与三方Node.js一致,目前支持部分接口。
关于详细HarmonyOS 中的N-API开发教程,详见指导
功能演示
备注:以添加 源码 形式演示
简易目录结构
粉色为添加和改动部分
片段1
- # the minimum version of CMake.
- cmake_minimum_required(VERSION 3.4.1)
- project(HarmonyLearn)
-
- # 设置源码文件目录
- set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
-
- # 设置 .h 文件目录
- include_directories(${NATIVERENDER_ROOT_PATH}
- ${NATIVERENDER_ROOT_PATH}/include)
-
- # 设置自己的动态名称 和 对应的编译文件
- add_library(customnapi SHARED main.cpp
- sm4.cpp
- util.cpp)
-
- # 设置链接自己的动态库与其它动态库
- target_link_libraries(customnapi PUBLIC libace_napi.z.so)
entry模块中的build-profile.json5文件增加native选项【内容见 “片段2”】
- ...
-
- "buildOption": {
- "externalNativeOptions": {
- "path": "./src/main/cpp/CMakeLists.txt",
- "arguments": "",
- "cppFlags": "",
- },
-
- ...
- }
-
- ...
在需要使用到"customnapi"库的文件中,通过import方式来进行引用
注意 虽然我们自己定义的库名称为"customnapi", 但是引用的时候应该为"libcustomnapi.so", 注意是以"lib"为前缀
- import customnapi from 'libcustomnapi.so'
-
- ...
-
- customnapi.passStr(...)
- ...
经过这三步,即可完成C++源码在HarmonyOS应用工程中的添加使用
这个文件在本示例中用来注册C++源码模块使用的,文件名称可任意修改,因为其最终会被CMakeLists.txt文件引用,所以其文件名称无关紧要
这个文件主要分为四部分
so注册,即在ets文件被加载时,触发import动作,然后会通过系统机制自动执行 napi_module_register 代码
so模块说明,即对so 模块的描述,包含NAPI接口描述入口,so模块名称,版本等
so api注册, 即ets函数名称和NAPI 函数名称的映射关系。比如,ets中调用add,因为有这里的映射,所以执行的是C++文件中的Add函数。
C++函数定义,即so库对外暴露的接口实现,比如static napi_value Add(napi_env env, napi_callback_info info)
- ......
-
- static napi_value Add(napi_env env, napi_callback_info info) {
- ......
- }
-
- ......
-
- // Init将在exports上挂上Add/NativeCallArkTS这些native方法,此处的exports就是开发者import之后获取到的ArkTS对象。
-
- static napi_value Init(napi_env env, napi_value exports) {
-
- // 函数描述结构体,以Add为例,第三个参数"Add"为上述的native方法,
- // 第一个参数"add"为ArkTS侧对应方法的名称。
- napi_property_descriptor desc[] = {
- {"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
-
- ......
-
- return exports;
- }
-
- // 准备模块加载相关信息,将上述Init函数与本模块名等信息记录下来。
- static napi_module demoModule = {
- .nm_version = 1,
- .nm_flags = 0,
- .nm_filename = nullptr,
- .nm_register_func = Init,
- .nm_modname = "customnapi",
- .nm_priv = ((void *)0),
- .reserved = {0},
- };
-
- // 打开so时,该函数将自动被调用,使用上述demoModule模块信息,进行模块注册相关动作。
- extern "C" __attribute__((constructor)) void RegisterModule(void) {
- napi_module_register(&demoModule);
- }
例如:Add函数
- // 期望从ArkTS侧获取的参数的数量,napi_value可理解为ArkTS value在native方法中的表现形式。
- //TS函数有2个参数
- size_t argc = 2;
-
- //创建一个包含2个元素的TS参数值数组
- napi_value args[2] = {nullptr};
-
- // 从info中,拿到从ArkTS侧传递过来的参数,此处获取了两个ArkTS参数,即arg[0]和arg[1]。
- napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
-
- // 将获取的ArkTS参数转换为native信息,此处ArkTS侧传入了两个number,这里将其转换为native侧可以操作的double类型。
-
- //解析TS函数中的第一个参数
- double value0;
- //声明于 js_native_api.h 文件,属于HarmonyOS SDK里边的一部分
- napi_get_value_double(env, args[0], &value0);
-
- //解析TS函数中的第二个参数
- double value1;
- //声明于 js_native_api.h 文件,属于HarmonyOS SDK里边的一部分
- napi_get_value_double(env, args[1], &value1);
例如:passStr函数
- static napi_value passStr(napi_env env, napi_callback_info info) {
- //TS函数有1一个参数
- size_t argc = 1;
- //创建一个包含1个元素的TS参数值数组
- napi_value args[1] = {nullptr};
-
- // 从info中,拿到从ArkTS侧传递过来的参数,此处获取了一个ArkTS参数,即arg[0]。
- napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
-
- //获取字符串参数的长度
- size_t typeLen = 0;
- napi_get_value_string_utf8(env, args[0], nullptr, 0, &typeLen);
-
- //创建存储字符串的数组,数组大小为“字符串长度+1”, 1代表字符串结束符
- char *extContent = new char[typeLen + 1];
- //解析TS的字符串参数,将内容赋值到char数组中
- napi_get_value_string_utf8(env, args[0], extContent, typeLen + 1, &typeLen);
-
- napi_value result;
- //将字符串赋值给napi_value
- napi_create_string_utf8(env, extContent, typeLen + 1, &result);
-
- //释放数组空间
- delete[] extContent;
-
- //返回结果
- return result;
- }
例如:generatorMockArray函数
- static napi_value generatorMockArray(napi_env env, napi_callback_info info) {
- size_t argc = 1;
- napi_value args[1] = {nullptr};
-
- napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
-
- //解析TS参数值,这里的值代表需要初始化的数组容量
- int result;
- napi_get_value_int32(env, args[0], &result);
-
- napi_value ret;
- // 创建返回类型为数组的对象
- napi_create_array(env, &ret);
-
- const int arrayLength = 4;
- const char *target[arrayLength] = {"Blue", "Red", "Orange", "Yellow"};
-
- // 根据TS入参设置数组的初始值
- for (int i = 0; i < result && i < arrayLength; i++) {
- napi_value tempValue;
- //创建字符串类型的tempValue对象,把字符串赋值给tempValue
- napi_create_string_utf8(env, target[i], strlen(target[i]),&tempValue);
- // 数组中添加元素
- napi_set_element(env, ret, i, tempValue);
- }
-
- return ret;
- }
例如:getCustomObject函数
- /**
- * 获取mock对象
- *
- * 格式
- * {
- * "testNumber" : 123,
- * "testString" : "welcome",
- * "testNested" : { "child" : "welcome"}
- * }
- *
- * @param env
- * @param info
- * @return
- */
- static napi_value getCustomObject(napi_env env, napi_callback_info info) {
-
- //创建一个数字类型的对象: value_number
- napi_value value_number;
- napi_create_int32(env, 123, &value_number);
-
- //创建一个字符串类型的对象: value_string
- char *contentStr = "welcome";
-
- napi_value value_string;
- napi_create_string_utf8(env, contentStr, strlen(contentStr), &value_string);
-
- //创建一个Object类型的对象:childObj
- napi_value childObj;
- napi_create_object(env, &childObj);
- //childObj对象添加一个名为“child”的属性,其值为value_string
- napi_set_named_property(env, childObj, "child", value_string);
-
- //创建一个返回类型为Object的对象: obj
- napi_value obj;
- napi_create_object(env, &obj);
-
- //obj对象添加一个名为“testNumber”的属性,其值为value_number
- napi_set_named_property(env, obj, "testNumber", value_number);
-
- //obj对象添加一个名为“testString”的属性,其值为value_string
- napi_set_named_property(env, obj, "testString", value_string);
-
- //obj对象添加一个名为“testNested”的属性,其值为childObj
- napi_set_named_property(env, obj, "testNested", childObj);
-
- return obj;
- }
- # cmake 最小版本
- cmake_minimum_required(VERSION 3.4.1)
- # 工程名称:HarmonyLearn
- project(HarmonyLearn)
-
- # set命令,格式为set(key value),表示设置key的值为value,其中value可以是路径,也可以是许多文件。
- set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
-
- # 添加项目编译所需要的头文件的目录
- include_directories(${NATIVERENDER_ROOT_PATH}
- ${NATIVERENDER_ROOT_PATH}/include)
-
-
- # 生成目标库文件customnapi.so,customnapi表示最终的库名称,SHARED表示生成的是动态链接库,
- # main.cpp, sm4.cpp, util.cpp 表示最终生成的libcustomnapi.so中所包含的源码
- # 如果要生成静态链接库,把SHARED该成STATIC即可
- add_library(customnapi SHARED main.cpp
- sm4.cpp
- util.cpp)
- # 把libcustomnapi.so链接到libace_napi.z.so上
- target_link_libraries(customnapi PUBLIC libace_napi.z.so)
如果平时不太写C/C++的情况下,上手写NAPI,还是比较困难的,相当于HarmonyOS新手不知道如何展示一个文字一样。
而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点
如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。
高清完整版请点击→《鸿蒙NEXT星河版开发学习文档》
针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细资料鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。
《鸿蒙 (OpenHarmony)开发学习视频》
《鸿蒙生态应用开发V2.0白皮书》
《鸿蒙 (OpenHarmony)开发基础到实战手册》
获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
ArkTS语言
安装DevEco Studio
运用你的第一个ArkTS应用
ArkUI声明式UI开发
.……
《鸿蒙开发进阶》
Stage模型入门
网络管理
数据管理
电话服务
分布式应用开发
通知与窗口管理
多媒体技术
安全技能
任务管理
WebGL
国际化开发
应用测试
DFX面向未来设计
鸿蒙系统移植和裁剪定制
……
《鸿蒙开发实战》
ArkTS实践
UIAbility应用
网络案例
……
获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》
鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。
并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。