当前位置:   article > 正文

Openharmony应用NAPI详解--基础篇_openharmony napi

openharmony napi

NAPI是什么?

简单点理解就是在Openharmony里,实现上层js或ets应用与底层C/C++之间交互的框架。

Openharmony里的官方解释:NAPI(Native API)组件是一套对外接口基于Node.js N-API规范开发的原生模块扩展开发框架。还有NAPI适合封装IO、CPU密集型、OS底层等能力并对外暴露JS接口,通过NAPI可以实现JS与C/C++代码互相访问。我们可以通过NAPI接口构建例如网络通信、串口访问、多媒体解码、传感器数据收集等模块。

now,以Openharmon V3.1-Release版本为例,抽取代码实例,分为两部份进行分析。

面向上层js或ets接口

1.定义接口

接口描述文件在Openharmony里.d.ts后缀结束。

在分布式文件服务(//foundation/filemanagement/dfs_service)的@ohos.sendfile.d.ts文件中

  1. import {AsyncCallback, Callback} from "./basic";
  2. declare namespace SendFile {
  3. // 异步接口----回调方式
  4. function sendFile(deviceId: string, sourPath: Array<string>, destPath: Array<string>, fileCount: number, callback: AsyncCallback<number>);
  5. // 异步接口----Promise方式
  6. function sendFile(deviceId: string, sourPath: Array<string>, destPath: Array<string>, fileCount: number): Promise<number>;
  7. // 异步接口----回调方式
  8. function on(type: 'sendFinished' | 'receiveFinished', callback: AsyncCallback<TransResult>): void;
  9. // 同步接口
  10. function off(type: 'sendFinished' | 'receiveFinished'): void;
  11. }
  12. export default SendFile;

以上为应用开发者提供了四个的JS接口,分为同步接口与异步接口两类,异步接口又分为回调方式与Promise。

2.App应用开发者的JS代码简单导入一下模块就可以直接调用了。

  1. // 同步调用
  2. import myapp1 from "@ohos.SendFile"
  3. var result = myapp1.off(/* 参数自填*/);
  4. // 异步调用
  5. /** call back 方式的异步调用 */
  6. myapp1.sendFile("xxxx", sourPath, destPath, 4, function (err, ret) {
  7. ......
  8. });
  9. /** Promise 方式的异步调用 */
  10. var promiseObj = myapp1.sendFile("xxxx", sourPath, destPath, 4).then(data => {
  11. ......
  12. }).catch(error => {
  13. ......
  14. });

3.关于d.ts的注意事项

1.自定义d.ts接口文件时,在应用开发工具(DevEco Studio)里需要将此文件放入Openharmony sdk所在目录中,例如,在作者的本机为D:\Program\Huawei\OpenHarmony3.1\Sdk\ets\3.1.5.5\api与D:\Program\Huawei\OpenHarmony3.1\Sdk\js\3.1.5.5\api,根据应用调用者(js或ets)的不同放入不同的目录。

2.Openharmony已有d.ts接口文件,根据文件中注释里说的@since 9对应相应的导入sdk版本后,不需要另做导入dts。

面向C++的接口实现

1.模块注册与方法名映射

  1. // foundation/filemanagement/dfs_service/frameworks/js/napi/src/sendfile_napi.cpp
  2. napi_value SendFileExport(napi_env env, napi_value exports)
  3. {
  4. const char className[] = "SendFile";
  5. static napi_property_descriptor desc[] = {
  6. DECLARE_NAPI_FUNCTION("sendFile", JsSendFile),
  7. DECLARE_NAPI_FUNCTION("on", JsOn),
  8. DECLARE_NAPI_FUNCTION("off", JsOff),
  9. };
  10. napi_value sendFileClass = nullptr;
  11. napi_define_class(env, className, sizeof(className), JsConstructor, nullptr,
  12. sizeof(desc) / sizeof(desc[0]), desc, &sendFileClass);
  13. napi_set_named_property(env, exports, "SendFile", sendFileClass);
  14. SendFile::RegisterCallback();
  15. return exports;
  16. }
  17. // 模块注册
  18. NAPI_MODULE(sendfile, SendFileExport)
  • 通过NAPI_MODULE与DECLARE_NAPI_FUNCTION两个宏分别完成模块注册与方法名映射。

  • 这里dts定义了两个sendFile接口,为何只需要定义映射一个?

因为对js或ets来说sendFile对外接口名相同,在C++实现时根据传入的参数个数或者参数类型来判断js或ets调用哪个函数。

2.同步接口

根据映射,同步接口off对应C++的实现是JsOff。

  • 函数声明

每一个映射后的函数,必须是参数napi_env env, napi_callback_info cbinfo,返回值为napi_value。

  1. // foundation/filemanagement/dfs_service/frameworks/js/napi/src/sendfile_napi.cpp
  2. napi_value JsOff(napi_env env, napi_callback_info cbinfo)
  3. {
  4. ......
  5. }

为了实现js或ets调用,NAPI框架需要解决以下问题:数据传递与转换

js/ets传入的入参、得到的返回结果,需要转换成C/C++代码可以操作的数据类型,NAPI框架引入了一个中间的数据类型,来分别对应上层js/ets与C/C++的类型,以及数据类型的操作方法。

  • 获取入参

napi_get_cb_info从cbinfo参数中js传入参数,以下为函数说明

  1. // napi_get_cb_info从napi_callback_info类型的参数中得到回调的参数等数据
  2. napi_status napi_get_cb_info(
  3. napi_env env,
  4. napi_callback_info cbinfo, // 传入回调函数的回调信息
  5. size_t *argc, // 作为入参传入`argv`数组的大小,并将接收实际的参数个数
  6. napi_value *argv, // 存放参数的buffer
  7. napi_value *this_arg, // Javascript中的`this`
  8. void** data // 接收数据指针
  9. );

argc为传入参数个数,argv为传入参数数组,此时参数的类型都为napi_value。

通过napi_typeof方法获取入参的实际类型

  1. // napi_typeof获取指定对象的类型
  2. napi_status napi_typeof(
  3. napi_env env,
  4. napi_value value, // 将要获取类型的Javascript值
  5. napi_valuetype *result // Javascript值的类型
  6. );

根据d.ts的描述,off传入的只有一个参数,参数类型为字符串。

  1. // foundation/filemanagement/dfs_service/frameworks/js/napi/src/sendfile_napi.cpp
  2. napi_value JsOff(napi_env env, napi_callback_info cbinfo)
  3. {
  4. size_t requireArgc = 1;
  5. ...
  6. NAPI_ASSERT(env, argc == requireArgc, "requires 1 parameter"); //参数个数为1
  7. napi_valuetype eventValueType = napi_undefined;
  8. napi_typeof(env, argv[0], &eventValueType);
  9. NAPI_ASSERT(env, eventValueType == napi_string, "type mismatch for parameter 1");//参数类型为napi_string,即为NAPI中定义一种字符串
  10. ...
  11. }
  • 类型转换为C/C++可识别的类型

napi_get_value_string_utf8方法将napi_string转换char*

  1. napi_status napi_get_value_string_utf8(napi_env env,
  2. napi_value value,
  3. char* buf,
  4. size_t bufsize,
  5. size_t* result);
  1. // foundation/filemanagement/dfs_service/frameworks/js/napi/src/sendfile_napi.cpp
  2. napi_value JsOff(napi_env env, napi_callback_info cbinfo)
  3. {
  4. ...
  5. char* type = nullptr;
  6. size_t typeLen = 0;
  7. napi_get_value_string_utf8(env, argv[0], nullptr, 0, &typeLen);
  8. NAPI_ASSERT(env, typeLen > 0, "typeLen == 0");
  9. type = new char[typeLen + 1];
  10. napi_get_value_string_utf8(env, argv[0], type, typeLen + 1, &typeLen);
  11. ...
  12. }
  • 返回值

C++没有返回值,此时JsOff将nullptr返回。

NAPI框架没有nullptr,通过napi_get_undefined将nullptr转换成napi_undefined。

  1. napi_value JsOff(napi_env env, napi_callback_info cbinfo)
  2. {
  3. ...
  4. napi_value result = nullptr;
  5. napi_get_undefined(env, &result);
  6. return result;
  7. }

后续更精彩

1.Openharmony应用NAPI详解--进阶篇

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/92024
推荐阅读