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