1# JSVM-API Development Process
2
3To implement cross-language interaction using JSVM-API, you need to register and load modules based on the JSVM-API mechanism first.
4
5- ArkTS/JS: Import the .so library and call C++ APIs.
6
7- 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 callback registered.
8
9The following demonstrates how to implement cross-language interaction by implementing **RunJsVm()** in ArkTS/JS code and **RunJsVm()** in native code.
10
11## Creating a Native C++ Project
12
13For details, see [Creating an NDK Project](create-with-ndk.md).
14
15## Implementing Native APIs
16
17- Set module registration information.
18
19  For details, see [Setting Module Registration Information](use-napi-process.md#implementing-native-apis).
20
21- Initialize the module.
22
23  Implement the mappings between the ArkTS and C++ APIs.
24
25  ```cpp
26  // entry/src/main/cpp/hello.cpp
27  EXTERN_C_START
28  // Initialize the module.
29  static napi_value Init(napi_env env, napi_value exports)
30  {
31      // Implement the mappings between the ArkTS runJsVm and C++ RunJsVm.
32      napi_property_descriptor desc[] = {
33          {"runTest", nullptr, RunTest, nullptr, nullptr, nullptr, napi_default, nullptr},
34      };
35      // Register the native RunJsVm function with the JS exports object, making the native function available to JS.
36      napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
37      return exports;
38  }
39  EXTERN_C_END
40  ```
41
42- In the **index.d.ts** file, declare the JS methods.
43
44  ```ts
45  // entry/src/main/cpp/types/libentry/index.d.ts
46  export const runTest: () => void;
47  ```
48
49- Associate **index.d.ts** with **.cpp** in the **oh-package.json5** file.
50
51  ```json
52  {
53    "name": "libentry.so",
54    "types": "./index.d.ts",
55    "version": "",
56    "description": "Please describe the basic information."
57  }
58  ```
59
60- Set CMake packaging parameters in the **CMakeLists.txt** file.
61
62  ```text
63  # entry/src/main/cpp/CMakeLists.txt
64  cmake_minimum_required(VERSION 3.4.1)
65  project(JSVMDemo)
66
67  set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
68  # Set logging information.
69  add_definitions( "-DLOG_DOMAIN=0xd0d0" )
70  add_definitions( "-DLOG_TAG=\"testTag\"" )
71  include_directories(${NATIVERENDER_ROOT_PATH}
72                      ${NATIVERENDER_ROOT_PATH}/include)
73
74  # Add a shared library named entry from the source file hello.cpp.
75  add_library(entry SHARED hello.cpp)
76  # Link the entry library with the specified shared libraries.
77  target_link_libraries(entry PUBLIC libace_napi.z.so libjsvm.so libhilog_ndk.z.so)
78  ```
79
80- Implement the native runTest function. The code is as follows:
81
82  ```cpp
83  #include "napi/native_api.h"
84  #include "hilog/log.h"
85  #include "ark_runtime/jsvm.h"
86
87  #define LOG_DOMAIN 0x3200
88  #define LOG_TAG "APP"
89
90  static int g_aa = 0;
91
92  #define CHECK_RET(theCall)                                                                                             \
93      do {                                                                                                               \
94          JSVM_Status cond = theCall;                                                                                    \
95          if ((cond) != JSVM_OK) {                                                                                       \
96              const JSVM_ExtendedErrorInfo *info;                                                                        \
97              OH_JSVM_GetLastErrorInfo(env, &info);                                                                      \
98              OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d message = %{public}s", \
99                           __FILE__, __LINE__, cond, info != nullptr ? info->errorMessage : "");                         \
100              return -1;                                                                                                 \
101          }                                                                                                              \
102      } while (0)
103
104  #define CHECK(theCall)                                                                                                 \
105      do {                                                                                                               \
106          JSVM_Status cond = theCall;                                                                                    \
107          if ((cond) != JSVM_OK) {                                                                                       \
108              OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d", __FILE__, __LINE__,  \
109                           cond);                                                                                        \
110              return -1;                                                                                                 \
111          }                                                                                                              \
112      } while (0)
113
114  // Call theCall and check whether the return value is JSVM_OK.
115  // If not, call OH_JSVM_GetLastErrorInfo to handle the error and return retVal.
116  #define JSVM_CALL_BASE(env, theCall, retVal)                                                                           \
117      do {                                                                                                               \
118          JSVM_Status cond = theCall;                                                                                    \
119          if (cond != JSVM_OK) {                                                                                         \
120              const JSVM_ExtendedErrorInfo *info;                                                                        \
121              OH_JSVM_GetLastErrorInfo(env, &info);                                                                      \
122              OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d message = %{public}s", \
123                           __FILE__, __LINE__, cond, info != nullptr ? info->errorMessage : "");                         \
124              return retVal;                                                                                             \
125          }                                                                                                              \
126      } while (0)
127
128  // Simplified version of JSVM_CALL_BASE, which returns nullptr.
129  #define JSVM_CALL(theCall) JSVM_CALL_BASE(env, theCall, nullptr)
130
131  // Define OH_JSVM_StrictEquals.
132  static JSVM_Value IsStrictEquals(JSVM_Env env, JSVM_CallbackInfo info) {
133      // Obtain the two parameters passed from JS.
134      size_t argc = 2;
135      JSVM_Value args[2] = {nullptr};
136      JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr));
137      // Call OH_JSVM_StrictEquals to check whether two given JS values are strictly equal.
138      bool result = false;
139      JSVM_Status status = OH_JSVM_StrictEquals(env, args[0], args[1], &result);
140      if (status != JSVM_OK) {
141          OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_StrictEquals: failed");
142      } else {
143          OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_StrictEquals: success: %{public}d", result);
144      }
145      JSVM_Value isStrictEqual;
146      JSVM_CALL(OH_JSVM_GetBoolean(env, result, &isStrictEqual));
147      return isStrictEqual;
148  }
149  // Register the IsStrictEquals callback.
150  static JSVM_CallbackStruct param[] = {
151      {.data = nullptr, .callback = IsStrictEquals},
152  };
153  static JSVM_CallbackStruct *method = param;
154  // Set a property descriptor named isStrictEquals and associate it with a callback. This allows the isStrictEquals callback to be called from JS.
155  static JSVM_PropertyDescriptor descriptor[] = {
156      {"isStrictEquals", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
157  };
158  // Call the C++ code from JS.
159  const char *srcCallNative = R"JS(    let data = '123';
160      let value = 123;
161      isStrictEquals(data,value);)JS";
162
163  static int32_t TestJSVM() {
164      JSVM_InitOptions initOptions = {0};
165      JSVM_VM vm;
166      JSVM_Env env = nullptr;
167      JSVM_VMScope vmScope;
168      JSVM_EnvScope envScope;
169      JSVM_HandleScope handleScope;
170      JSVM_Value result;
171      // Initialize the JSVM instance.
172      if (g_aa == 0) {
173          g_aa++;
174         CHECK(OH_JSVM_Init(&initOptions));
175      }
176      // Create a JSVM environment.
177      CHECK(OH_JSVM_CreateVM(nullptr, &vm));
178      CHECK(OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env));
179      CHECK(OH_JSVM_OpenVMScope(vm, &vmScope));
180      CHECK_RET(OH_JSVM_OpenEnvScope(env, &envScope));
181      CHECK_RET(OH_JSVM_OpenHandleScope(env, &handleScope));
182
183      // Call the test function through the script.
184      JSVM_Script script;
185      JSVM_Value jsSrc;
186      CHECK_RET(OH_JSVM_CreateStringUtf8(env, srcCallNative, JSVM_AUTO_LENGTH, &jsSrc));
187      CHECK_RET(OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script));
188      CHECK_RET(OH_JSVM_RunScript(env, script, &result));
189
190      // Destroy the JSVM environment.
191      CHECK_RET(OH_JSVM_CloseHandleScope(env, handleScope));
192      CHECK_RET(OH_JSVM_CloseEnvScope(env, envScope));
193      CHECK(OH_JSVM_CloseVMScope(vm, vmScope));
194      CHECK(OH_JSVM_DestroyEnv(env));
195      CHECK(OH_JSVM_DestroyVM(vm));
196      return 0;
197  }
198
199  static napi_value RunTest(napi_env env, napi_callback_info info)
200  {
201      TestJSVM();
202      return nullptr;
203  }
204
205  // Module registration information, which enables calling from the ArkTS side.
206  EXTERN_C_START
207  static napi_value Init(napi_env env, napi_value exports) {
208  napi_property_descriptor desc[] = {{"runTest", nullptr, RunTest, nullptr, nullptr, nullptr, napi_default, nullptr}};
209  napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
210  return exports;
211  }
212  EXTERN_C_END
213
214  static napi_module demoModule = {
215  .nm_version = 1,
216  .nm_flags = 0,
217  .nm_filename = nullptr,
218  .nm_register_func = Init,
219  .nm_modname = "entry",
220  .nm_priv = ((void *)0),
221  .reserved = {0},
222  };
223
224  extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
225  ```
226
227## Calling C/C++ APIs in ArkTS
228
229```ts
230import hilog from '@ohos.hilog'
231// Import the native APIs.
232import napitest from 'libentry.so'
233
234@Entry
235@Component
236struct Index {
237  @State message: string = 'Hello World';
238
239  build() {
240    Row() {
241      Column() {
242        Text(this.message)
243          .fontSize(50)
244          .fontWeight(FontWeight.Bold)
245          .onClick(() => {
246            // runtest
247            napitest.runTest();
248          })
249      }
250      .width('100%')
251    }
252    .height('100%')
253  }
254}
255```
256
257**Expected output**
258```ts
259JSVM OH_JSVM_StrictEquals: success: 1
260```
261