arkui_napi:基于Node.js N-API规范的原生模块扩展开发框架

暂无描述

分支320Tags57
文件最后提交记录最后更新时间
11 个月前
2 年前
2 天前
3 年前
1 天前
18 天前
4 天前
1 年前
17 天前
2 年前
3 天前
6 个月前
2 年前
5 年前
2 天前
17 天前
5 年前
3 年前
3 年前
3 年前
1 个月前
1 个月前
8 个月前

NAPI组件

简介

NAPI(原生应用编程接口)组件是基于Node.js N-API规范开发的原生模块扩展框架,提供标准化接口支持。

图 1 NAPI组件架构图

  • NativeEngine

    JavaScript引擎抽象层,统一不同JS引擎在NAPI层的接口行为规范。

  • ModuleManager

    模块管理中心,负责模块加载与元数据缓存管理。

  • ScopeManager

    原生值生命周期管理模块。

  • ReferenceManager

    原生引用生命周期管理模块。

目录

NAPI组件源代码位于/foundation/arkui/napi目录下,结构如下所示:

foundation/arkui/napi
   ├── interfaces
   │   └── kits
   │       └── napi           # NAPI头文件目录
   ├── module_manager         # 模块管理
   ├── native_engine          # NativeEngine抽象层
   │   └── impl
   │       └── ark            # 基于Ark的NativeEngine实现
   ├── scope_manager          # 作用域管理
   └── test                   # 测试目录

Usage Scenarios

NAPI is suitable for encapsulating capabilities such as I/O, CPU-intensive tasks, and OS-level functionalities, exposing them as JavaScript interfaces. Through NAPI, bidirectional access between JavaScript and C/C++ code can be achieved. It enables the development of modules like network communication, serial port access, multimedia decoding, and sensor data collection.

Interface Description

For interface implementation details, refer to: foundation/arkui/napi.

Table 1 NAPI Interface Description

Interface Category

Description

Module Registration

Interfaces for registering module information with module management.

Exception & Error Handling

Throwing exceptions to JavaScript.

Object Lifecycle Management

Scope management, used to define the lifecycle of NAPI objects within a specific scope.

Creating JS Objects

Creating standard object types.

C to NAPI Type Conversion

Type conversion from C to NAPI.

NAPI to C Type Conversion

Type conversion from NAPI to C.

Functions for Obtaining Global Instances

Obtaining global instances.

JS Value Operations

NAPI interfaces for operators such as ===, typeof, and instanceof.

JS Object Property Operations

Function set for manipulating object properties.

JS Function Operations

Method invocation and instance creation.

Object Encapsulation

Binding external context relationships for JS objects.

Simple Asynchronous

Creating asynchronous tasks.

Promise

Function set for creating promise objects.

Script Execution

Executing JS code.

Development Steps

The following example demonstrates how to use NAPI by developing a JS interface to retrieve an application's package name.

The JS interface prototype we aim to implement is:

function getAppName(): string;

Here is the implementation source code:

// 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;
    // 创建promise
    NAPI_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);
}

Implementation of the corresponding build script:

// 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"
}

JavaScript Test Code in the Application:

import app from '@ohos.app'
export default {
  testGetAppName() {
    app.getAppName().then(function (data) {
      console.info('app name: ' + data);
    });
  }
}

ArkUI Framework Subsystem

arkui_ace_engine

arkui_ace_engine_lite

arkui_napi