HarmonyOS实战开发:NAPI接口规范开发
简介
NAPI(Native API)组件是一套对外接口基于Node.js N-API规范开发的原生模块扩展开发框架。
-
NativeEngine
JS引擎抽象层,统一JS引擎在NAPI层的接口行为。
-
ModuleManager
管理模块,用于模块加载、模块信息缓存。
-
ScopeManager
管理NativeValue的生命周期。
-
ReferenceManager
管理NativeReference的生命周期。
目录
NAPI组件源代码在/foundation/arkui/napi下,目录结构如下图所示:
foundation/arkui/napi├── interfaces│ └── kits│ └── napi # NAPI头文件目录├── module_manager # 模块管理├── native_engine # NativeEngine抽象层│ └── impl│ └── ark # 基于Ark的NativeEngine实现├── scope_manager # 作用域管理└── test # 测试目录
使用场景
NAPI适合封装IO、CPU密集型、OS底层等能力并对外暴露JS接口,通过NAPI可以实现JS与C/C++代码互相访问。我们可以通过NAPI接口构建例如网络通信、串口访问、多媒体解码、传感器数据收集等模块。
接口说明
接口实现详见:foundation/arkui/napi。
表 1 NAPI接口说明
接口分类 | |
---|---|
模块注册 | |
异常&错误处理 | |
对象生命周期管理 | |
创建JS对象 | |
C类型转NAPI类型 | |
NAPI类型转C类型 | |
获取全局实例的函数 | |
JS值的操作 | |
JS对象的属性操作 | |
JS函数的操作 | |
对象封装 | |
简单异步 | |
promise | |
脚本运行 |
开发步骤
下面以开发一个获取应用包名的JS接口为例介绍如何使用NAPI。
我们要实现的JS接口原型是:
function getAppName(): string;
以下是实现源码:
// app.cpp
#include <stdio.h>
#include <string.h>
#include "napi/native_api.h"
#include "napi/native_node_api.h"struct AsyncCallbackInfo {napi_env env;napi_async_work asyncWork;napi_deferred deferred;
};// getAppName对应的C/C++实现函数
napi_value JSGetAppName(napi_env env, napi_callback_info info) {napi_deferred deferred;napi_value promise;// 创建promiseNAPI_CALL(env, napi_create_promise(env, &deferred, &promise));AsyncCallbackInfo* asyncCallbackInfo = new AsyncCallbackInfo {.env = env,.asyncWork = nullptr,.deferred = deferred,};napi_value resourceName;napi_create_string_latin1(env, "GetAppName", NAPI_AUTO_LENGTH, &resourceName);// 创建异步任务队列napi_create_async_work(env, nullptr, resourceName,// 异步任务的回调[](napi_env env, void* data) {},// 异步任务结束后的回调[](napi_env env, napi_status status, void* data) {AsyncCallbackInfo* asyncCallbackInfo = (AsyncCallbackInfo*)data;napi_value appName;const char* str = "com.example.helloworld";napi_create_string_utf8(env, str, strlen(str), &appName);// 触发回调napi_resolve_deferred(asyncCallbackInfo->env, asyncCallbackInfo->deferred, appName);napi_delete_async_work(env, asyncCallbackInfo->asyncWork);delete asyncCallbackInfo;},(void*)asyncCallbackInfo, &asyncCallbackInfo->asyncWork);napi_queue_async_work(env, asyncCallbackInfo->asyncWork);return promise;
}// 模块导出入口函数
static napi_value AppExport(napi_env env, napi_value exports)
{static napi_property_descriptor desc[] = {DECLARE_NAPI_FUNCTION("getAppName", JSGetAppName),};NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));return exports;
}// app模块描述
static napi_module appModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = AppExport,.nm_modname = "app",.nm_priv = ((void*)0),.reserved = {0}
};// 注册模块
extern "C" __attribute__((constructor)) void AppRegister()
{napi_module_register(&appModule);
}
对应编译脚本的实现:
// BUILD.gn
import("//build/ohos.gni")
ohos_shared_library("app") {# 指定编译源文件sources = ["app.cpp",]# 指定编译依赖deps = [ "//foundation/arkui/napi:ace_napi" ]# 指定库生成的路径relative_install_dir = "module"subsystem_name = "arkui"part_name = "napi"
}
应用中的JS测试代码:
import app from '@ohos.app'
export default {testGetAppName() {app.getAppName().then(function (data) {console.info('app name: ' + data);});}
}