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