• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用Node-API接口进行模块加载
2<!--Kit: NDK-->
3<!--Subsystem: arkcompiler-->
4<!--Owner: @xliu-huanwei; @shilei123; @huanghello-->
5<!--Designer: @shilei123-->
6<!--Tester: @kirl75; @zsw_zhushiwei-->
7<!--Adviser: @fang-jinxu-->
8
9Node-API中的napi_load_module_with_info接口的功能是进行模块的加载,当模块加载出来之后,可以使用函数napi_get_property获取模块导出的变量,也可以使用napi_get_named_property获取模块导出的函数,该函数可以在[新创建的ArkTS基础运行时环境](use-napi-ark-runtime.md)中使用,即napi_create_ark_runtime接口创建的运行时环境。
10
11## 函数说明
12
13```cpp
14napi_status napi_load_module_with_info(napi_env env, const char* path, const char* module_info, napi_value* result);
15```
16
17| 参数            | 说明          |
18| :------------- | :----------------------------- |
19| env            | 当前的虚拟机环境       |
20| path          | 加载的文件路径或者模块名          |
21| module_info   | bundleName/moduleName的路径拼接       |
22| result         | 加载的模块          |
23
24> **注意**
25>
26> 1. bundleName表示AppScope/app.json5中配置的工程名;
27> 2. moduleName指的是待加载模块所在的HAP下module.json5中配置的名字;
28
29## napi_load_module_with_info支持的场景
30
31| 场景            | 详细分类           | 说明                         |
32| :------------- | :----------------------------- | :--------------------------- |
33| 本地工程模块   | 加载模块内文件路径       | 要求路径以moduleName开头             |
34| 本地工程模块   | 加载HAR模块名           | -                            |
35| 远程包         | 加载远程HAR模块名        | -                            |
36| 远程包         | 加载ohpm包名            | -                            |
37| API        |    加载@ohos.*或 @system.*          | -                            |
38| 模块Native库   | 加载libNativeLibrary.so | -                            |
39
40> **注意**
41>
42> 1. 加载一个模块名,实际的行为是加载该模块的入口文件,一般为index.ets/ts43> 2. 如果在HAR中加载另外一个HAR,需要确保module_info的配置正确,尤其注意moduleName应为HAP的moduleName或者HSP的moduleName。
44> 3. 如果在HAP/HSP中直接或间接使用了三方包,该三方包中使用napi_load_module_with_info接口加载其他模块A,则需要在HAP/HSP中也添加A的依赖。
45
46## 异常场景
471. 在模块加载过程中,若出现包内未找到对应文件或build-profile.json5配置错误等问题,返回错误码`napi_generic_failure`,并打印报错日志。
48![napi_load_module_with_info](figures/napi_load_module_with_info.png)
492. 系统侧发生非预期行为导致加载模块无法正常执行,将抛出cppcrash。
50
51## 使用示例
52
53- **加载模块内文件路径**
54
55当加载文件中的模块时,如以下ArkTS代码:
56
57```javascript
58//./src/main/ets/Test.ets
59let value = 123;
60function test() {
61  console.info("Hello OpenHarmony");
62}
63export {value, test};
64```
65
661. 当前模块的build-profile.json5文件中需进行以下配置:
67
68    ```json
69    {
70        "buildOption" : {
71            "arkOptions" : {
72                "runtimeOnly" : {
73                    "sources": [
74                        "./src/main/ets/Test.ets"
75                    ]
76                }
77            }
78        }
79    }
80    ```
81
822. 使用napi_load_module_with_info加载Test文件,调用函数test以及获取变量value。
83
84    > **注意**
85    >
86    > 开启useNormalizedOHMUrl后(即将工程目录中与entry同级别的应用级build-profile.json5文件中strictMode属性的useNormalizedOHMUrl字段配置为true),加载模块内文件路径时:
87    >
88    > 1. bundleName不会影响最终加载逻辑,会智能通过module名索引进程内对应的hap,例如:工程的bundleName为com.example.application,实际入参时填写为 com.example.application1,模块也能正常加载。
89    > 2. 路径需要以packageName开头,packageName指的是模块的oh-package.json5中配置的name字段。
90
91
92    ~~~c++
93    static napi_value loadModule(napi_env env, napi_callback_info info) {
94        napi_value result;
95        // 1. 使用napi_load_module_with_info加载Test文件中的模块
96        napi_status status = napi_load_module_with_info(env, "entry/src/main/ets/Test", "com.example.application/entry", &result);
97        if (status != napi_ok) {
98            return nullptr;
99        }
100
101        napi_value testFn;
102        // 2. 使用napi_get_named_property获取test函数
103        napi_get_named_property(env, result, "test", &testFn);
104        // 3. 使用napi_call_function调用函数test
105        napi_call_function(env, result, testFn, 0, nullptr, nullptr);
106
107        napi_value value;
108        napi_value key;
109        std::string keyStr = "value";
110        napi_create_string_utf8(env, keyStr.c_str(), keyStr.size(), &key);
111        // 4. 使用napi_get_property获取变量value
112        napi_get_property(env, result, key, &value);
113        return result;
114    }
115    ~~~
116
117- **加载源码HAR模块**
118
119HAR包Index.ets文件如下:
120
121```javascript
122//library Index.ets
123let value = 123;
124function test() {
125    console.info("Hello OpenHarmony");
126}
127export {value, test};
128```
129
1301. 在oh-package.json5文件中配置dependencies项:
131
132    ```json
133    {
134        "dependencies": {
135            "library": "file:../library"
136        }
137    }
138    ```
139
1402. 在使用library的模块中,对build-profile.json5进行配置:
141
142    ```json
143    {
144        "buildOption" : {
145            "arkOptions" : {
146                "runtimeOnly" : {
147                    "packages": [
148                        "library"
149                    ]
150                }
151            }
152        }
153    }
154    ```
155
1563. 使用napi_load_module_with_info加载library,调用函数test以及获取变量value:
157
158    ```cpp
159    static napi_value loadModule(napi_env env, napi_callback_info info) {
160        napi_value result;
161        // 1. 使用napi_load_module_with_info加载library
162        napi_status status = napi_load_module_with_info(env, "library", "com.example.application/entry", &result);
163        if (status != napi_ok) {
164           return nullptr;
165        }
166
167        napi_value testFn;
168        // 2. 使用napi_get_named_property获取test函数
169        napi_get_named_property(env, result, "test", &testFn);
170        // 3. 使用napi_call_function调用函数test
171        status = napi_call_function(env, result, testFn, 0, nullptr, nullptr);
172        if (status != napi_ok) {
173           return nullptr;
174        }
175
176        napi_value value;
177        napi_value key;
178        std::string keyStr = "value";
179        napi_create_string_utf8(env, keyStr.c_str(), keyStr.size(), &key);
180        // 4. 使用napi_get_property获取变量value
181        status = napi_get_property(env, result, key, &value);
182        if (status != napi_ok) {
183           return nullptr;
184        }
185        return result;
186    }
187    ```
188
189- **加载源码HSP模块**
190
191HSP包Index.ets文件如下:
192
193```javascript
194//hsp Index.ets
195let value = 123;
196function test() {
197    console.info("Hello World");
198}
199export {value, test};
200```
201
2021. 在oh-package.json5文件中配置dependencies项:
203
204    ```json
205    {
206        "dependencies": {
207            "hsp": "file:../hsp"
208        }
209    }
210    ```
211
2122. 在使用hsp的模块中,对build-profile.json5进行配置:
213
214    ```json
215    {
216        "buildOption" : {
217            "arkOptions" : {
218                "runtimeOnly" : {
219                    "packages": [
220                        "hsp"
221                    ]
222                }
223            }
224        }
225    }
226    ```
227
2283. 使用napi_load_module_with_info加载hsp,调用函数test以及获取变量value:
229
230    ```cpp
231    static napi_value loadModule(napi_env env, napi_callback_info info) {
232        napi_value result;
233        // 1. 使用napi_load_module_with_info加载hsp
234        napi_status status = napi_load_module_with_info(env, "hsp", "com.example.application/entry", &result);
235        if (status != napi_ok) {
236            return nullptr;
237        }
238
239        napi_value testFn;
240        // 2. 使用napi_get_named_property获取test函数
241        status = napi_get_named_property(env, result, "test", &testFn);
242        if (status != napi_ok) {
243            return nullptr;
244        }
245        // 3. 使用napi_call_function调用函数test
246        status = napi_call_function(env, result, testFn, 0, nullptr, nullptr);
247        if (status != napi_ok) {
248            return nullptr;
249        }
250
251        napi_value value;
252        napi_value key;
253        std::string keyStr = "value";
254        napi_create_string_utf8(env, keyStr.c_str(), keyStr.size(), &key);
255        // 4. 使用napi_get_property获取变量value
256        status = napi_get_property(env, result, key, &value);
257        if (status != napi_ok) {
258            return nullptr;
259        }
260        return result;
261    }
262    ```
263
264- **加载远程HAR模块名**
265
2661. 在oh-package.json5文件中配置dependencies项:
267
268    ```json
269    {
270        "dependencies": {
271            "@ohos/hypium": "1.0.16"
272        }
273    }
274    ```
275
2762. 在使用@ohos/hypium的模块中,对build-profile.json5进行配置:
277
278    ```json
279    {
280        "buildOption" : {
281            "arkOptions" : {
282                "runtimeOnly" : {
283                    "packages": [
284                        "@ohos/hypium"
285                    ]
286                }
287            }
288        }
289    }
290    ```
291
2923. 使用napi_load_module_with_info加载@ohos/hypium,获取DEFAULT变量:
293
294    ```cpp
295    static napi_value loadModule(napi_env env, napi_callback_info info) {
296        napi_value result;
297        // 1. 使用napi_load_module_with_info加载@ohos/hypium
298        napi_status status = napi_load_module_with_info(env, "@ohos/hypium", "com.example.application/entry", &result);
299        if (status != napi_ok) {
300           return nullptr;
301        }
302
303        napi_value key;
304        std::string keyStr = "DEFAULT";
305        napi_create_string_utf8(env, keyStr.c_str(), keyStr.size(), &key);
306        // 2. 使用napi_get_property获取DEFAULT变量
307        napi_value defaultValue;
308        napi_get_property(env, result, key, &defaultValue);
309        return result;
310    }
311    ```
312
313- **加载ohpm包名**
314
3151. 在oh-package.json5文件中配置dependencies项:
316
317    ```json
318    {
319        "dependencies": {
320            "json5": "^2.2.3"
321        }
322    }
323    ```
324
3252. 在使用json5的模块中,对build-profile.json5进行配置:
326
327    ```json
328    {
329        "buildOption" : {
330            "arkOptions" : {
331                "runtimeOnly" : {
332                    "packages": [
333                        "json5"
334                    ]
335                }
336            }
337        }
338    }
339    ```
340
3413. 用napi_load_module_with_info加载json5,调用函数stringify:
342
343    ```cpp
344    static napi_value loadModule(napi_env env, napi_callback_info info) {
345        napi_value result;
346        // 1. 使用napi_load_module_with_info加载json5
347        napi_status status = napi_load_module_with_info(env, "json5", "com.example.application/entry", &result);
348        if (status != napi_ok) {
349           return nullptr;
350        }
351
352        napi_value key;
353        std::string keyStr = "default";
354        napi_create_string_utf8(env, keyStr.c_str(), keyStr.size(), &key);
355        // 2. 使用napi_get_property获取default对象
356        napi_value defaultValue;
357        napi_get_property(env, result, key, &defaultValue);
358
359        napi_value stringifyFn;
360        // 3. 使用napi_get_named_property获取stringify函数
361        napi_get_named_property(env, defaultValue, "stringify", &stringifyFn);
362        // 4. 使用napi_call_function调用函数stringify
363        napi_value argStr;
364        std::string text = "call json5 stringify";
365        napi_create_string_utf8(env, text.c_str(), text.size(), &argStr);
366        napi_value args[1] = {argStr};
367
368        napi_value returnValue;
369        napi_call_function(env, defaultValue, stringifyFn, 1, args, &returnValue);
370        return result;
371    }
372    ```
373
374- **加载API模块**
375
376```cpp
377static napi_value loadModule(napi_env env, napi_callback_info info) {
378    // 1. 使用napi_load_module_with_info加载模块@ohos.hilog
379    napi_value result;
380    napi_status status = napi_load_module_with_info(env, "@ohos.hilog", nullptr, &result);
381    if (status != napi_ok) {
382        return nullptr;
383    }
384
385    // 2. 使用napi_get_named_property获取info函数
386    napi_value infoFn;
387    status = napi_get_named_property(env, result, "info", &infoFn);
388    if (status != napi_ok) {
389        return nullptr;
390    }
391
392    napi_value tag;
393    std::string formatStr = "test";
394    napi_create_string_utf8(env, formatStr.c_str(), formatStr.size(), &tag);
395
396    napi_value outputString;
397    std::string str = "Hello OpenHarmony";
398    napi_create_string_utf8(env, str.c_str(), str.size(), &outputString);
399
400    napi_value flag;
401    napi_create_int32(env, 0, &flag);
402
403    napi_value args[3] = {flag, tag, outputString};
404    // 3. 使用napi_call_function调用info函数
405    status = napi_call_function(env, result, infoFn, 3, args, nullptr);
406    if (status != napi_ok) {
407        return nullptr;
408    }
409    return result;
410}
411```
412
413- **加载Native库**
414
415libentry.soindex.d.ts文件如下:
416
417```javascript
418//index.d.ts
419export const add: (a: number, b: number) => number;
420```
421
4221. 在oh-package.json5文件中配置dependencies项:
423
424    ```json
425    {
426        "dependencies": {
427            "libentry.so": "file:../src/main/cpp/types/libentry"
428        }
429    }
430    ```
431
4322. 在使用libentry.so的模块中,对build-profile.json5进行配置:
433
434    ```json
435    {
436        "buildOption" : {
437            "arkOptions" : {
438                "runtimeOnly" : {
439                    "packages": [
440                        "libentry.so"
441                    ]
442                }
443            }
444        }
445    }
446    ```
447
4483. 用napi_load_module_with_info加载libentry.so,调用函数add:
449
450    ```cpp
451    static constexpr int INT_NUM_2 = 2; // int类型数值2
452    static constexpr int INT_NUM_3 = 3; // int类型数值3
453
454    static napi_value loadModule(napi_env env, napi_callback_info info) {
455        napi_value result;
456        // 1. 使用napi_load_module_with_info加载libentry.so
457        napi_status status = napi_load_module_with_info(env, "libentry.so", "com.example.application/entry", &result);
458        if (status != napi_ok) {
459            return nullptr;
460        }
461
462        napi_value addFn;
463        // 2. 使用napi_get_named_property获取add函数
464        napi_get_named_property(env, result, "add", &addFn);
465
466        napi_value a;
467        napi_value b;
468        napi_create_int32(env, INT_NUM_2, &a);
469        napi_create_int32(env, INT_NUM_3, &b);
470        napi_value args[2] = {a, b};
471        // 3. 使用napi_call_function调用函数add
472        napi_value returnValue;
473        napi_call_function(env, result, addFn, INT_NUM_2, args, &returnValue);
474        return result;
475    }
476    ```
477
478- **HAR加载HAR模块名**
479
480场景为har1加载har2,har2中的Index.ets文件如下:
481
482```javascript
483//har2 Index.ets
484let value = 123;
485function test() {
486  console.info("Hello OpenHarmony");
487}
488export {value, test};
489```
490
4911. 在har1中的oh-package.json5文件中配置dependencies项:
492
493    ```json
494    {
495        "dependencies": {
496            "har2": "file:../har2"
497        }
498    }
499    ```
500
5012. 在har1的build-profile.json5文件中进行配置:
502
503    ```json
504    {
505        "buildOption" : {
506            "arkOptions" : {
507                "runtimeOnly" : {
508                    "packages": [
509                        "har2"
510                    ]
511                }
512            }
513        }
514    }
515    ```
516
5173. 在har1中使用napi_load_module_with_info加载har2,调用test函数并获取value变量:
518
519    ```cpp
520    static napi_value loadModule(napi_env env, napi_callback_info info) {
521        napi_value result;
522        // 1. 使用napi_load_module_with_info加载har2,注意这里的moduleName为模块所在HAP包的moduleName
523        napi_status status = napi_load_module_with_info(env, "har2", "com.example.application/entry", &result);
524        if (status != napi_ok) {
525            return nullptr;
526        }
527
528        napi_value testFn;
529        // 2. 使用napi_get_named_property获取test函数
530        status = napi_get_named_property(env, result, "test", &testFn);
531        if (status != napi_ok) {
532            return nullptr;
533        }
534        // 3. 使用napi_call_function调用函数test
535        status = napi_call_function(env, result, testFn, 0, nullptr, nullptr);
536        if (status != napi_ok) {
537            return nullptr;
538        }
539
540        napi_value value;
541        napi_value key;
542        std::string keyStr = "value";
543        napi_create_string_utf8(env, keyStr.c_str(), keyStr.size(), &key);
544        // 4. 使用napi_get_property获取变量value
545        status = napi_get_property(env, result, key, &value);
546        if (status != napi_ok) {
547            return nullptr;
548        }
549        return result;
550    }
551    ```
552