#星计划# OpenHarmony NAPI技术简介 原创

中软小助手
发布于 2024-1-8 10:59
浏览
2收藏

作者:廖家兴

简介

NAPI(Native API)是OpenHarmony系统中的一套原生模块扩展开发框架,它基于Node.js N-API规范开发,为开发者提供了JavaScript与C/C++模块之间相互调用的交互能力。可以在NodeJs官网查看各种NAPI接口定义说明。

NAPI作用

  • OpenHarmony系统可以将框架层丰富的模块功能通过js接口开放给上层应用使用
  • 上层应用也可以将一些对性能有要求或者需要调用到系统侧框架的功能使用C/C++封装实现,下探到系统层以提高运行效率

NAPI在系统中的位置

NAPI在OpenHarmony中属于ArkUI框架的一部分
NAIP框架代码在 foundation\arkui\napi\ 路径下。总体上可分为interface、native_engine 和 xxxManager 三部分。

interface 目录为NAPI开发者提供了各种常用功能的API接口及宏定义。

native_engine 目录是NAPI框架的核心部分,interface目录提供的接口对应的功能都在这里实现。C++与Js之间的调用交互最终是要依托JS引擎来完成的,针对系统支持的不同JS引擎,在impl目录中也有对应的4种实现(ark, jerryscript, quickjs, v8)。

此外,还有几个Manager目录,分别负责模块注册、引用对象管理、作用域管理等专项功能。

NAPI使用

假设我们在框架测使用c/c++实现了hello模块,该模块提供了一个接口int hello(const std::string &s),传入一个字符串,打印该字符串。

要使用js调用到如上hello接口,需要解决如下几个问题

  1. 模块注册(import的模块名称hello,是怎么对应到实际的c++lib库的?) — Module Manager。

  2. 方法名映射(js调用的hello方法,是怎么对应到native的C/C++的方法的?) — Native Engine。

  3. 数据传递与转换(js传入的入参、得到的返回结果,需要转换成C/C++代码可以操作的数据类型)

c++方法具体实现:

// hello.h

#ifndef HELLO_H
#define HELLO_H

#include <string>
namespace OHOS {
namespace hello {

int hello(const std::string &s);

} // namespace add
} // namespace OHOS

#endif // HELLO_H
// hello.cpp

#include <iostream>
#include "hello.h"

namespace OHOS {
namespace hello {

int hello(const std::string &s);
{
    std::cout << s << endl;
    return 0;
}

} // namespace add
} // namespace OHOS

此时需要为js提供调用,需要为该接口进行NAPI封装

// helloNapi.cpp

#include "napi/native_api.h"
#include "hello.h"

static napi_value Hello(napi_env env, napi_callback_info info)
{
    // 根据环境变量获取参数

    // js参数个数
    size_t argc = 1;
    // 参数定义
    napi_value argv[1] = { 0 };
    // 入参变量获取
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    // 获取入参的类型
    napi_valuetype valueType = napi_undefined;
    napi_typeof(env, argv[0], &valueType);
    // js类型的入参值转换为C/C++可以操作的数据类型
    char value[VALUE_BUFFER_SIZE] = { 0 };
    size_t valueLen = 0;
    napi_get_value_string_utf8(env, argv[0], value, VALUE_BUFFER_SIZE, &valueLen);
    std::string s = value;

    // 调用hello接口
    int ret = hello(s);

    // C/C++数据类型转换为JS数据类型并返回给应用层
    // JS字符串对象
    napi_value result = nullptr;
    retult = napi_create_int32(env, ret, &result);

    //返回JS对象
    return result;
}

// 方法名映射
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "hello", nullptr, Hello, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END


// nm_modname为提供给应用侧调用的模块名称
static napi_module helloModule = {
    .nm_version =1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "hello",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

// 注册模块
extern "C" __attribute__((constructor)) void RegisterNative_helloModule(void)
{
    napi_module_register(&helloModule);
}

编译生成假设为hello.z.so

js调用代码

// hello.ets

// 引入hello napi模块
import testNapi from '@ohos.hello'

// 调用js接口 hello
testNapi.hello("hello world")

以上就是简单的NAPI简介以及简单的一个NAPI应用开发模版。

更多原创内容请关注:中软国际 HarmonyOS 技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
收藏 2
回复
举报
回复
    相关推荐