1# Native生成工具使用说明
2
3## 准备
4
5### 依赖
6
7系统:建议Windows 10
8
9开发工具:DevEco Studio
10
11## 生成框架
12
13### 创建工程
14
151.打开 DevEco Studio:
16
17选择Create Project -> Application -> Native C++ ,然后点击Next,将Project name修改为cJsonSampleTest,点击Finish,则工程创建成功。
18
19![image-20240508095733751](../figures/DevEco_create_new_project.png)
20
21![image-20240508095757468](../figures/DevEco_create_new_project_finish.png)
22
23### 导入三方库
24
25将待转换的三方库导入工程中,如将cJSON三方库导入工程:
26
271.cJSON三方库获取:[测试用三方库](https://gitee.com/openharmony/napi_generator/releases/tag/测试用资源)  选择cJSON.zip下载
28
29![image-20240508100218813](../figures/download_thirdparty.png)
30
312.将三方库导入工程:将cJSON.zip解压,解压后可以拷贝内容进  cJsonSampleTest\entry\src\main\cpp\thirdparty 和 cJsonSampleTest\entry\libs 下
32
33![image-20240508100502230](../figures/DevEco_import_libs.png)
34
35同时将arm64-v8a/lib下的所有.so文件拷贝一份至arm64-v8a下,将armeabi-v7a/lib下的所有.so文件拷贝一份至armeabi-v7a下。
36
373.将libcjson加入编译:在CMakeLists.txtcJsonSampleTest/entry/src/main/cpp/CMakeLists.txt)中加入libcjson路径
38
39```
40set(CJSON_LIB_PATH ${NATIVERENDER_ROOT_PATH}/../../../libs/${OHOS_ARCH})
41```
42
43在target_link_libraries中加入hilog和libcjson.so:
44
45```
46libhilog_ndk.z.so
47```
48
49```
50${CJSON_LIB_PATH}/libcjson.so
51```
52
53![image-20240508100005194](../figures/DevEco_add_thirdparty_lib.png)
54
554.修改编译选项:在cJsonSampleTest/entry/build-profile.json5文件中buildOption中增加abiFilters字段, 并将targets字段的runtimeOS改为OpenHarmony
56
57```
58"abiFilters": [
59        "arm64-v8a",
60        "armeabi-v7a"
61      ]
62```
63
64```
65"runtimeOS": "OpenHarmony"
66```
67
68![image-20240508100544906](../figures/DevEco_add_buildOption.png)
69
70### 使用nativetool生成框架
71
72#### 准备
73
74##### 1.在本地新建文件夹nativetoolGen
75
76##### **2.下载native_gen-win.exe**, header_parser.exe
77
78下载  native_gen-win.exe 可执行程序和 header_parser.exe 可执行程序:[下载生成工具 ](https://gitee.com/openharmony/napi_generator/releases/tag/生成工具) ;选择 tool.rar下载并解压,将解压后的文件拷贝到nativetoolGen目录下
79
80![image-20240508143053083](../figures/DevEco_Download_exe.png)
81
82#### 使用命令行生成框架
83
84##### 1.运行可执行文件
85
861.1将待转换的.h文件放到nativetoolGen目录下,例如:将cJSON.h文件放入nativetoolGen目录下(cJSON.h可从导入的三方库下的include文件夹中获取)
87
88![image-20240508143053083](../figures/DevEco_add_hFile.png)
89
901.2在命令行使用 以下命令运行脚本
91
92```
93native_gen-win.exe -f 接口文件路径 -o 生成路径
94```
95
96其中,参数详情如下:
97
98-f, 必选参数,待转换的.h文件;如cJSON.h99
100-o, 可选参数,生成路径,默认路径为.h文件所在路径;
101
102例如:
103
104```
105native_gen-win.exe -f cJSON.h
106```
107
1081.3运行成功后命令行会打印出 Generate success;
109
110![image-20240508143053083](../figures/DevEco_generate_success.png)
111
112并在nativetoolGen/cppout目录下会生成方法的cpp文件: 分别是cjsonnapi.hcJSON.h中接口对应的napi接口声明),cjsoninit.cpp(所有napi接口的init,用来初始化模块),cjsoncommon.hcjsoncommon.cpp(公共方法的声明和实现,如获取错误信息方法)和cJSON.h中接口对应的cpp文件:每个cJSON.h中的接口对应一个cpp文件,该文件中为框架生成的cJSON接口的napi框架代码,如:cjsoncreateobject.cpp, cjsonparse.cpp 等等。在nativetoolGen/tsout/index.d.ts文件中会写入生成的ts接口;在nativetoolGen/testout/cJSONAbility.test.ets生成接口测试代码模板。
113
114![image-20240508143053083](../figures/DevEco_generate_success_result.png)
115
116##### 2.确认生成代码是否能正确编译
117
1182.1将cppout(nativetoolGen/cppout)拷贝至 cJsonSampleTest/entry/src/main/cpp目录下; 将cJSON.h拷贝至cppout目录下。
119
1202.2将生成的所有cpp文件加入CMakeLists.txtcJsonSampleTest/entry/src/main/cpp/CMakeLists.txt)编译,其中cppout/cjsoninit.cpp为编译入口;即用下列add_library替换原有的add_library
121
122```
123add_library(entry SHARED
124    cppout/cjsonparse.cpp
125    cppout/cjsoninithooks.cpp
126    cppout/cjsonaddarraytoobject.cpp
127    cppout/cjsonaddbooltoobject.cpp
128    cppout/cjsonaddfalsetoobject.cpp
129    cppout/cjsonadditemreferencetoarray.cpp
130    cppout/cjsonadditemreferencetoobject.cpp
131    cppout/cjsonadditemtoarray.cpp
132    cppout/cjsonadditemtoobject.cpp
133    cppout/cjsonadditemtoobjectcs.cpp
134    cppout/cjsonaddnulltoobject.cpp
135    cppout/cjsonaddnumbertoobject.cpp
136    cppout/cjsonaddobjecttoobject.cpp
137    cppout/cjsonaddrawtoobject.cpp
138    cppout/cjsonaddstringtoobject.cpp
139    cppout/cjsonaddtruetoobject.cpp
140    cppout/cjsoncompare.cpp
141    cppout/cjsoncreatearray.cpp
142    cppout/cjsoncreatearrayreference.cpp
143    cppout/cjsoncreatebool.cpp
144    cppout/cjsoncreatedoublearray.cpp
145    cppout/cjsoncreatefalse.cpp
146    cppout/cjsoncreatefloatarray.cpp
147    cppout/cjsoncreateintarray.cpp
148    cppout/cjsoncreatenull.cpp
149    cppout/cjsoncreatenumber.cpp
150    cppout/cjsoncreateobject.cpp
151    cppout/cjsoncreateobjectreference.cpp
152    cppout/cjsoncreateraw.cpp
153    cppout/cjsoncreatestringarray.cpp
154    cppout/cjsoncreatestringreference.cpp
155    cppout/cjsoncreatetrue.cpp
156    cppout/cjsondelete.cpp
157    cppout/cjsondeleteitemfromarray.cpp
158    cppout/cjsondeleteitemfromobject.cpp
159    cppout/cjsondeleteitemfromobjectcasesensitive.cpp
160    cppout/cjsondetachitemfromarray.cpp
161    cppout/cjsondetachitemfromobject.cpp
162    cppout/cjsondetachitemfromobjectcasesensitive.cpp
163    cppout/cjsondetachitemviapointer.cpp
164    cppout/cjsonduplicate.cpp
165    cppout/cjsonfree.cpp
166    cppout/cjsongetarrayitem.cpp
167    cppout/cjsongetarraysize.cpp
168    cppout/cjsongeterrorptr.cpp
169    cppout/cjsongetnumbervalue.cpp
170    cppout/cjsongetobjectitem.cpp
171    cppout/cjsongetobjectitemcasesensitive.cpp
172    cppout/cjsongetstringvalue.cpp
173    cppout/cjsonhasobjectitem.cpp
174    cppout/cjsoninsertiteminarray.cpp
175    cppout/cjsonisarray.cpp
176    cppout/cjsonisbool.cpp
177    cppout/cjsonisfalse.cpp
178    cppout/cjsonisinvalid.cpp
179    cppout/cjsonisnull.cpp
180    cppout/cjsonisnumber.cpp
181    cppout/cjsonisobject.cpp
182    cppout/cjsonisraw.cpp
183    cppout/cjsonisstring.cpp
184    cppout/cjsonistrue.cpp
185    cppout/cjsonmalloc.cpp
186    cppout/cjsonminify.cpp
187    cppout/cjsonparsewithlength.cpp
188    cppout/cjsonparsewithlengthopts.cpp
189    cppout/cjsonparsewithopts.cpp
190    cppout/cjsonprint.cpp
191    cppout/cjsonprintbuffered.cpp
192    cppout/cjsonprintpreallocated.cpp
193    cppout/cjsonprintunformatted.cpp
194    cppout/cjsonreplaceiteminarray.cpp
195    cppout/cjsonreplaceiteminobject.cpp
196    cppout/cjsonreplaceiteminobjectcasesensitive.cpp
197    cppout/cjsonreplaceitemviapointer.cpp
198    cppout/cjsonsetnumberhelper.cpp
199    cppout/cjsonsetvaluestring.cpp
200    cppout/cjsonversion.cpp
201    cppout/cjsoncreatestring.cpp
202    cppout/cjsoncommon.cpp
203    cppout/cjsoninit.cpp
204    )
205```
206
2072.4将index.d.tsnativetoolGen/tsout/index.d.ts)中所有内容拷贝至 cJsonSampleTest/entry/src/main/cpp/types/libentry/index.d.ts中;
208
2092.5将nativetoolGen/testout/cJSONAbilitytest.test.ets拷贝到cJsonSampleTest/entry/src/ohosTest/ets/test目录下;
210
211cJsonSampleTest/entry/src/ohosTest/ets/test/List.test.ets中导入cJSONAbilitytest.test.ets
212
213```
214import abilityTest from './Ability.test';
215import cJSONabilityTest from './cJSONAbility.test';
216
217export default function testsuite() {
218  abilityTest();
219  cJSONabilityTest();
220}
221```
222
223![image-20240508110824799](../figures/DevEco_add_abilitytest.png)
224
2252.6对工程签名:File->Project Structure ->Project -> Signing Configs
226
227![image-20240508111334952](../figures/DevEco_Sign_configs.png)
228
229运行cJSONAbilitytest.test.ets中的测试集cJSONActsAbilityTest,用例成功运行,并打印出相关log。
230
231![image-20240508111334952](../figures/DevEco_test_allcases_success.png)
232
233例如:方法KH418_cJSON_Parse打印出默认对象值(以cJSON_Parse接口为例:本例子生成的方法为KH418_cJSON_Parse,其中KH418中的数字为随机生成,用户使用时数字可能不是418, 而是其它三位随机数。)
234
235```
236 I  KH418_cJSON_Parse result: {"next":{},"prev":{},"child":{},"type":1,"valuestring":"valuestring","valueint":1,"valuedouble":1,"string":"string"}
237```
238
239![image-20240508111334952](../figures/DevEco_test_gen_is_success.png)
240
241## 增加业务代码并测试
242
243### 增加业务代码
244
245以cjson_parse接口为例
246
2471.在cjsonparse.cpp(cJsonSampleTest\entry\src\main\cpp\cppout)代码中
248
249```
250// Todo: add business logic. 在这前后代码为框架所生成
251```
252
253处加入业务代码:
254
2551.1将字符串转换为cJSON对象,调用cJSON_Parse方法;
256
257```
258    cJSON *json = cJSON_Parse(valueIn);
259    if (json == nullptr) {
260        return nullptr;
261    }
262    cJSON *jsonChild = nullptr;
263    if (json != nullptr) {
264        jsonChild = json->child;
265    }
266    cJSON *jsonNext = nullptr;
267    if (jsonChild != nullptr) {
268        jsonNext = jsonChild->next;
269    }
270    delete[] valueIn;
271```
272
2731.2将native层转换成功的json对象对应转换为js层的对象:向框架生成的cJSON_ParseOut空对象中一一塞入json对象数据并返回js层。
274
275增加业务代码之后的cjsonparse.cpp如下所示:(注意:本示例的方法名字是KH418_cJSON_Parse,用户使用时需要将KH418_cJSON_Parse方法名修改为自身的KHxxx_cJSON_Parse方法名)
276
277```
278#include "cjsonnapi.h"
279
280napi_value getCjsonChildOut2(napi_env env, napi_value childOut, cJSON *jsonChild) {
281    napi_status status;
282    const napi_extended_error_info *extended_error_info;
283    const char *tag = "[KH418_cJSON_Parse]";
284    napi_value childTypeOut;
285    status = napi_create_int32(env, jsonChild->type, &childTypeOut);
286    if (status != napi_ok) {
287        getErrMessage(status, env, extended_error_info, "napi_create_int32 jsonChild->type", tag);
288        return nullptr;
289    }
290    status = napi_set_named_property(env, childOut, "type", childTypeOut);
291    if (status != napi_ok) {
292        getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonChild->type", tag);
293        return nullptr;
294    }
295    napi_value childValueintOut;
296    status = napi_create_int32(env, jsonChild->valueint, &childValueintOut);
297    if (status != napi_ok) {
298        getErrMessage(status, env, extended_error_info, "napi_create_int32 jsonChild->valueint", tag);
299        return nullptr;
300    }
301    status = napi_set_named_property(env, childOut, "valueint", childValueintOut);
302    if (status != napi_ok) {
303        getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonChild->valueint", tag);
304        return nullptr;
305    }
306    napi_value childValuedoubleOut;
307    status = napi_create_double(env, jsonChild->valuedouble, &childValuedoubleOut);
308    if (status != napi_ok) {
309        getErrMessage(status, env, extended_error_info, "napi_create_double jsonChild->valuedouble", tag);
310        return nullptr;
311    }
312    status = napi_set_named_property(env, childOut, "valuedouble", childValuedoubleOut);
313    if (status != napi_ok) {
314        getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonChild->valuedouble", tag);
315        return nullptr;
316    }
317    return childOut;
318}
319
320napi_value getCjsonChildOut(napi_env env, napi_value childOut, cJSON *jsonChild) {
321    napi_status status;
322    const napi_extended_error_info *extended_error_info;
323    const char *tag = "[KH418_cJSON_Parse]";
324    // 将数据塞入child
325    if (jsonChild != nullptr) {
326        napi_value childValuestringOut;
327        status = napi_create_string_utf8(env, jsonChild->valuestring == nullptr ? "" : jsonChild->valuestring,
328                                         NAPI_AUTO_LENGTH, &childValuestringOut);
329        if (status != napi_ok) {
330            getErrMessage(status, env, extended_error_info, "napi_create_string_utf8 jsonChild->valuestring", tag);
331            return nullptr;
332        }
333        status = napi_set_named_property(env, childOut, "valuestring", childValuestringOut);
334        if (status != napi_ok) {
335            getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonChild->valuestring", tag);
336            return nullptr;
337        }
338        napi_value childStringOut;
339        status = napi_create_string_utf8(env, jsonChild->string == nullptr ? "" : jsonChild->string, NAPI_AUTO_LENGTH,
340                                         &childStringOut);
341        if (status != napi_ok) {
342            getErrMessage(status, env, extended_error_info, "napi_create_string_utf8 jsonChild->string", tag);
343            return nullptr;
344        }
345        status = napi_set_named_property(env, childOut, "string", childStringOut);
346        if (status != napi_ok) {
347            getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonChild->string", tag);
348            return nullptr;
349        }
350        childOut = getCjsonChildOut2(env, childOut, jsonChild);
351    }
352    return childOut;
353}
354
355napi_value getCjsonNextOut2(napi_env env, napi_value nextOut, cJSON *jsonNext) {
356    napi_status status;
357    const napi_extended_error_info *extended_error_info;
358    const char *tag = "[KH418_cJSON_Parse]";
359    napi_value nextTypeOut;
360    status = napi_create_int32(env, jsonNext->type, &nextTypeOut);
361    if (status != napi_ok) {
362        getErrMessage(status, env, extended_error_info, "napi_create_int32 jsonNext->type", tag);
363        return nullptr;
364    }
365    status = napi_set_named_property(env, nextOut, "type", nextTypeOut);
366    if (status != napi_ok) {
367        getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonNext->type", tag);
368        return nullptr;
369    }
370    napi_value nextValueintOut;
371    status = napi_create_int32(env, jsonNext->valueint, &nextValueintOut);
372    if (status != napi_ok) {
373        getErrMessage(status, env, extended_error_info, "napi_create_int32 jsonNext->valueint", tag);
374        return nullptr;
375    }
376    status = napi_set_named_property(env, nextOut, "valueint", nextValueintOut);
377    if (status != napi_ok) {
378        getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonNext->valueint", tag);
379        return nullptr;
380    }
381    napi_value nextValuedoubleOut;
382    status = napi_create_double(env, jsonNext->valuedouble, &nextValuedoubleOut);
383    if (status != napi_ok) {
384        getErrMessage(status, env, extended_error_info, "napi_create_double jsonNext->valuedouble", tag);
385        return nullptr;
386    }
387    status = napi_set_named_property(env, nextOut, "valuedouble", nextValuedoubleOut);
388    if (status != napi_ok) {
389        getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonNext->valuedouble", tag);
390        return nullptr;
391    }
392    return nextOut;
393}
394
395napi_value getCjsonNextOut(napi_env env, napi_value nextOut, cJSON *jsonNext) {
396    napi_status status;
397    const napi_extended_error_info *extended_error_info;
398    const char *tag = "[KH418_cJSON_Parse]";
399    // 将数据塞入next
400    if (jsonNext != nullptr) {
401        napi_value nextValuestringOut;
402        status = napi_create_string_utf8(env, jsonNext->valuestring == nullptr ? "" : jsonNext->valuestring,
403                                         NAPI_AUTO_LENGTH, &nextValuestringOut);
404        if (status != napi_ok) {
405            getErrMessage(status, env, extended_error_info, "napi_create_string_utf8 jsonNext->valuestring", tag);
406            return nullptr;
407        }
408        status = napi_set_named_property(env, nextOut, "valuestring", nextValuestringOut);
409        if (status != napi_ok) {
410            getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonNext->valuestring", tag);
411            return nullptr;
412        }
413        napi_value nextStringOut;
414        status = napi_create_string_utf8(env, jsonNext->string == nullptr ? "" : jsonNext->string, NAPI_AUTO_LENGTH,
415                                         &nextStringOut);
416        if (status != napi_ok) {
417            getErrMessage(status, env, extended_error_info, "napi_create_string_utf8 jsonNext->string", tag);
418            return nullptr;
419        }
420        status = napi_set_named_property(env, nextOut, "string", nextStringOut);
421        if (status != napi_ok) {
422            getErrMessage(status, env, extended_error_info, "napi_set_named_property jsonNext->string", tag);
423            return nullptr;
424        }
425        nextOut = getCjsonNextOut2(env, nextOut, jsonNext);
426    }
427    return nextOut;
428}
429
430napi_value getCjsonparseOut1(napi_env env, cJSON *jsonNext, napi_value cJSON_ParseOut) {
431    napi_status status;
432    const napi_extended_error_info *extended_error_info;
433    const char *tag = "[KH418_cJSON_Parse]";
434    napi_value nextOut;
435    /* [NAPI_GEN]: 返回值是对象时,需要使用napi_create_object创建一个js的对象与js代码交互
436     * env: 当前环境的句柄
437     * result: 一个napi_value的指针,该指针将被设置为新创建的js对象
438     */
439    status = napi_create_object(env, &nextOut);
440    if (status != napi_ok) {
441        getErrMessage(status, env, extended_error_info, "napi_create_object", tag);
442        return nullptr;
443    }
444    nextOut = getCjsonNextOut(env, nextOut, jsonNext);
445    /* [NAPI_GEN]: 返回值是对象时,将native侧的对象的属性和值依次塞入napi_create_object创建出的对象,后将该对象返回js
446     * env: 当前环境的句柄
447     * object: 要设置属性的js对象,该对象是由上文napi_create_object创建的
448     * utf8name: 属性的名称,是一个以UTF-8编码的字符串
449     * value: 与属性名称关联的值,这个值可以是任何js类型(如一个数值、字符串、另一个对象等)
450     */
451    status = napi_set_named_property(env, cJSON_ParseOut, "next", nextOut);
452    if (status != napi_ok) {
453        /* [NAPI_GEN]: 错误处理*/
454        getErrMessage(status, env, extended_error_info, "napi_set_named_property", tag);
455        return nullptr;
456    }
457    napi_value prevOut;
458    /* [NAPI_GEN]: 返回值是对象时,需要使用napi_create_object创建一个js的对象与js代码交互
459     * env: 当前环境的句柄
460     * result: 一个napi_value的指针,该指针将被设置为新创建的js对象
461     */
462    status = napi_create_object(env, &prevOut);
463    if (status != napi_ok) {
464        getErrMessage(status, env, extended_error_info, "napi_create_object", tag);
465        return nullptr;
466    }
467    /* [NAPI_GEN]: 返回值是对象时,将native侧的对象的属性和值依次塞入napi_create_object创建出的对象,将该对象返回js
468     * env: 当前环境的句柄
469     * object: 要设置属性的js对象,该对象是由上文napi_create_object创建的
470     * utf8name: 属性的名称,是一个以UTF-8编码的字符串
471     * value: 与属性名称关联的值,这个值可以是任何js类型(如一个数值、字符串、另一个对象等)
472     */
473    status = napi_set_named_property(env, cJSON_ParseOut, "prev", prevOut);
474    if (status != napi_ok) {
475        /* [NAPI_GEN]: 错误处理*/
476        getErrMessage(status, env, extended_error_info, "napi_set_named_property", tag);
477        return nullptr;
478    }
479    return cJSON_ParseOut;
480}
481
482napi_value getCjsonparseOut2(napi_env env, cJSON *json, cJSON *jsonChild, napi_value cJSON_ParseOut) {
483    napi_status status;
484    const napi_extended_error_info *extended_error_info;
485    const char *tag = "[KH418_cJSON_Parse]";
486    napi_value childOut;
487    /* [NAPI_GEN]: 返回值是对象时,需要使用napi_create_object创建一个js的对象与js代码交互
488     * env: 当前环境的句柄
489     * result: 一个napi_value的指针,该指针将被设置为新创建的js对象
490     */
491    status = napi_create_object(env, &childOut);
492    if (status != napi_ok) {
493        getErrMessage(status, env, extended_error_info, "napi_create_object", tag);
494        return nullptr;
495    }
496    childOut = getCjsonChildOut(env, childOut, jsonChild);
497    /* [NAPI_GEN]:
498     * 返回值是对象时,将native侧的对象的属性和值依次塞入napi_create_object创建出的对象,后将该对象返回js env:
499     * 当前环境的句柄 object: 要设置属性的js对象,该对象是由上文napi_create_object创建的 utf8name:
500     * 属性的名称,是一个以UTF-8编码的字符串 value:
501     * 与属性名称关联的值,这个值可以是任何js类型(如一个数值、字符串、另一个对象等)
502     */
503    status = napi_set_named_property(env, cJSON_ParseOut, "child", childOut);
504    if (status != napi_ok) {
505        /* [NAPI_GEN]: 错误处理*/
506        getErrMessage(status, env, extended_error_info, "napi_set_named_property", tag);
507        return nullptr;
508    }
509    napi_value typeOut;
510    /* [NAPI_GEN]: 返回值是int32_t类型时,napi_create_int32 创建一个包含32位整数(int32_t)的js数值(Number)对象
511     * env: 当前环境的句柄
512     * value: 要准换成js数值的int32_t的值,这里以传入1为例,用例新增业务代码时可根据自身需求修改
513     * result: 指向napi_value的指针,这个指针会被设置为新创建的js数值对象
514     */
515    status = napi_create_int32(env, json == nullptr ? 0 : json->type, &typeOut);
516    if (status != napi_ok) {
517        getErrMessage(status, env, extended_error_info, "napi_create_int32", tag);
518        return nullptr;
519    }
520    /* [NAPI_GEN]: 返回值是对象时,将native侧的对象的属性和值依次塞入napi_create_object创建出的对象,后将该对象返回js
521     * env: 当前环境的句柄
522     * object: 要设置属性的js对象,该对象是由上文napi_create_object创建的
523     * utf8name: 属性的名称,是一个以UTF-8编码的字符串
524     * value: 与属性名称关联的值,这个值可以是任何js类型(如一个数值、字符串、另一个对象等)
525     */
526    status = napi_set_named_property(env, cJSON_ParseOut, "type", typeOut);
527    if (status != napi_ok) {
528        /* [NAPI_GEN]: 错误处理*/
529        getErrMessage(status, env, extended_error_info, "napi_set_named_property", tag);
530        return nullptr;
531    }
532    return cJSON_ParseOut;
533}
534
535napi_value getCjsonparseOut3(napi_env env, cJSON *json, napi_value cJSON_ParseOut) {
536    napi_status status;
537    const napi_extended_error_info *extended_error_info;
538    const char *tag = "[KH418_cJSON_Parse]";
539    napi_value valuestringOut;
540    /* [NAPI_GEN]:
541     * 返回值是字符串时,napi_create_string_utf8用于在原生代码中创建一个新的js字符串。这个函数会根据提供的UTF-8编码的字符串创建一个等价的js字符串
542     * env: 当前环境的句柄
543     * str: 指向以null结尾的UTF-8编码的C字符串的指针,这里以valuestring举例,用户可根据需求修改
544     * length:
545     * 字符串的长度,可以是具体的字节数,或者使用特殊的值NAPI_AUTO_LENGTH来让函数自己计算长度(假定字符串以null结尾)
546     * result: 指向napi_value的指针,函数执行成功后这个指针将指向新创建的js字符串
547     */
548    status =
549        napi_create_string_utf8(env, json == nullptr ? "" : (json->valuestring == nullptr ? "" : json->valuestring),
550                                NAPI_AUTO_LENGTH, &valuestringOut);
551    if (status != napi_ok) {
552        /*错误处理*/
553        getErrMessage(status, env, extended_error_info, "napi_create_string_utf8", tag);
554        return nullptr;
555    }
556    /* [NAPI_GEN]: 返回值是对象时,将native侧的对象的属性和值依次塞入napi_create_object创建出的对象,后将该对象返回js
557     * env: 当前环境的句柄
558     * object: 要设置属性的js对象,该对象是由上文napi_create_object创建的
559     * utf8name: 属性的名称,是一个以UTF-8编码的字符串
560     * value: 与属性名称关联的值,这个值可以是任何js类型(如一个数值、字符串、另一个对象等)
561     */
562    status = napi_set_named_property(env, cJSON_ParseOut, "valuestring", valuestringOut);
563    if (status != napi_ok) {
564        /* [NAPI_GEN]: 错误处理*/
565        getErrMessage(status, env, extended_error_info, "napi_set_named_property", tag);
566        return nullptr;
567    }
568    napi_value valueintOut;
569    /* [NAPI_GEN]: 返回值是int32_t类型时,napi_create_int32 创建一个包含32位整数(int32_t)的js数值(Number)对象
570     * env: 当前环境的句柄
571     * value: 要准换成js数值的int32_t的值,这里以传入1为例,用例新增业务代码时可根据自身需求修改
572     * result: 指向napi_value的指针,这个指针会被设置为新创建的js数值对象
573     */
574    status = napi_create_int32(env, json == nullptr ? 0 : json->valueint, &valueintOut);
575    if (status != napi_ok) {
576        getErrMessage(status, env, extended_error_info, "napi_create_int32", tag);
577        return nullptr;
578    }
579    /* [NAPI_GEN]: 返回值是对象时,将native侧的对象的属性和值依次塞入napi_create_object创建出的对象,后将该对象返回js
580     * env: 当前环境的句柄
581     * object: 要设置属性的js对象,该对象是由上文napi_create_object创建的
582     * utf8name: 属性的名称,是一个以UTF-8编码的字符串
583     * value: 与属性名称关联的值,这个值可以是任何js类型(如一个数值、字符串、另一个对象等)
584     */
585    status = napi_set_named_property(env, cJSON_ParseOut, "valueint", valueintOut);
586    if (status != napi_ok) {
587        /* [NAPI_GEN]: 错误处理*/
588        getErrMessage(status, env, extended_error_info, "napi_set_named_property", tag);
589        return nullptr;
590    }
591    return cJSON_ParseOut;
592}
593
594napi_value getCjsonparseOut4(napi_env env, cJSON *json, napi_value cJSON_ParseOut) {
595    napi_status status;
596    const napi_extended_error_info *extended_error_info;
597    const char *tag = "[KH418_cJSON_Parse]";
598    napi_value valuedoubleOut;
599    /* [NAPI_GEN]: 返回值是double类型时,napi_create_double 创建一个包含双精度浮点数的js数值(Number)对象
600     * env: 当前环境的句柄
601     * value: 要传递给js的双精度浮点数值,这里以传入1.0为例,用例新增业务代码时可根据自身需求修改
602     * result: 指向napi_value的指针,这个指针会被设置为新创建的js数值对象
603     */
604    status = napi_create_double(env, json == nullptr ? 0 : json->valuedouble, &valuedoubleOut);
605    if (status != napi_ok) {
606        getErrMessage(status, env, extended_error_info, "napi_create_double", tag);
607        return nullptr;
608    }
609    /* [NAPI_GEN]: 返回值是对象时,将native侧的对象的属性和值依次塞入napi_create_object创建出的对象,后将该对象返回js
610     * env: 当前环境的句柄
611     * object: 要设置属性的js对象,该对象是由上文napi_create_object创建的
612     * utf8name: 属性的名称,是一个以UTF-8编码的字符串
613     * value: 与属性名称关联的值,这个值可以是任何js类型(如一个数值、字符串、另一个对象等)
614     */
615    status = napi_set_named_property(env, cJSON_ParseOut, "valuedouble", valuedoubleOut);
616    if (status != napi_ok) {
617        /* [NAPI_GEN]: 错误处理*/
618        getErrMessage(status, env, extended_error_info, "napi_set_named_property", tag);
619        return nullptr;
620    }
621    napi_value stringOut;
622    /* [NAPI_GEN]:
623     * 返回值是字符串时,napi_create_string_utf8用于在原生代码中创建一个新的js字符串。这个函数会根据提供的UTF-8编码的字符串创建一个等价的js字符串
624     * env: 当前环境的句柄
625     * str: 指向以null结尾的UTF-8编码的C字符串的指针,这里以string举例,用户可根据需求修改
626     * length:
627     * 字符串的长度,可以是具体的字节数,或者使用特殊的值NAPI_AUTO_LENGTH来让函数自己计算长度(假定字符串以null结尾)
628     * result: 指向napi_value的指针,函数执行成功后这个指针将指向新创建的js字符串
629     */
630    status = napi_create_string_utf8(env, json == nullptr ? "" : (json->string == nullptr ? "" : json->string),
631                                     NAPI_AUTO_LENGTH, &stringOut);
632    if (status != napi_ok) {
633        /*错误处理*/
634        getErrMessage(status, env, extended_error_info, "napi_create_string_utf8", tag);
635        return nullptr;
636    }
637    /* [NAPI_GEN]: 返回值是对象时,将native侧的对象的属性和值依次塞入napi_create_object创建出的对象,后将该对象返回js
638     * env: 当前环境的句柄
639     * object: 要设置属性的js对象,该对象是由上文napi_create_object创建的
640     * utf8name: 属性的名称,是一个以UTF-8编码的字符串
641     * value: 与属性名称关联的值,这个值可以是任何js类型(如一个数值、字符串、另一个对象等)
642     */
643    status = napi_set_named_property(env, cJSON_ParseOut, "string", stringOut);
644    if (status != napi_ok) {
645        /* [NAPI_GEN]: 错误处理*/
646        getErrMessage(status, env, extended_error_info, "napi_set_named_property", tag);
647        return nullptr;
648    }
649    return cJSON_ParseOut;
650}
651
652/* [NAPI_GEN]:对应cJSON.h中:cJSON_Parse的napi方法,
653 * 输入:value: const char *; 
654 * 输出:cJSON *
655 */ 
656napi_value KH418_cJSON_Parse(napi_env env, napi_callback_info info)
657{
658    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "KH418_cJSON_Parse", "KH418_cJSON_Parse begins");
659    napi_status status;
660    /* [NAPI_GEN]: Node.js在其N-API中用来提供错误的扩展信息的结构体,结构体包含以下字段
661     * error_message: 一个指向错误详细字符串的指针,提供了关于错误的文本描述
662     * engin_reserved: 一个保留给Js引擎使用的指针
663     * error_code: 错误码,指示了错误的种类,比如napi_pending_exception表示有一个JavaScript异常未被清理。
664     * engine_error_code:一个引擎特定的错误码,为引擎实现保留,具体含义依赖于使用的JavaScript引擎。
665     * error_message_len:错误消息字符串的长度。
666     */
667    const napi_extended_error_info *extended_error_info;
668    /* [NAPI_GEN]: tag: 日志打印标签*/
669    const char *tag = "[KH418_cJSON_Parse]";
670    /* [NAPI_GEN]: get function param in*/
671    /* [NAPI_GEN]: argc:js传入的参数个数 */
672    size_t argc = PARAMS1;
673    /* [NAPI_GEN]: args: 一个数组,保存js传入的参数 */
674    napi_value args[PARAMS1] = {nullptr};
675    /* [NAPI_GEN]: napi_get_cb_info用于获取JS调用该函数时所传递的参数、接收参数的个数以及'this'的值
676     * env: 当前环境的句柄,代表当前的Node.js环境
677     * info: 回调信息句柄,代表当前回调的上下文
678     * argc: 指向size_t的指针,开始应包含可接受的max参数数量,函数返回时,它将包含实际传递的参数数量
679     * args: 一个足够大的数组,用于接收传递给回调函数的所有js参数。数组的大小应至少与argc传入的值一样大。
680     * this_arg: 如果不是NULL,则返回js回调中this的值
681     * data: 如果不是NULL,则返回与回调函数关联的任何可选数据。通常用于传递在创建函数时指定的静态数据
682     */
683    status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
684    if(status != napi_ok) {
685        /* [NAPI_GEN]: 错误处理*/
686        getErrMessage(status, env,extended_error_info, "napi_get_cb_info", tag);
687        return nullptr;
688    }
689    /* [NAPI_GEN]: 从args数组中获取入参 */
690    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "KH418_cJSON_Parse", "KH418_cJSON_Parse get param info begins");
691    napi_valuetype valuetypevalue;
692    /* [NAPI_GEN]: 获取入参类型,第PARAMS0个入参
693     * env: N-API环境的句柄,表示当前的上下文
694     * value: 要检查类型的js值
695     * result: 是一个指针,指向napi_valuetype枚举的值,函数会将结果存储在这里
696     */
697    status = napi_typeof(env, args[PARAMS0], &valuetypevalue);
698    if (status != napi_ok) {
699        getErrMessage(status, env, extended_error_info, "napi_typeof", tag);
700        return nullptr;
701    }
702    size_t strSizePARAMS0 = 0;
703    /* [NAPI_GEN]: napi_get_value_string_utf8用于将Js字符串转换为UTF-8编码的C字符串
704     * env: N-API环境的句柄,表示当前的上下文
705     * value: 要转换的JavaScript字符串
706     * buf: 用于存储结果的字符数组的指针
707     * bufsize: 缓冲区大小,以字节为单位
708     * result: 转换后的字符串的字节长度(不包括空终止符)。若干buf是NULL,则返回所需的缓冲区大小(包括空终止符)
709     */
710    /* [NAPI_GEN]: buf参数是NULL时,用于获取所需缓冲区大小*/
711    status = napi_get_value_string_utf8(env, args[PARAMS0], NULL, 0, &strSizePARAMS0);
712    if (status != napi_ok) {
713        getErrMessage(status, env, extended_error_info, "get value string", tag);
714        return nullptr;
715    }
716    char *valueIn = new char[strSizePARAMS0 + 1];
717    /* [NAPI_GEN]: 用于获取字符串*/
718    status = napi_get_value_string_utf8(env, args[PARAMS0], valueIn, strSizePARAMS0 + 1, &strSizePARAMS0);
719    if (status != napi_ok) {
720        getErrMessage(status, env, extended_error_info, "get value string", tag);
721        delete[] valueIn;
722        return nullptr;
723    }
724    // delete[] valueIn;  // remember to delete memory 
725
726    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "KH418_cJSON_Parse", "KH418_cJSON_Parse get param info ends");
727    
728    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "KH418_cJSON_Parse", "KH418_cJSON_Parse get return info begins");
729    // Todo: add business logic. 在这前后代码为框架所生成
730    cJSON *json = cJSON_Parse(valueIn);
731    if (json == nullptr) {
732        return nullptr;
733    }
734    cJSON *jsonChild = nullptr;
735    if (json != nullptr) {
736        jsonChild = json->child;
737    }
738    cJSON *jsonNext = nullptr;
739    if (jsonChild != nullptr) {
740        jsonNext = jsonChild->next;
741    }
742    delete[] valueIn;
743
744    /* [NAPI_GEN]: function return value*/ 
745    napi_value cJSON_ParseOut;
746    /* [NAPI_GEN]: 返回值是对象时,需要使用napi_create_object创建一个js的对象与js代码交互
747     * env: 当前环境的句柄
748     * result: 一个napi_value的指针,该指针将被设置为新创建的js对象
749     */
750    status = napi_create_object(env, &cJSON_ParseOut);
751    if (status != napi_ok) {
752        getErrMessage(status, env, extended_error_info, "napi_create_object", tag);
753        return nullptr;
754    }
755    cJSON_ParseOut = getCjsonparseOut1(env, jsonNext, cJSON_ParseOut);
756    cJSON_ParseOut = getCjsonparseOut2(env, json, jsonChild, cJSON_ParseOut);
757    cJSON_ParseOut = getCjsonparseOut3(env, json, cJSON_ParseOut);
758    cJSON_ParseOut = getCjsonparseOut4(env, json, cJSON_ParseOut);
759
760    cJSON_Delete(json);
761
762    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "KH418_cJSON_Parse", "KH418_cJSON_Parse get return info ends");
763    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "KH418_cJSON_Parse", "KH418_cJSON_Parse ends");
764    return cJSON_ParseOut;
765
766}
767
768```
769
770### 测试调用
771
772以cjson_parse接口为例
773
7741.在cJsonSampleTest/entry/src/ohosTest/ets/test/CjsonTest/CjsonTest.test.ets测试集中修改KH418_cJSON_Parse方法的测试用例
775
776![image-20240508111649030](../figures/DevEco_add_businessTest_case.png)
777
778```
779    it('KH418_cJSON_Parse', 0, () => {
780      // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
781      hilog.info(0x0000, 'testTag', '%{public}s', 'it KH418_cJSON_Parse begin');
782      // 测试字符串的转换
783      let value = '"helloworld"'
784      let result: testNapi.cJSON = testNapi.KH418_cJSON_Parse(value);
785      // 测试数字的转换
786      let value2 = '1.8'
787      let result2: testNapi.cJSON = testNapi.KH418_cJSON_Parse(value2);
788      // 测试数组的转换
789      let value3 = '["a","b"]'
790      let result3: testNapi.cJSON = testNapi.KH418_cJSON_Parse(value3);
791      // 测试对象的转换
792      let value4 = '{"name":"JohnDoe","age":18}'
793      let result4: testNapi.cJSON = testNapi.KH418_cJSON_Parse(value4);
794      
795      // 打印结果
796      console.info("Test NAPI KH418_cJSON_Parse result1: ", JSON.stringify(result))
797      console.info("Test NAPI KH418_cJSON_Parse result2: ", JSON.stringify(result2))
798      console.info("Test NAPI KH418_cJSON_Parse result3: ", JSON.stringify(result3))
799      console.info("Test NAPI KH418_cJSON_Parse result4: ", JSON.stringify(result4))
800    })
801```
802
8032.运行 KH418_cJSON_Parse, 打印结果如下:
804
805```
806I  Test NAPI KH418_cJSON_Parse result1:  {"next":{},"prev":{},"child":{},"type":16,"valuestring":"helloworld","valueint":0,"valuedouble":0,"string":""}
807I  Test NAPI KH418_cJSON_Parse result2:  {"next":{},"prev":{},"child":{},"type":8,"valuestring":"","valueint":1,"valuedouble":1.8,"string":""}
808I  Test NAPI KH418_cJSON_Parse result3:  {"next":{"valuestring":"b","string":"","type":16,"valueint":0,"valuedouble":0},"prev":{},"child":{"valuestring":"a","string":"","type":16,"valueint":0,"valuedouble":0},"type":32,"valuestring":"","valueint":0,"valuedouble":0,"string":""}
809I  Test NAPI KH418_cJSON_Parse result4:  {"next":{"valuestring":"","string":"age","type":8,"valueint":18,"valuedouble":18},"prev":{},"child":{"valuestring":"JohnDoe","string":"name","type":16,"valueint":0,"valuedouble":0},"type":64,"valuestring":"","valueint":0,"valuedouble":0,"string":""}
810```
811
812![image-20240508111649030](../figures/DevEco_test_add_businesscode_success.png)
813
814