• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用JSVM进行class相关开发
2
3## 简介
4
5使用JSVM-API接口进行class相关开发,处理JavaScript中的类,例如定义类、构造实例等。
6
7## 基本概念
8
9在使用JSVM-API接口进行class相关开发时,需要理解以下基本概念:
10
11- **类**:类是用于创建对象的模板。它提供了一种封装数据和行为的方式,以便于对数据进行处理和操作。类在JavaScript中是建立在原型(prototype)的基础上的,并且还引入了一些类独有的语法和语义。
12- **实例**:实例是通过类创建具体的对象。类定义了对象的结构和行为,而实例则是类的具体表现。通过实例化类,我们可以访问类中定义的属性和方法,并且每个实例都具有自己的属性值。
13
14## 接口说明
15
16| 接口                | 功能说明                           |
17| ------------------- | ---------------------------------- |
18| OH_JSVM_NewInstance   | 通过给定的构造函数,构建一个实例|
19| OH_JSVM_GetNewTarget  | 获取构造函数调用的new.target|
20| OH_JSVM_DefineClass   | 用于在JavaScript中定义一个类,并与对应的C类进行封装和交互。它提供了创建类的构造函数、定义属性和方法的能力,以及在C和JavaScript之间进行数据交互的支持|
21| OH_JSVM_Wrap           | 在JavaScript对象中封装原生实例。稍后可以使用OH_JSVM_Unwrap()检索原生实例|
22| OH_JSVM_Unwrap         | 使用OH_JSVM_Wrap()检索先前封装在JavaScript对象中的原生实例|
23| OH_JSVM_RemoveWrap     | 检索先前封装在JavaScript对象中的原生实例并移除封装|
24
25## 使用示例
26
27JSVM-API接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md),本文仅对接口对应C++及ArkTS相关代码进行展示。
28
29### OH_JSVM_NewInstance
30
31通过给定的构造函数,构建一个实例。
32
33cpp部分代码
34
35```cpp
36// hello.cpp
37#include "napi/native_api.h"
38#include "ark_runtime/jsvm.h"
39#include <hilog/log.h>
40通过给定的构造函数,构建一个实例。
41// NewInstance注册回调
42static JSVM_CallbackStruct param[] = {
43    {.data = nullptr, .callback = NewInstance},
44};
45static JSVM_CallbackStruct *method = param;
46// NewInstance方法别名,供JS调用
47static JSVM_PropertyDescriptor descriptor[] = {
48    {"newInstance", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
49};
50// OH_JSVM_NewInstance的样例方法
51static JSVM_Value NewInstance(JSVM_Env env, JSVM_CallbackInfo info) {
52    // 获取js侧传入的两个参数
53    size_t argc = 2;
54    JSVM_Value args[2] = {nullptr};
55    OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr);
56    // 调用OH_JSVM_NewInstance接口,实例化一个对象,将这个对象返回
57    JSVM_Value result = nullptr;
58    JSVM_Status status = OH_JSVM_NewInstance(env, args[0], 1, &args[1], &result);
59    if (status != JSVM_OK) {
60        OH_LOG_ERROR(LOG_APP, "JSVM API TEST RESULT: PASS");
61    } else {
62        OH_LOG_INFO(LOG_APP, "JSVM API TEST RESULT: PASS");
63    }
64    return result;
65}
66```
67
68ArkTS侧示例代码
69
70```ts
71import hilog from '@ohos.hilog'
72// 通过import的方式,引入Native能力。
73import napitest from 'libentry.so'
74let script: string = `
75   function Fruit(name) {
76       this.name = name;
77   }
78   newInstance(Fruit, "apple");
79  `;
80try {
81  let result = napitest.runJsVm(script.toString());
82  hilog.info(0x0000, 'JSVM', 'NewInstance:%{public}s', result);
83} catch (error) {
84  hilog.error(0x0000, 'JSVM', 'NewInstance:%{public}s', error.message);
85}
86```
87
88### OH_JSVM_GetNewTarget
89
90用于获取构造函数的new.target值。在JavaScript中,new.target是一个特殊的元属性,用于在构造函数中判断是否通过new关键字调用了该构造函数。
91
92### OH_JSVM_DefineClass
93
94用于在JavaScript中定义一个类,并与对应的C类进行封装和交互。它提供了创建类的构造函数、定义属性和方法的能力,以及在C和JavaScript之间进行数据交互的支持
95
96cpp部分代码
97
98```cpp
99// hello.cpp
100#include "napi/native_api.h"
101#include "ark_runtime/jsvm.h"
102#include <hilog/log.h>
103// 自定义类结构体
104struct DefineObject {
105    std::string name;
106    int32_t age;
107    JSVM_Ref wrapper_;
108};
109static thread_local JSVM_Ref g_ref = nullptr;
110// 创建实例
111struct DefineObject *defineObject = new struct DefineObject();
112JSVM_Value New(JSVM_Env env, JSVM_CallbackInfo info) {
113    JSVM_Value newTarget;
114    OH_JSVM_GetNewTarget(env, info, &newTarget);
115    if (newTarget != nullptr) {
116        OH_LOG_INFO(LOG_APP, "NAPI MyObject::New newTarget != nullptr");
117        // 使用`new MyObject(...)`调用方式
118        size_t argc = 1;
119        JSVM_Value args[1];
120        JSVM_Value jsThis;
121        OH_JSVM_GetCbInfo(env, info, &argc, args, &jsThis, nullptr);
122        double value = 0.0;
123        JSVM_ValueType valuetype;
124        OH_JSVM_Typeof(env, args[0], &valuetype);
125        if (valuetype != JSVM_UNDEFINED) {
126            OH_JSVM_GetValueDouble(env, args[0], &value);
127        }
128        defineObject->name = "lilei";
129        defineObject->age = 18;
130        return nullptr;
131    } else {
132        OH_LOG_INFO(LOG_APP, "NAPI MyObject::New newTarget == nullptr");
133        size_t argc = 1;
134        JSVM_Value args[1];
135        (OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr));
136        JSVM_Value cons;
137        (OH_JSVM_GetReferenceValue(env, g_ref, &cons));
138        JSVM_Value instance;
139        (OH_JSVM_NewInstance(env, cons, argc, args, &instance));
140        return instance;
141    }
142}
143
144// 获取封装后的c++自定义结构中的数据方法
145napi_value GetObj(napi_env env) {
146    std::string str = "{\"name\": \"" + defineObject->name + "\",\"age\": " + std::to_string(defineObject->age) + "}";
147    napi_value jsResult;
148    napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &jsResult);
149    return jsResult;
150}
151
152// 封装c++中的自定义数据结构
153JSVM_Value DefineClass(JSVM_Env env, JSVM_Value exports) {
154    JSVM_CallbackStruct param1;
155    param1.data = nullptr;
156    param1.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value { return New(env, info); };
157    JSVM_Value cons;
158    OH_JSVM_DefineClass(env, "MyObject", JSVM_AUTO_LENGTH, &param1, 0, nullptr, &cons);
159    JSVM_Value instanceValue = nullptr;
160    OH_JSVM_NewInstance(env, cons, 0, nullptr, &instanceValue);
161    return nullptr;
162}
163```
164
165需要将[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md)中的RunJsVm方法改动如下:
166
167```cpp
168    // hello.cpp
169    // 将JSVM开发流程文档中defineClass方法的预留位置的代码更改为如下内容
170    if (strcmp(sourceCodeStr.c_str(), "defineClass") == 0) {
171        JSVM_Value obj;
172        DefineClass(env, obj);
173        nResult = GetObj(nEnv);
174    }
175```
176
177ArkTS侧示例代码
178
179```ts
180import hilog from '@ohos.hilog'
181// 通过import的方式,引入Native能力。
182import napitest from 'libentry.so'
183// test defineclass
184try {
185  let result = napitest.runJsVm("defineClass");
186  hilog.info(0x0000, 'testJSVM', 'Test JSVM defineclass:%{public}s', JSON.stringify(result));
187} catch (error) {
188  hilog.error(0x0000, 'testJSVM', 'Test JSVM AssertEqual error: %{public}s', error);
189}
190```
191
192### OH_JSVM_Wrap
193
194在JavaScript对象中封装原生实例。稍后可以使用OH_JSVM_Unwrap()检索原生实例
195
196### OH_JSVM_Unwrap
197
198使用OH_JSVM_Wrap()检索先前封装在JavaScript对象中的原生实例
199
200### OH_JSVM_RemoveWrap
201
202检索先前封装在JavaScript对象中的原生实例并移除封装
203
204cpp部分代码
205
206```cpp
207// hello.cpp
208#include "napi/native_api.h"
209#include "ark_runtime/jsvm.h"
210#include <hilog/log.h>
211// WrapObject、RemoveWrap注册回调
212static JSVM_CallbackStruct param[] = {
213    {.data = nullptr, .callback = WrapObject},
214    {.data = nullptr, .callback = RemoveWrap},
215};
216static JSVM_CallbackStruct *method = param;
217// WrapObject、RemoveWrap方法别名,供JS调用
218static JSVM_PropertyDescriptor descriptor[] = {
219    {"wrapObject", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
220    {"removeWrap", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}
221};
222// OH_JSVM_GetNewTarget、OH_JSVM_DefineClass、OH_JSVM_Wrap、OH_JSVM_Unwrap、OH_JSVM_RemoveWrap的样例方法
223// 表示是否调用了deref_item函数
224static bool deref_item_called = false;
225
226// 自定义类结构体Object
227struct Object {
228    std::string name;
229    int32_t age;
230};
231struct Object *obj = new struct Object();
232
233// 定义一个回调函数
234static void DerekItem(JSVM_Env env, void *data, void *hint) {
235    OH_LOG_INFO(LOG_APP, "JSVM deref_item");
236    (void)hint;
237}
238
239static JSVM_Value WrapObject(JSVM_Env env, JSVM_CallbackInfo info) {
240    OH_LOG_INFO(LOG_APP, "JSVM wrap");
241    // 设置Object属性
242    obj->name = "lilei";
243    obj->age = 18;
244    // 获取回调信息中的参数数量和将要被封装的值
245    size_t argc = 1;
246    JSVM_Value toWrap = nullptr;
247    OH_JSVM_GetCbInfo(env, info, &argc, &toWrap, nullptr, nullptr);
248    // 将自定义结构Object封装
249    OH_JSVM_Wrap(env, toWrap, reinterpret_cast<void *>(obj), DerekItem, NULL, NULL);
250    struct Object *data;
251    struct Object *data1;
252    OH_JSVM_Unwrap(env, toWrap, reinterpret_cast<void **>(&data));
253    OH_LOG_INFO(LOG_APP, "JSVM name: %{public}s", data->name.c_str());
254    OH_LOG_INFO(LOG_APP, "JSVM age: %{public}d", data->age);
255    //检索先前封装的object,并移除封装
256    OH_JSVM_RemoveWrap(env, toWrap, reinterpret_cast<void **>(&obj));
257    JSVM_Status status = OH_JSVM_Unwrap(env, toWrap, reinterpret_cast<void **>(&data1));
258    if (status != JSVM_OK) {
259        OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_RemoveWrap success");
260    }
261    JSVM_Value checked;
262    OH_JSVM_GetBoolean(env, true, &checked);
263    return checked;
264}
265
266static JSVM_Value RemoveWrap(JSVM_Env env, JSVM_CallbackInfo info) {
267    OH_LOG_INFO(LOG_APP, "JSVM removeWrap");
268    size_t argc = 1;
269    JSVM_Value wrapped = nullptr;
270    void *data;
271    OH_JSVM_GetCbInfo(env, info, &argc, &wrapped, nullptr, nullptr);
272    OH_JSVM_RemoveWrap(env, wrapped, &data);
273    return nullptr;
274}
275```
276
277ArkTS侧示例代码
278
279```ts
280import hilog from '@ohos.hilog'
281// 通过import的方式,引入Native能力。
282import napitest from 'libentry.so'
283// wrapObject
284class Obj {}
285let obj: Obj = `{}`;
286let script: string = `
287  wrapObject(${obj});
288  `;
289try {
290  let result = napitest.runJsVm(script);
291  hilog.info(0x0000, 'JSVM', 'WrapObject:%{public}s', result);
292} catch (error) {
293  hilog.error(0x0000, 'JSVM', 'WrapObject:%{public}s', error.message);
294}
295
296// removeWrap
297class Obj {}
298let obj: Obj = `{}`;
299let script: string = `
300  removeWrap(${obj});
301  `;
302try {
303  let result = napitest.runJsVm(script);
304  hilog.info(0x0000, 'JSVM', 'RemoveWrap:%{public}s', result);
305} catch (error) {
306  hilog.error(0x0000, 'JSVM', 'RemoveWrap:%{public}s', error.message);
307}
308```
309