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