1e41f4b71Sopenharmony_ci# Node-API Development Process
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ciTo implement cross-language interaction using Node-API, you need to register and load modules based on the Node-API mechanism first.
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ci- ArkTS/JS: Import the .so library and call C++ APIs.  
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci- Native: Implement module registration via a .cpp file. You need to declare the name of the library to register and define the mappings between the native and JS/ArkTS APIs in the callbacks registered.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci
12e41f4b71Sopenharmony_ciThe following demonstrates how to implement cross-language interaction by implementing **add()** in ArkTS/JS code and **Add()** in native code.
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci## Creating a Native C++ Project
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci- In DevEco Studio, choose **New** > **Create Project**, select the **Native C++** template, click **Next**, select the API version, set the project name, and click **Finish**.
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci- The main code of the project created consists of two parts: **cpp** and **ets**. For details about the project structure, see <!--RP1-->[C++ Project Directory Structure](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-project-structure-0000001546098578-V5#section181711599584)<!--RP1End-->.
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ci## Implementing Native APIs
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ci- Set module registration information.
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci  When a native module is imported in ArkTS, the .so file will be loaded. During the loading process, the **napi_module_register** method is called to register the module with the system and call the module initialization function.
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci  napi_module has two key attributes: **.nm_register_func** and **.nm_modname**. **.nm_register_func** defines the module initialization function, and **.nm_modname** defines the module name, that is, the name of the .so file imported by ArkTS.
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci  ```
31e41f4b71Sopenharmony_ci  // entry/src/main/cpp/hello.cpp
32e41f4b71Sopenharmony_ci  
33e41f4b71Sopenharmony_ci  // Information about the module. Record information such as the Init() function and module name.
34e41f4b71Sopenharmony_ci  static napi_module demoModule = {
35e41f4b71Sopenharmony_ci      .nm_version = 1,
36e41f4b71Sopenharmony_ci      .nm_flags = 0,
37e41f4b71Sopenharmony_ci      .nm_filename = nullptr,
38e41f4b71Sopenharmony_ci      .nm_register_func = Init,
39e41f4b71Sopenharmony_ci      .nm_modname = "entry",
40e41f4b71Sopenharmony_ci      .nm_priv = nullptr,
41e41f4b71Sopenharmony_ci      .reserved = {0},
42e41f4b71Sopenharmony_ci  };
43e41f4b71Sopenharmony_ci  
44e41f4b71Sopenharmony_ci  // When the .so file is loaded, this function is automatically called to register the demoModule module with the system.
45e41f4b71Sopenharmony_ci  extern "C" __attribute__((constructor)) void RegisterDemoModule() { 
46e41f4b71Sopenharmony_ci      napi_module_register(&demoModule);
47e41f4b71Sopenharmony_ci   }
48e41f4b71Sopenharmony_ci  ```
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ci- Initialize the module.
51e41f4b71Sopenharmony_ci
52e41f4b71Sopenharmony_ci  Implement the mappings between the ArkTS and C++ APIs.
53e41f4b71Sopenharmony_ci
54e41f4b71Sopenharmony_ci  ```
55e41f4b71Sopenharmony_ci  // entry/src/main/cpp/hello.cpp
56e41f4b71Sopenharmony_ci  EXTERN_C_START
57e41f4b71Sopenharmony_ci  // Initialize the module.
58e41f4b71Sopenharmony_ci  static napi_value Init(napi_env env, napi_value exports) {
59e41f4b71Sopenharmony_ci      // Implement the mappings between the ArkTS and C++ APIs.
60e41f4b71Sopenharmony_ci      napi_property_descriptor desc[] = {
61e41f4b71Sopenharmony_ci          {"callNative", nullptr, CallNative, nullptr, nullptr, nullptr, napi_default, nullptr},
62e41f4b71Sopenharmony_ci          {"nativeCallArkTS", nullptr, NativeCallArkTS, nullptr, nullptr, nullptr, napi_default, nullptr},
63e41f4b71Sopenharmony_ci      };
64e41f4b71Sopenharmony_ci      // Hook the CallNative and NativeCallArkTS APIs to the exports object.
65e41f4b71Sopenharmony_ci      napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
66e41f4b71Sopenharmony_ci      return exports;
67e41f4b71Sopenharmony_ci  }
68e41f4b71Sopenharmony_ci  EXTERN_C_END
69e41f4b71Sopenharmony_ci  
70e41f4b71Sopenharmony_ci  // Basic module information.
71e41f4b71Sopenharmony_ci  static napi_module demoModule = {
72e41f4b71Sopenharmony_ci      .nm_version = 1,
73e41f4b71Sopenharmony_ci      .nm_flags = 0,
74e41f4b71Sopenharmony_ci      .nm_filename = nullptr,
75e41f4b71Sopenharmony_ci      .nm_register_func = Init,
76e41f4b71Sopenharmony_ci      .nm_modname = "entry",
77e41f4b71Sopenharmony_ci      .nm_priv = nullptr,
78e41f4b71Sopenharmony_ci      .reserved = {0},
79e41f4b71Sopenharmony_ci  };
80e41f4b71Sopenharmony_ci  ```
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci- Add JS APIs in the index.d.ts file.
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ci  ```
85e41f4b71Sopenharmony_ci  // entry/src/main/cpp/types/libentry/index.d.ts
86e41f4b71Sopenharmony_ci  export const callNative: (a: number, b: number) => number;
87e41f4b71Sopenharmony_ci  export const nativeCallArkTS: (cb: (a: number) => number) => number;
88e41f4b71Sopenharmony_ci  ```
89e41f4b71Sopenharmony_ci
90e41f4b71Sopenharmony_ci- Associate **index.d.ts** with **.cpp** in the **oh-package.json5** file.
91e41f4b71Sopenharmony_ci
92e41f4b71Sopenharmony_ci  ```
93e41f4b71Sopenharmony_ci  {
94e41f4b71Sopenharmony_ci    "name": "libentry.so",
95e41f4b71Sopenharmony_ci    "types": "./index.d.ts",
96e41f4b71Sopenharmony_ci    "version": "",
97e41f4b71Sopenharmony_ci    "description": "Please describe the basic information."
98e41f4b71Sopenharmony_ci  }
99e41f4b71Sopenharmony_ci  ```
100e41f4b71Sopenharmony_ci
101e41f4b71Sopenharmony_ci- Set CMake packaging parameters in the **CMakeLists.txt** file.
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci  ```
104e41f4b71Sopenharmony_ci  # entry/src/main/cpp/CMakeLists.txt
105e41f4b71Sopenharmony_ci  cmake_minimum_required(VERSION 3.4.1)
106e41f4b71Sopenharmony_ci  project(MyApplication2)
107e41f4b71Sopenharmony_ci  
108e41f4b71Sopenharmony_ci  set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
109e41f4b71Sopenharmony_ci  
110e41f4b71Sopenharmony_ci  include_directories(${NATIVERENDER_ROOT_PATH}
111e41f4b71Sopenharmony_ci                      ${NATIVERENDER_ROOT_PATH}/include)
112e41f4b71Sopenharmony_ci  
113e41f4b71Sopenharmony_ci  # Add a library named entry.
114e41f4b71Sopenharmony_ci  add_library(entry SHARED hello.cpp)
115e41f4b71Sopenharmony_ci  # Build the library to be linked to this executable.
116e41f4b71Sopenharmony_ci  target_link_libraries(entry PUBLIC libace_napi.z.so)
117e41f4b71Sopenharmony_ci  ```
118e41f4b71Sopenharmony_ci
119e41f4b71Sopenharmony_ci- Implement **CallNative** and **NativeCallArkTS**. The code is as follows:
120e41f4b71Sopenharmony_ci
121e41f4b71Sopenharmony_ci  ```
122e41f4b71Sopenharmony_ci  // entry/src/main/cpp/hello.cpp
123e41f4b71Sopenharmony_ci  static napi_value CallNative(napi_env env, napi_callback_info info)
124e41f4b71Sopenharmony_ci  {
125e41f4b71Sopenharmony_ci      size_t argc = 2;
126e41f4b71Sopenharmony_ci      // Declare the parameter array.
127e41f4b71Sopenharmony_ci      napi_value args[2] = {nullptr};
128e41f4b71Sopenharmony_ci  
129e41f4b71Sopenharmony_ci      // Obtain input parameters and put them into the parameter array in sequence.
130e41f4b71Sopenharmony_ci      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
131e41f4b71Sopenharmony_ci  
132e41f4b71Sopenharmony_ci      // Obtain the parameters in sequence.
133e41f4b71Sopenharmony_ci      double value0;
134e41f4b71Sopenharmony_ci      napi_get_value_double(env, args[0], &value0);
135e41f4b71Sopenharmony_ci      double value1;
136e41f4b71Sopenharmony_ci      napi_get_value_double(env, args[1], &value1);
137e41f4b71Sopenharmony_ci  
138e41f4b71Sopenharmony_ci      // Return the sum of the two numbers.
139e41f4b71Sopenharmony_ci      napi_value sum;
140e41f4b71Sopenharmony_ci      napi_create_double(env, value0 + value1, &sum);
141e41f4b71Sopenharmony_ci      return sum;
142e41f4b71Sopenharmony_ci  }
143e41f4b71Sopenharmony_ci  
144e41f4b71Sopenharmony_ci  static napi_value NativeCallArkTS(napi_env env, napi_callback_info info)
145e41f4b71Sopenharmony_ci  {    
146e41f4b71Sopenharmony_ci      size_t argc = 1;
147e41f4b71Sopenharmony_ci      // Declare the parameter array.
148e41f4b71Sopenharmony_ci      napi_value args[1] = {nullptr};
149e41f4b71Sopenharmony_ci  
150e41f4b71Sopenharmony_ci      // Obtain input parameters and put them into the parameter array in sequence.
151e41f4b71Sopenharmony_ci      napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
152e41f4b71Sopenharmony_ci  
153e41f4b71Sopenharmony_ci      // Create an int() as the input parameter of ArkTS.
154e41f4b71Sopenharmony_ci      napi_value argv = nullptr;    
155e41f4b71Sopenharmony_ci      napi_create_int32(env, 2, &argv );
156e41f4b71Sopenharmony_ci  
157e41f4b71Sopenharmony_ci      // Invoke the callback that is passed in, and return the result.
158e41f4b71Sopenharmony_ci      napi_value result = nullptr;
159e41f4b71Sopenharmony_ci      napi_call_function(env, nullptr, args[0], 1, &argv, &result);
160e41f4b71Sopenharmony_ci      return result;
161e41f4b71Sopenharmony_ci  }
162e41f4b71Sopenharmony_ci  ```
163e41f4b71Sopenharmony_ci
164e41f4b71Sopenharmony_ci
165e41f4b71Sopenharmony_ci## Calling C/C++ APIs on ArkTS
166e41f4b71Sopenharmony_ci
167e41f4b71Sopenharmony_ciOn ArkTS, import the .so file that contains the processing logic on the native side to use C/C++ APIs.
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ci```
170e41f4b71Sopenharmony_ci// entry/src/main/ets/pages/Index.ets
171e41f4b71Sopenharmony_ci// Import the native APIs.
172e41f4b71Sopenharmony_ciimport nativeModule from 'libentry.so'
173e41f4b71Sopenharmony_ci
174e41f4b71Sopenharmony_ci@Entry
175e41f4b71Sopenharmony_ci@Component
176e41f4b71Sopenharmony_cistruct Index {
177e41f4b71Sopenharmony_ci  @State message: string = 'Test Node-API callNative result: ';
178e41f4b71Sopenharmony_ci  @State message2: string = 'Test Node-API nativeCallArkTS result: ';
179e41f4b71Sopenharmony_ci  build() {
180e41f4b71Sopenharmony_ci    Row() {
181e41f4b71Sopenharmony_ci      Column() {
182e41f4b71Sopenharmony_ci        // Pressing the first button calls add(), which uses CallNative() in the native code to add the two numbers.
183e41f4b71Sopenharmony_ci        Text(this.message)
184e41f4b71Sopenharmony_ci          .fontSize(50)
185e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
186e41f4b71Sopenharmony_ci          .onClick(() => {
187e41f4b71Sopenharmony_ci            this.message += nativeModule.callNative(2, 3);
188e41f4b71Sopenharmony_ci            })
189e41f4b71Sopenharmony_ci        // Pressing the second button calls nativeCallArkTS, which corresponds to NativeCallArkTS in the native code. The ArkTS function is called on the native side.
190e41f4b71Sopenharmony_ci        Text(this.message2)
191e41f4b71Sopenharmony_ci          .fontSize(50)
192e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
193e41f4b71Sopenharmony_ci          .onClick(() => {
194e41f4b71Sopenharmony_ci            this.message2 += nativeModule.nativeCallArkTS((a: number)=> {
195e41f4b71Sopenharmony_ci                return a * 2;
196e41f4b71Sopenharmony_ci            });
197e41f4b71Sopenharmony_ci          })
198e41f4b71Sopenharmony_ci      }
199e41f4b71Sopenharmony_ci      .width('100%')
200e41f4b71Sopenharmony_ci    }
201e41f4b71Sopenharmony_ci    .height('100%')
202e41f4b71Sopenharmony_ci  }
203e41f4b71Sopenharmony_ci}
204e41f4b71Sopenharmony_ci```
205e41f4b71Sopenharmony_ci
206e41f4b71Sopenharmony_ci
207e41f4b71Sopenharmony_ci## Node-API Constraints
208e41f4b71Sopenharmony_ci
209e41f4b71Sopenharmony_ci
210e41f4b71Sopenharmony_ci### Naming Rules of .so Files
211e41f4b71Sopenharmony_ci
212e41f4b71Sopenharmony_ciThe case of the module name to import must be the same as that registered. For example, if the module name is **entry**, the .so file name must be **libentry.so**, and the **nm_modname** field in **napi_module** must be **entry**. When importing the module in ArkTS, use **import xxx from 'libentry.so'**.
213e41f4b71Sopenharmony_ci
214e41f4b71Sopenharmony_ci
215e41f4b71Sopenharmony_ci### Registration
216e41f4b71Sopenharmony_ci
217e41f4b71Sopenharmony_ci- To prevent conflicts with symbols in the .so file, add **static** to the function corresponding to **nm_register_func**. For example, the **Init()** function in this document.
218e41f4b71Sopenharmony_ci
219e41f4b71Sopenharmony_ci- The name of the module registration entry, that is, the function modified by **__attribute__((constructor))** must be unique. For example, the **RegisterDemoModule** function in this document.
220e41f4b71Sopenharmony_ci
221e41f4b71Sopenharmony_ci
222e41f4b71Sopenharmony_ci### Multithread Processing
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ciEach engine instance corresponds to a JS thread. The objects of an instance cannot be operated across threads. Otherwise, the application crashes. Observe the following rules:
225e41f4b71Sopenharmony_ci
226e41f4b71Sopenharmony_ci- The Node-API can be used only by JS threads.
227e41f4b71Sopenharmony_ci
228e41f4b71Sopenharmony_ci- The input parameter **env** of a native API can be bound to a JS thread only when the thread is created.
229