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 Create 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 {"runJsVm", nullptr, RunJsVm, 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 API. 43 44 ```ts 45 // entry/src/main/cpp/types/libentry/index.d.ts 46 export const runJsVm: (jsCode: string) => 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 RunJsVm function. The code is as follows: 81 82 ```cpp 83 // entry/src/main/cpp/hello.cpp 84 #include "napi/native_api.h" 85 #include "ark_runtime/jsvm.h" 86 #include <sys/stat.h> 87 #include <thread> 88 #include <unistd.h> 89 #include <bits/alltypes.h> 90 #include <hilog/log.h> 91 static int g_aa = 0; 92 static JSVM_Value Assert(JSVM_Env env, JSVM_CallbackInfo info) 93 { 94 size_t argc = 2; 95 JSVM_Value args[2] = {nullptr}; 96 OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr); 97 bool isStrictEquals; 98 if (argc > 1) { 99 OH_JSVM_StrictEquals(env, args[0], args[1], &isStrictEquals); 100 } else { 101 JSVM_Value valTrue; 102 OH_JSVM_GetBoolean(env, true, &valTrue); 103 OH_JSVM_StrictEquals(env, args[0], valTrue, &isStrictEquals); 104 } 105 if (isStrictEquals) { 106 OH_LOG_INFO(LOG_APP, "JSVM API TEST RESULT: PASS"); 107 } else { 108 OH_LOG_ERROR(LOG_APP, "JSVM API TEST RESULT: FAILED"); 109 } 110 JSVM_Value result; 111 OH_JSVM_GetBoolean(env, isStrictEquals, &result); 112 return result; 113 } 114 115 // Allow the JS environment to call the native Assert function through the asset property. 116 static JSVM_CallbackStruct param[] = { 117 {.data = nullptr, .callback = Assert}, 118 }; 119 static JSVM_CallbackStruct *method = param; 120 // Alias of the Assert function to be called by the TS. 121 static JSVM_PropertyDescriptor descriptor[] = { 122 {"assert", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 123 }; 124 125 // Obtain the JS code string. 126 static std::string getCodeString(napi_env nEnv, napi_callback_info nInfo) { 127 size_t argc = 1; 128 napi_value argv[1] = {nullptr}; 129 napi_get_cb_info(nEnv, nInfo, &argc, argv, nullptr, nullptr); 130 std::string jsCodeStr; 131 size_t result = 0; 132 napi_get_value_string_utf8(nEnv, argv[0], nullptr, NAPI_AUTO_LENGTH, &result); 133 const size_t bufSize = result + 1; 134 char *buf = new char[bufSize]; 135 napi_status status = napi_get_value_string_utf8(nEnv, argv[0], buf, bufSize, &result); 136 if (status == napi_ok) { 137 jsCodeStr = buf; 138 } 139 free(buf); 140 return jsCodeStr; 141 } 142 143 // Process logic when the JS code fails to be executed. 144 void RunScriptFail(napi_env &nEnv, JSVM_Env &env, JSVM_Status &res) { 145 JSVM_Value exceptionValue; 146 JSVM_Status status = OH_JSVM_GetAndClearLastException(env, &exceptionValue); 147 if (status == JSVM_OK) { 148 JSVM_Value message; 149 OH_JSVM_GetNamedProperty(env, exceptionValue, "message", &message); 150 size_t length; 151 OH_JSVM_GetValueStringUtf8(env, message, nullptr, 0, &length); 152 char *buffer = new char[length + 1]; 153 OH_JSVM_GetValueStringUtf8(env, message, buffer, length + 1, nullptr); 154 napi_throw_error(nEnv, std::to_string(static_cast<int>(status)).c_str(), buffer); 155 delete[] buffer; 156 } else { 157 napi_throw_error(nEnv, std::to_string(static_cast<int>(status)).c_str(), nullptr); 158 OH_LOG_INFO(LOG_APP, "JSVM RunJsVm failed Error code: %{public}d", static_cast<int>(res)); 159 } 160 } 161 // Create a JSVM to run JS code to obtain JSVM_Value. 162 static napi_value RunJsVm(napi_env nEnv, napi_callback_info nInfo) { 163 std::string jsCodeStr = getCodeString(nEnv, nInfo); 164 JSVM_InitOptions initOptions; 165 memset(&initOptions, 0, sizeof(initOptions)); 166 // Set the initialization options for the JSVM. 167 initOptions.externalReferences = nullptr; 168 if (g_aa == 0) { 169 g_aa++; 170 // Initialize the JSVM instance. 171 OH_JSVM_Init(&initOptions); 172 } 173 JSVM_VM vm; 174 JSVM_CreateVMOptions options; 175 memset(&options, 0, sizeof(options)); 176 // Create a JSVM instance. 177 OH_JSVM_CreateVM(&options, &vm); 178 JSVM_VMScope vmScope; 179 // Open a VM scope. The VM instance can be used only within the scope and will not be garbage-collected until the scope is closed. 180 OH_JSVM_OpenVMScope(vm, &vmScope); 181 JSVM_Env env; 182 // Create a JS context and registers the specified native function. 183 JSVM_Status res = OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env); 184 if (res != JSVM_OK) { 185 OH_LOG_INFO(LOG_APP, "JSVM API OH_JSVM_CreateEnv failed res is %{public}d", static_cast<int>(res)); 186 } 187 JSVM_EnvScope envScope; 188 // Open a JS context scope. The context can be used only within the scope. 189 OH_JSVM_OpenEnvScope(env, &envScope); 190 JSVM_HandleScope handleScope; 191 // Open a handle scope. 192 OH_JSVM_OpenHandleScope(env, &handleScope); 193 std::string sourceCodeStr = jsCodeStr; 194 napi_value nResult = nullptr; 195 JSVM_Value jsVmResult; 196 OH_LOG_INFO(LOG_APP, "JSVM API RunJsVm %{public}s", sourceCodeStr.c_str()); 197 // Determine whether to call the JSVM API based on the JS code string passed in. 198 if (strcmp(sourceCodeStr.c_str(), "defineClass") == 0) { 199 // DefineClass is reserved. 200 OH_LOG_INFO(LOG_APP, "JSVM API DefineClass called"); 201 } else { 202 JSVM_Value sourceCodeValue = nullptr; 203 OH_JSVM_CreateStringUtf8(env, sourceCodeStr.c_str(), sourceCodeStr.size(), &sourceCodeValue); 204 JSVM_Script script; 205 // Compile the JS code string and return the compiled script. 206 OH_JSVM_CompileScript(env, sourceCodeValue, nullptr, 0, true, nullptr, &script); 207 // Execute the JS script. 208 res = OH_JSVM_RunScript(env, script, &jsVmResult); 209 if (res != JSVM_OK) { 210 RunScriptFail(nEnv, env, res); 211 napi_get_boolean(nEnv, false, &nResult); 212 } else { 213 napi_get_boolean(nEnv, true, &nResult); 214 } 215 } 216 // Close the handle scope. 217 OH_JSVM_CloseHandleScope(env, handleScope); 218 // Close the JS context scope. 219 OH_JSVM_CloseEnvScope(env, envScope); 220 // Close the VM scope. 221 OH_JSVM_CloseVMScope(vm, vmScope); 222 // Destroys the JS context. 223 OH_JSVM_DestroyEnv(env); 224 // Destroy the JSVM instance. 225 OH_JSVM_DestroyVM(vm); 226 return nResult; 227 } 228 ``` 229 230## Calling C/C++ APIs from ArkTS 231 232```ts 233import hilog from '@ohos.hilog' 234// Import the native APIs. 235import napitest from 'libentry.so' 236// Test assert. 237try { 238 let data = false; 239 let script: string = `assert(${data});`; 240 let result = napitest.runJsVm(script); 241 hilog.info(0x0000, 'testJSVM', 'Test JSVM Assert:%{public}s', result); 242} catch (error) { 243 hilog.error(0x0000, 'testJSVM', 'Test JSVM Assert error: %{public}s', error); 244} 245``` 246