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/ts。 43> 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 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.so的index.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