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