• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用JSVM-API实现JS与C/C++语言交互开发流程
2<!--Kit: NDK Development-->
3<!--Subsystem: arkcompiler-->
4<!--Owner: @yuanxiaogou; @string_sz-->
5<!--Designer: @knightaoko-->
6<!--Tester: @test_lzz-->
7<!--Adviser: @fang-jinxu-->
8
9使用JSVM-API实现跨语言交互,首先需按其机制注册和加载模块。
10
11- ArkTS/JS侧:实现C++方法的调用。代码比较简单,import一个对应的so库后,即可调用C++方法。
12
13- Native侧:.cpp文件,实现模块的注册。需要提供注册lib库的名称,并在注册回调方法中定义接口的映射关系,即Native方法及对应的JS/ArkTS接口名称等。
14
15此处以在ArkTS/JS侧和Native侧实现RunJsVm()接口实现跨语言交互为例,展示使用JSVM-API进行跨语言交互的流程。
16
17## 创建Native C++工程
18
19具体见[创建NDK工程](create-with-ndk.md)
20
21## Native侧方法的实现
22
23参考[使用Node-API实现跨语言交互开发流程](use-napi-process.md#native侧方法的实现),以下代码提供了“使用JSVM-API实现JS与C/C++语言交互开发流程”Native侧方法实现的一个demo。
24
25- 在index.d.ts文件中,提供JS侧的接口方法。
26
27  ```ts
28  // entry/src/main/cpp/types/libentry/index.d.ts
29  export const runTest: () => void;
30  ```
31  <!-- @[export_native](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/JSVMAPI/JsvmProcess/entry/src/main/cpp/types/libentry/Index.d.ts) -->
32
33- 在oh-package.json5文件中将index.d.ts与cpp文件关联起来。
34
35  ```json
36  {
37    "name": "libentry.so",
38    "types": "./index.d.ts",
39    "version": "",
40    "description": "Please describe the basic information."
41  }
42  ```
43
44- 在CMakeLists.txt文件中配置CMake打包参数。
45
46  ```text
47  # entry/src/main/cpp/CMakeLists.txt
48  cmake_minimum_required(VERSION 3.4.1)
49  project(JSVMDemo)
50
51  set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
52  # 日志打印配置
53  add_definitions( "-DLOG_DOMAIN=0xd0d0" )
54  add_definitions( "-DLOG_TAG=\"testTag\"" )
55  include_directories(${NATIVERENDER_ROOT_PATH}
56                      ${NATIVERENDER_ROOT_PATH}/include)
57
58  # 添加名为entry的库
59  add_library(entry SHARED hello.cpp)
60  # 构建此可执行文件需要链接的库
61  target_link_libraries(entry PUBLIC libace_napi.z.so libjsvm.so libhilog_ndk.z.so)
62  ```
63
64- 新建entry/src/main/cpp/hello.cpp,实现Native侧的runTest接口。具体代码如下:
65
66  ```cpp
67  // entry/src/main/cpp/hello.cpp
68  #include "napi/native_api.h"
69  #include "hilog/log.h"
70  #include "ark_runtime/jsvm.h"
71
72  #define LOG_DOMAIN 0x3200
73  #define LOG_TAG "APP"
74
75  static int g_aa = 0;
76
77  #define CHECK_RET(theCall)                                                                                             \
78      do {                                                                                                               \
79          JSVM_Status cond = theCall;                                                                                    \
80          if ((cond) != JSVM_OK) {                                                                                       \
81              const JSVM_ExtendedErrorInfo *info;                                                                        \
82              OH_JSVM_GetLastErrorInfo(env, &info);                                                                      \
83              OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d message = %{public}s", \
84                           __FILE__, __LINE__, cond, info != nullptr ? info->errorMessage : "");                         \
85              return -1;                                                                                                 \
86          }                                                                                                              \
87      } while (0)
88
89  #define CHECK(theCall)                                                                                                 \
90      do {                                                                                                               \
91          JSVM_Status cond = theCall;                                                                                    \
92          if ((cond) != JSVM_OK) {                                                                                       \
93              OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d", __FILE__, __LINE__,  \
94                           cond);                                                                                        \
95              return -1;                                                                                                 \
96          }                                                                                                              \
97      } while (0)
98
99  // 用于调用theCall并检查其返回值是否为JSVM_OK。
100  // 如果不是,则调用OH_JSVM_GetLastErrorInfo处理错误并返回retVal。
101  #define JSVM_CALL_BASE(env, theCall, retVal)                                                                           \
102      do {                                                                                                               \
103          JSVM_Status cond = theCall;                                                                                    \
104          if (cond != JSVM_OK) {                                                                                         \
105              const JSVM_ExtendedErrorInfo *info;                                                                        \
106              OH_JSVM_GetLastErrorInfo(env, &info);                                                                      \
107              OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d message = %{public}s", \
108                           __FILE__, __LINE__, cond, info != nullptr ? info->errorMessage : "");                         \
109              return retVal;                                                                                             \
110          }                                                                                                              \
111      } while (0)
112
113  // JSVM_CALL_BASE的简化版本,返回nullptr
114  #define JSVM_CALL(theCall) JSVM_CALL_BASE(env, theCall, nullptr)
115
116  // OH_JSVM_StrictEquals的样例方法
117  static JSVM_Value IsStrictEquals(JSVM_Env env, JSVM_CallbackInfo info) {
118      // 接受两个入参
119      size_t argc = 2;
120      JSVM_Value args[2] = {nullptr};
121      JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr));
122      // 调用OH_JSVM_StrictEquals接口判断给定的两个JavaScript value是否严格相等
123      bool result = false;
124      JSVM_Status status = OH_JSVM_StrictEquals(env, args[0], args[1], &result);
125      if (status != JSVM_OK) {
126          OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_StrictEquals: failed");
127      } else {
128          OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_StrictEquals: success: %{public}d", result);
129      }
130      JSVM_Value isStrictEqual;
131      JSVM_CALL(OH_JSVM_GetBoolean(env, result, &isStrictEqual));
132      return isStrictEqual;
133  }
134  // IsStrictEquals注册回调
135  static JSVM_CallbackStruct param[] = {
136      {.data = nullptr, .callback = IsStrictEquals},
137  };
138  static JSVM_CallbackStruct *method = param;
139  // IsStrictEquals方法别名,供JS调用
140  static JSVM_PropertyDescriptor descriptor[] = {
141      {"isStrictEquals", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
142  };
143  // 样例测试js
144  const char *srcCallNative = R"JS(    let data = '123';
145      let value = 123;
146      isStrictEquals(data,value);)JS";
147
148  static int32_t TestJSVM() {
149      JSVM_InitOptions initOptions = {0};
150      JSVM_VM vm;
151      JSVM_Env env = nullptr;
152      JSVM_VMScope vmScope;
153      JSVM_EnvScope envScope;
154      JSVM_HandleScope handleScope;
155      JSVM_Value result;
156      // 初始化JavaScript引擎实例
157      if (g_aa == 0) {
158          g_aa++;
159         CHECK(OH_JSVM_Init(&initOptions));
160      }
161      // 创建JSVM环境
162      CHECK(OH_JSVM_CreateVM(nullptr, &vm));
163      CHECK(OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env));
164      CHECK(OH_JSVM_OpenVMScope(vm, &vmScope));
165      CHECK_RET(OH_JSVM_OpenEnvScope(env, &envScope));
166      CHECK_RET(OH_JSVM_OpenHandleScope(env, &handleScope));
167
168      // 通过script调用测试函数
169      JSVM_Script script;
170      JSVM_Value jsSrc;
171      CHECK_RET(OH_JSVM_CreateStringUtf8(env, srcCallNative, JSVM_AUTO_LENGTH, &jsSrc));
172      CHECK_RET(OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script));
173      CHECK_RET(OH_JSVM_RunScript(env, script, &result));
174
175      // 销毁JSVM环境
176      CHECK_RET(OH_JSVM_CloseHandleScope(env, handleScope));
177      CHECK_RET(OH_JSVM_CloseEnvScope(env, envScope));
178      CHECK(OH_JSVM_CloseVMScope(vm, vmScope));
179      CHECK(OH_JSVM_DestroyEnv(env));
180      CHECK(OH_JSVM_DestroyVM(vm));
181      return 0;
182  }
183
184  static napi_value RunTest(napi_env env, napi_callback_info info)
185  {
186      TestJSVM();
187      return nullptr;
188  }
189
190  // 模块初始化
191  EXTERN_C_START
192  static napi_value Init(napi_env env, napi_value exports) {
193      // 实现ArkTS接口与C++接口的绑定和映射
194      napi_property_descriptor desc[] = {
195        {"runTest", nullptr, RunTest, nullptr, nullptr, nullptr, napi_default, nullptr}
196      };
197      // 在exports对象上挂载RunJsVm的Native方法
198      napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
199      return exports;
200  }
201  EXTERN_C_END
202
203  static napi_module demoModule = {
204      .nm_version = 1,
205      .nm_flags = 0,
206      .nm_filename = nullptr,
207      .nm_register_func = Init,
208      .nm_modname = "entry",
209      .nm_priv = ((void *)0),
210      .reserved = {0},
211  };
212
213  extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
214  ```
215  <!-- @[oh_jsvm_process](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/JSVMAPI/JsvmProcess/entry/src/main/cpp/hello.cpp) -->
216
217## ArkTS侧调用C/C++方法实现
218
219```ts
220import hilog from '@ohos.hilog';
221// 通过import的方式,引入Native能力。
222import napitest from 'libentry.so';
223
224@Entry
225@Component
226struct Index {
227  @State message: string = 'Hello World';
228
229  build() {
230    Row() {
231      Column() {
232        Text(this.message)
233          .fontSize(50)
234          .fontWeight(FontWeight.Bold)
235          .onClick(() => {
236            // runtest
237            napitest.runTest();
238          })
239      }
240      .width('100%')
241    }
242    .height('100%')
243  }
244}
245```
246<!-- @[call_native_cpp](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/JSVMAPI/JsvmProcess/entry/src/main/ets/pages/Index.ets) -->
247
248预期输出结果
249```ts
250JSVM OH_JSVM_StrictEquals: success: 0
251```