Skip to content

Development framework for extending the JS Native Module | 原生模块扩展开发框架

License

Notifications You must be signed in to change notification settings

openharmony/arkui_napi

Repository files navigation

NAPI

Introduction

The foundation/arkui/napi repository contains a development framework for extending the JS Native Module and provides APIs developed based on Node.js N-API for external use.

Figure 1 Architecture

  • NativeEngine

    NativeEngine is the JS engine abstraction layer. It unifies API behavior of the JS engines at the NAPI layer.

  • ModuleManager

    ModuleManager is used to load modules and cache module information.

  • ScopeManager

    ScopeManager manages the NativeValue lifecycle.

  • ReferenceManager

    ReferenceManager manages the NativeReference lifecycle.

Directory Structure

The source code directory structure of this repository is as follows:

foundation/arkui/napi
   ├── interfaces
   │   └── kits
   │       └── napi           # NAPI header files
   ├── module_manager         # Module manager
   ├── native_engine          # NativeEngine abstraction layer
   │   └── impl
   │       └── ark            # Ark-based NativeEngine implementation
   ├── scope_manager          # Scope manager
   └── test                   # Test code

When to Use

NAPI is suitable for processing I/O- and CPU-intensive tasks and system tasks. It encapsulates the capabilities and provides them to apps as JS APIs. NAPI can be used to implement mutual access between JS and C/C++ code. You can use NAPI to develop modules such as network communications, serial port access, multimedia decoding, and sensor data collection.

Available APIs

For details about the API implementation, see the foundation/arkui/napi repository.

Table 1 Available NAPIs

Category

Description

Module registration

Registers module information with a manager.

Exception & Error handling

Throws exceptions.

Object lifecycle

Manages NAPI object lifecycle within limited scopes.

JS object

Creates standard object types.

C-to-NAPI

Converts data types from C to NAPI.

NAPI-to-C

Converts data types from NAPI to C.

Global instance

Obtains global instances.

JS value

Provides APIs executing ===, typeof, instanceof, and other operations alike.

JS object property

Provides functions for performing operations on object properties.

JS function

Invokes functions and creates instances.

Object encapsulation

Binds the external context of JS objects.

Simple asynchronization

Creates asynchronous tasks.

Promise

Creates a function set for a promise.

Script

Runs JS code.

How to Develop

The following example describes how to use NAPI to develop a JS API for obtaining the application bundle name.

The prototype of the JS API is as follows:

function getAppName(): string;

The implementation code of the JS API is as follows:

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

// C/C++ function corresponding to getAppName()
napi_value JSGetAppName(napi_env env, napi_callback_info info) {
    napi_deferred deferred;
    napi_value promise;
    // Create a 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);
    // Create a queue of asynchronous tasks.
    napi_create_async_work(
        env, nullptr, resourceName,
        // Callback for an asynchronous task
        [](napi_env env, void* data) {},
        // Callback after the asynchronous task is complete
        [](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);
            // Trigger the callback.
            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;
}

// Export the module.
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 module description
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}
};

// Register the module.
extern "C" __attribute__((constructor)) void AppRegister()
{
    napi_module_register(&appModule);
}

The build script is as follows:

// BUILD.gn
import("//build/ohos.gni")
ohos_shared_library("app") {
  # Specify the source file to build.
  sources = [
    "app.cpp",
  ]
  # Specify build dependencies.
  deps = [ "//foundation/arkui/napi:ace_napi" ]
  # Specify the directory where the library is generated.
  relative_install_dir = "module"
  subsystem_name = "arkui"
  part_name = "napi"
}

Test code to run in your app is as follows:

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

Repositories Involved

ArkUI framework

arkui_ace_engine

arkui_ace_engine_lite

arkui_napi

About

Development framework for extending the JS Native Module | 原生模块扩展开发框架

Resources

License

Stars

Watchers

Forks

Packages

No packages published