• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 动态加载
2
3<!--Kit: ArkTS-->
4<!--Subsystem: ArkCompiler-->
5<!--Owner: @huyunhui1; @oh-rgx1; @zmw1-->
6<!--Designer: @ctw-ian-->
7<!--Tester: @kirl75; @zsw_zhushiwei-->
8<!--Adviser: @foryourself-->
9
10动态import支持条件延迟加载,支持部分反射功能,可以提升页面的加载速度;动态import支持加载HSP模块/HAR模块/OHPM包/Native库等,并且HAR模块间只有变量动态import时还可以进行模块解耦。
11
12## 技术适用场景介绍
13应用开发的有些场景中,如果希望根据条件导入模块或者按需导入模块,可以使用动态import代替[静态import](../quick-start/introduction-to-arkts.md#导入)。下面是可能会需要动态import的场景:
14
15* 当静态import的模块明显降低了代码的加载速度且很少被使用,或者并不需要马上使用它。
16* 当静态import的模块明显占用了大量的系统内存且很少被使用。
17* 当被导入的模块,在加载时并不存在,需要异步获取。
18* 当需要动态构建模块说明符时,应使用动态import。静态import仅支持静态说明符。
19* 当导入的模块存在副作用(即模块中包含直接运行的代码),这些副作用仅在满足特定条件时才需要。
20
21## 业务扩展场景介绍
22动态import在业务上除了能实现条件延迟加载,还可以实现部分反射功能。实例如下,HAP动态import HAR包harlibrary,并调用类Calc的静态成员函数staticAdd()、成员函数instanceAdd(),以及全局方法addHarLibrary()。
23```typescript
24// harlibrary's src/main/ets/utils/Calc.ets
25export class Calc {
26  public static staticAdd(a: number, b: number): number {
27    let c = a + b;
28    console.info('DynamicImport I am harlibrary in staticAdd, %d + %d = %d', a, b, c);
29    return c;
30  }
31
32  public instanceAdd(a: number, b: number): number {
33    let c = a + b;
34    console.info('DynamicImport I am harlibrary in instanceAdd, %d + %d = %d', a, b, c);
35    return c;
36  }
37}
38
39export function addHarLibrary(a: number, b: number): number {
40  let c = a + b;
41  console.info('DynamicImport I am harlibrary in addHarLibrary, %d + %d = %d', a, b, c);
42  return c;
43}
44```
45
46```typescript
47// harlibrary's Index.ets
48export { Calc, addHarLibrary } from './src/main/ets/utils/Calc'
49```
50
51```json5
52// HAP's oh-package.json5
53"dependencies": {
54  "harlibrary": "file:../harlibrary"
55}
56```
57
58```typescript
59// HAP's src/main/ets/pages/Index.ets
60import('harlibrary').then((ns:ESObject) => {
61  ns.Calc.staticAdd(8, 9);  // 调用静态成员函数staticAdd()
62  let calc:ESObject = new ns.Calc();  // 实例化类Calc
63  calc.instanceAdd(10, 11);  // 调用成员函数instanceAdd()
64  ns.addHarLibrary(6, 7);  // 调用全局方法addHarLibrary()
65
66  // 使用类、成员函数和方法的字符串名字进行反射调用
67  let className = 'Calc';
68  let methodName = 'instanceAdd';
69  let staticMethod = 'staticAdd';
70  let functionName = 'addHarLibrary';
71  ns[className][staticMethod](12, 13);  // 调用静态成员函数staticAdd()
72  let calc1:ESObject = new ns[className]();  // 实例化类Calc
73  calc1[methodName](14, 15);  // 调用成员函数instanceAdd()
74  ns[functionName](16, 17);  // 调用全局方法addHarLibrary()
75});
76```
77
78## 动态import实现方案介绍
79动态import根据入参是常量或变量,分为动态import常量表达式和动态import变量表达式两大特性规格。
80以下是动态import支持的规格列表:
81
82| 动态import场景 | 动态import详细分类             | 说明                                                     |
83| :------------- | :----------------------------- | :------------------------------------------------------- |
84| 本地工程模块   | 动态import模块内文件路径       | 要求路径以./或../开头。                                    |
85| 本地工程模块   | 动态import HSP模块名           | -                                                        |
86| 本地工程模块   | 动态import HSP模块文件路径     | -                                                        |
87| 本地工程模块   | 动态import HAR模块名           | -                                                        |
88| 本地工程模块   | 动态import HAR模块文件路径     | -                                                        |
89| 远程包         | 动态import远程HAR模块名        | -                                                        |
90| 远程包         | 动态import ohpm包名            | -                                                        |
91| API            | 动态import @system.*           | -                                                        |
92| API            | 动态import @ohos.*             | -                                                        |
93| API            | 动态import @arkui-x.*          | -                                                        |
94| 模块Native库   | 动态import libNativeLibrary.so | -                                                        |
95
96>**说明:**
97>
98> 1.当前所有import中使用的模块名都是依赖方oh-package.json5文件中dependencies项的别名。</br>
99> 2.本地模块在依赖方的dependencies中配置的别名建议与moduleName以及packageName三者一致。moduleName指的是被依赖的HSP/HARmodule.json5中配置的名字,packageName指的是被依赖的HSP/HARoh-package.json5中配置的名字。</br>
100> 3.import一个模块名,实际的行为是import该模块的入口文件,一般为Index.ets/ts101
102## 动态import实现中的关键点
103
104### 动态import常量表达式
105
106动态import常量表达式是指动态import的入参为常量的场景。下面以HAP引用其他模块的API的示例来说明典型用法。
107
108本文示例代码中的路径,如Index.ets,是根据当前DevEco Studio的模块配置设置的。如果后续有变化,请调整文件的位置和相对路径。
109
110- **HAP常量动态import HAR模块名**
111
112  ```typescript
113  // HAR's Index.ets
114  export function add(a: number, b: number): number {
115    let c = a + b;
116    console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c);
117    return c;
118  }
119  ```
120
121  ```typescript
122  // HAP's src/main/ets/pages/Index.ets
123  import('myhar').then((ns:ESObject) => {
124    console.info('DynamicImport ns.add(3, 5) = %d', ns.add(3, 5));
125  });
126
127  // 可使用 await 处理动态import (必须在 async 函数内使用)
128  async function asyncDynamicImport() {
129    let ns:ESObject = await import('myhar');
130    console.info('DynamicImport ns.add(3, 5) = %d', ns.add(3, 5));
131  }
132  ```
133
134  ```json5
135  // HAP's oh-package.json5
136  "dependencies": {
137    "myhar": "file:../myhar"
138  }
139  ```
140
141- **HAP常量动态import HAR模块文件路径**
142
143  ```typescript
144  // HAR's Index.ets
145  export function add(a: number, b: number): number {
146    let c = a + b;
147    console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c);
148    return c;
149  }
150  ```
151
152  ```typescript
153  // HAP's src/main/ets/pages/Index.ets
154  import('myhar/Index').then((ns:ESObject) => {
155    console.info('DynamicImport ns.add(3, 5) = %d', ns.add(3, 5));
156  });
157  ```
158
159  ```json5
160  // HAP's oh-package.json5
161  "dependencies": {
162    "myhar": "file:../myhar"
163  }
164  ```
165
166- **HAP常量动态import HSP模块名**
167
168  ```typescript
169  // HSP's Index.ets
170  export function add(a: number, b: number): number {
171    let c = a + b;
172    console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c);
173    return c;
174  }
175  ```
176
177  ```typescript
178  // HAP's src/main/ets/pages/Index.ets
179  import('myhsp').then((ns:ESObject) => {
180    console.info('DynamicImport ns.add(3, 5) = %d', ns.add(3, 5));
181  });
182  ```
183
184  ```json5
185  // HAP's oh-package.json5
186  "dependencies": {
187    "myhsp": "file:../myhsp"
188  }
189  ```
190
191- **HAP常量动态import HSP模块名文件路径**
192
193  ```typescript
194  // HSP's Index.ets
195  export function add(a: number, b: number): number {
196    let c = a + b;
197    console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c);
198    return c;
199  }
200  ```
201
202  ```typescript
203  // HAP's src/main/ets/pages/Index.ets
204  import('myhsp/Index').then((ns:ESObject) => {
205    console.info('DynamicImport ns.add(3, 5) = %d', ns.add(3, 5));
206  });
207  ```
208
209  ```json5
210  // HAP's oh-package.json5
211  "dependencies": {
212    "myhsp": "file:../myhsp"
213  }
214  ```
215
216- **HAP常量动态import远程HAR模块名**
217
218  ```typescript
219  // HAP's src/main/ets/pages/Index.ets
220  import('@ohos/crypto-js').then((ns:ESObject) => {
221    console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456));
222  });
223  ```
224
225  ```json5
226  // HAP's oh-package.json5
227  "dependencies": {
228    "@ohos/crypto-js": "2.0.3-rc.0"
229  }
230  ```
231
232- **HAP常量动态import ohpm包**
233
234  ```typescript
235  // HAP's src/main/ets/pages/Index.ets
236  import('json5').then((ns:ESObject) => {
237    console.info('DynamicImport json5');
238  });
239  ```
240
241  ```json5
242  // HAP's oh-package.json5
243  "dependencies": {
244    "json5": "1.0.2"
245  }
246  ```
247
248- **HAP常量动态import自己的单文件**
249
250  ```typescript
251  // HAP's src/main/ets/Calc.ets
252  export function add(a: number, b: number): number {
253    let c = a + b;
254    console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c);
255    return c;
256  }
257  ```
258
259  ```typescript
260  // HAP's src/main/ets/pages/Index.ets
261  import('../Calc').then((ns:ESObject) => {
262    console.info('DynamicImport ns.add(3, 5) = %d', ns.add(3, 5));
263  });
264  ```
265
266- **HAP常量动态import自己的Native库**
267
268  ```typescript
269  // libnativeapi.so's index.d.ts
270  export const add: (a: number, b: number) => number;
271  ```
272
273  ```typescript
274  // HAP's src/main/ets/pages/Index.ets
275  import('libnativeapi.so').then((ns:ESObject) => {
276    console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3));
277  });
278  ```
279
280  ```json5
281  // HAP's oh-package.json5
282  "dependencies": {
283    "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi"
284  }
285  ```
286
287- **HAP常量动态import加载API**
288
289  ```typescript
290  // HAP's src/main/ets/pages/Index.ets
291  import('@system.app').then((ns:ESObject) => { ns.default.terminate(); });
292  import('@system.router').then((ns:ESObject) => { ns.default.clear(); });
293  import('@ohos.curves').then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); });
294  import('@ohos.matrix4').then((ns:ESObject) => { ns.default.identity(); });
295  import('@ohos.hilog').then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); });
296  ```
297
298### 动态import变量表达式
299
300DevEco Studio中模块间的依赖关系通过oh-package.json5中的dependencies字段进行配置。dependencies列表中所有的模块默认都会进行安装(本地模块)或下载(远程模块),但是不会默认参与编译。HAP/HSP编译时会以入口文件(一般为Index.ets/Index.ts)开始搜索依赖关系,搜索到的模块或文件才会加入编译。
301在编译期,静态import和常量动态import可以被打包工具rollup及其插件识别解析,加入依赖树中,参与编译流程,最终生成方舟字节码。但是,如果是变量动态import,该变量值可能需要进行运算或外部传入才能得到,在编译态无法解析其内容,也就无法加入编译。为了将这部分模块/文件加入编译,还需要额外增加一个runtimeOnly的buildOption配置,用于指定动态import的变量实际的模块名或文件路径。
302
303**1. runtimeOnly字段schema配置格式**
304
305HAP/HSP/HARbuild-profile.json5中的buildOption中增加runtimeOnly配置项,仅在通过变量动态import时配置,静态import和常量动态import无需配置;并且,通过变量动态import加载API时也无需配置runtimeOnly。如下实例说明如何配置通过变量动态import其他模块,以及变量动态import本模块自己的单文件:
306
307```typescript
308// 变量动态import其他模块myhar
309let harName = 'myhar';
310import(harName).then((obj: ESObject) => {
311    console.info('DynamicImport I am a har');
312})
313
314// 变量动态import本模块自己的单文件src/main/ets/index.ets
315let filePath = './utils/Calc';
316import(filePath).then((obj: ESObject) => {
317    console.info('DynamicImport I am a file');
318})
319```
320
321对应的runtimeOnly配置:
322
323```json
324"buildOption": {
325  "arkOptions": {
326    "runtimeOnly": {
327      "packages": [ "myhar" ],  // 配置本模块变量动态import其他模块名,要求与dependencies中配置的名字一致。
328      "sources": [ "./src/main/ets/utils/Calc.ets" ]  // 配置本模块变量动态import自己的文件路径,路径相对于当前build-profile.json5文件。
329    }
330  }
331}
332```
333
334"runtimeOnly"的"packages":用于配置本模块变量动态import其他模块名,要求与dependencies中配置的名字一致。
335"runtimeOnly"的"sources":用于配置本模块变量动态import自己的文件路径,路径相对于当前build-profile.json5文件。
336
337**2. 使用实例**
338
339- **HAP变量动态import HAR模块名**
340
341  ```typescript
342  // HAR's Index.ets
343  export function add(a: number, b: number): number {
344    let c = a + b;
345    console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c);
346    return c;
347  }
348  ```
349  ```typescript
350  // HAP's src/main/ets/pages/Index.ets
351  let packageName = 'myhar';
352  import(packageName).then((ns:ESObject) => {
353    console.info('DynamicImport ns.add(3, 5) = %d', ns.add(3, 5));
354  });
355  ```
356  ```json5
357  // HAP's oh-package.json5
358  "dependencies": {
359    "myhar": "file:../myhar"
360  }
361  ```
362  ```json5
363  // HAP's build-profile.json5
364  "buildOption": {
365    "arkOptions": {
366      "runtimeOnly": {
367        "packages": [
368          "myhar"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
369        ]
370      }
371    }
372  }
373  ```
374
375- **HAP变量动态import HSP模块名**
376
377  ```typescript
378  // HSP's Index.ets
379  export function add(a: number, b: number): number {
380    let c = a + b;
381    console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c);
382    return c;
383  }
384  ```
385  ```typescript
386  // HAP's src/main/ets/pages/Index.ets
387  let packageName = 'myhsp';
388  import(packageName).then((ns:ESObject) => {
389    console.info('DynamicImport ns.add(3, 5) = %d', ns.add(3, 5));
390  });
391  ```
392  ```json5
393  // HAP's oh-package.json5
394  "dependencies": {
395    "myhsp": "file:../myhsp"
396  }
397  ```
398  ```json5
399  // HAP's build-profile.json5
400  "buildOption": {
401    "arkOptions": {
402      "runtimeOnly": {
403        "packages": [
404          "myhsp"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
405        ]
406      }
407    }
408  }
409  ```
410
411- **HAP变量动态import远程HAR模块名**
412
413  ```typescript
414  // HAP's src/main/ets/pages/Index.ets
415  let packageName = '@ohos/crypto-js';
416  import(packageName).then((ns:ESObject) => {
417    console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456));
418  });
419  ```
420  ```json5
421  // HAP's oh-package.json5
422  "dependencies": {
423    "@ohos/crypto-js": "2.0.3-rc.0"
424  }
425  ```
426  ```json5
427  // HAP's build-profile.json5
428  "buildOption": {
429    "arkOptions": {
430      "runtimeOnly": {
431        "packages": [
432          "@ohos/crypto-js"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
433        ]
434      }
435    }
436  }
437  ```
438
439- **HAP变量动态import ohpm包**
440
441  ```typescript
442  // HAP's src/main/ets/pages/Index.ets
443  let packageName = 'json5';
444  import(packageName).then((ns:ESObject) => {
445    console.info('DynamicImport json5');
446  });
447  ```
448  ```json5
449  // HAP's oh-package.json5
450  "dependencies": {
451    "json5": "1.0.2"
452  }
453  ```
454  ```json5
455  // HAP's build-profile.json5
456  "buildOption": {
457    "arkOptions": {
458      "runtimeOnly": {
459        "packages": [
460          "json5"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
461        ]
462      }
463    }
464  }
465  ```
466
467- **HAP变量动态import自己的单文件**
468
469  ```typescript
470  // HAP's src/main/ets/Calc.ets
471  export function add(a: number, b: number): number {
472    let c = a + b;
473    console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c);
474    return c;
475  }
476  ```
477  ```typescript
478  // HAP's src/main/ets/pages/Index.ets
479  let filePath = '../Calc';
480  import(filePath).then((ns:ESObject) => {
481    console.info('DynamicImport ns.add(3, 5) = %d', ns.add(3, 5));
482  });
483  ```
484  ```json5
485  // HAP's build-profile.json5
486  "buildOption": {
487    "arkOptions": {
488      "runtimeOnly": {
489        "sources": [
490          "./src/main/ets/Calc.ets"  // 仅用于使用变量动态import模块自己单文件场景,静态import或常量动态import无需配置。
491        ]
492      }
493    }
494  }
495  ```
496
497- **HAP变量动态import自己的Native库**
498
499  ```typescript
500  // libnativeapi.so's index.d.ts
501  export const add: (a: number, b: number) => number;
502  ```
503  ```typescript
504  // HAP's src/main/ets/pages/Index.ets
505  let soName = 'libnativeapi.so';
506  import(soName).then((ns:ESObject) => {
507    console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3));
508  });
509  ```
510  ```json5
511  // HAP's oh-package.json5
512  "dependencies": {
513    "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi"
514  }
515  ```
516  ```json5
517  // HAP's build-profile.json5
518  "buildOption": {
519    "arkOptions": {
520      "runtimeOnly": {
521        "packages": [
522          "libnativeapi.so"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
523        ]
524      }
525    }
526  }
527  ```
528
529- **HAP变量动态import加载API**
530
531  ```typescript
532  // HAP's src/main/ets/pages/Index.ets
533  let packageName = '@system.app';
534  import(packageName).then((ns:ESObject) => { ns.default.terminate(); });
535  packageName = '@system.router';
536  import(packageName).then((ns:ESObject) => { ns.default.clear(); });
537  packageName = '@ohos.curves';
538  import(packageName).then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); });
539  packageName = '@ohos.matrix4';
540  import(packageName).then((ns:ESObject) => { ns.default.identity(); });
541  packageName = '@ohos.hilog';
542  import(packageName).then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); });
543  ```
544通过变量动态import加载API时无需配置runtimeOnly。
545
546### HAR模块间动态import依赖解耦
547当应用包含多个HAR包,HAR包之间的依赖关系比较复杂。在DevEco Studio中配置依赖关系时,可能会形成循环依赖。这时,如果HAR之间的依赖关系中仅有变量动态import,可以将HAR包之间直接依赖关系转移到HAP/HSP中配置,HAR包之间无需配置依赖关系,从而达到HAR包间依赖解耦的目的。如下示意图:
548
549![变量动态import HAR包形成循环依赖](figures/dynamicimport1.png)
550
551HAR之间的依赖关系转移至HAP/HSP后:
552
553![变量动态import HAR包依赖转移到HAP](figures/dynamicimport2.png)
554
555
556**使用限制**
557- 仅限在本地源码HAR包之间存在循环依赖时,使用该规避方案。
558- 被转移依赖的HAR之间只能通过变量动态import,不能有静态import或常量动态import。
559- 转移依赖时,需同时转移**dependencies**和**runtimeOnly**依赖配置。
560- HSP不支持转移依赖。即:HAP->HSP1->HSP2->HSP3,这里的HSP2和HSP3不能转移到HAP上面。
561- 转移依赖的整个链路上只能有HAR包,不能跨越HSP转移。即:HAP->HAR1->HAR2->HSP->HAR3->HAR4,HAR1对HAR2的依赖可以转移到HAP上,HAR3对HAR4的依赖可以转移到HSP上。但是,不能将HAR3或HAR4转移到HAP上。
562- 如果引用了其他工程模块、远程包或集成HSP,需确保**useNormalizedOHMUrl**配置一致,同时设置为true或false,否则可能导致运行错误:**Cannot find dynamic-import module library**。
563
564
565**使用实例**
566
567下面的实例通过在单向依赖HAP->HAR1->HAR2->HAR3之上增加依赖HAR2->HAR1、HAR3->HAR1,形成了循环依赖。
568
569![变量动态import HAR包形成循环依赖](figures/dynamicimport1.png)
570
571```typescript
572// HAP's src/main/ets/pages/Index.ets
573let harName = 'har1'
574import(harName).then((ns: ESObject) => {
575  console.info('[DynamicImport] hap -> har1, 0 + 1 = ' + ns.classHar1.add(0, 1));
576})
577
578// HAR1's src/main/ets/utils/Calc.ets
579export class classHar1 {
580  static isImportedHar2: boolean = false;
581
582  static add(a: number, b: number): number {
583    const c = a + b;
584    console.info('[DynamicImport] classHar1.add(), %d + %d = %d', a, b, c);
585
586    if (!classHar1.isImportedHar2) {
587      const harName = 'har2';
588      import(harName).then((ns: ESObject) => {
589        classHar1.isImportedHar2 = true;
590        console.info('[DynamicImport] har1 -> har2, 1 + 2 = ' + ns.classHar2.add(1, 2));
591      })
592    }
593
594    return c;
595  }
596}
597// HAR1's Index.ets
598export { classHar1 } from './src/main/ets/utils/Calc';
599
600// HAR2's src/main/ets/utils/Calc.ets
601export class classHar2 {
602  static isImportedHar1: boolean = false;
603  static isImportedHar3: boolean = false;
604
605  static add(a: number, b: number): number {
606    const c = a + b;
607    console.info('[DynamicImport] classHar2.add(), %d + %d = %d', a, b, c);
608
609    if (!classHar2.isImportedHar1) {
610      const harName = 'har1';
611      import(harName).then((ns: ESObject) => {
612        classHar2.isImportedHar1 = true;
613        console.info('[DynamicImport] har2 -> har1, 2 + 1 = ' + ns.classHar1.add(2, 1));
614      })
615    }
616
617    if (!classHar2.isImportedHar3) {
618      const harName = 'har3';
619      import(harName).then((ns: ESObject) => {
620        classHar2.isImportedHar3 = true;
621        console.info('[DynamicImport] har2 -> har3, 2 + 3 = ' + ns.classHar3.add(2, 3));
622      })
623    }
624
625    return c;
626  }
627}
628// HAR2's Index.ets
629export { classHar2 } from './src/main/ets/utils/Calc';
630
631// HAR3's src/main/ets/utils/Calc.ets
632export class classHar3 {
633  static isImportedHar1: boolean = false;
634
635  static add(a: number, b: number): number {
636    const c = a + b;
637    console.info('[DynamicImport] classHar3.add(), %d + %d = %d', a, b, c);
638
639    if (!classHar3.isImportedHar1) {
640      const harName = 'har1';
641      import(harName).then((ns: ESObject) => {
642        classHar3.isImportedHar1 = true;
643        console.info('[DynamicImport] har3 -> har1, 3 + 1 = ' + ns.classHar1.add(3, 1));
644      })
645    }
646
647    return c;
648  }
649}
650// HAR3's Index.ets
651export { classHar3 } from './src/main/ets/utils/Calc';
652```
653
654若未对HAR之间的**dependencies**和**runtimeOnly**配置进行依赖解耦,ohpm无法解决循环依赖,依赖安装失败。
655
656```json5
657// HAP's oh-package.json5
658"dependencies": {
659  "har1": "file:../har1"
660}
661// HAP's build-profile.json5
662"buildOption": {
663  "arkOptions": {
664    "runtimeOnly": {
665      "packages": [ // 仅用于变量动态加载的场景,静态加载或常量动态加载无需配置。
666        "har1"
667      ]
668    }
669  }
670}
671
672// HAR1's oh-package.json5
673"dependencies": {
674  "har2": "file:../har2"
675}
676// HAR1's build-profile.json5
677"buildOption": {
678  "arkOptions": {
679    "runtimeOnly": {
680      "packages": [ // 仅用于变量动态加载的场景,静态加载或常量动态加载无需配置。
681        "har2"
682      ]
683    }
684  }
685}
686
687// HAR2's oh-package.json5
688"dependencies": {
689  "har1": "file:../har1",
690  "har3": "file:../har3"
691}
692// HAR2's build-profile.json5
693"buildOption": {
694  "arkOptions": {
695    "runtimeOnly": {
696      "packages": [ // 仅用于变量动态加载的场景,静态加载或常量动态加载无需配置。
697        "har1",
698        "har3"
699      ]
700    }
701  }
702}
703
704// HAR3's oh-package.json5
705"dependencies": {
706  "har1": "file:../har1",
707}
708// HAR3's build-profile.json5
709"buildOption": {
710  "arkOptions": {
711    "runtimeOnly": {
712      "packages": [ // 仅用于变量动态加载的场景,静态加载或常量动态加载无需配置。
713        "har1"
714      ]
715    }
716  }
717}
718```
719
720**对应的报错信息如下:**
721
722```text
723ohpm ERROR: Run install command failed
724Error: 00618005 Invalid Dependency
725Error Message: Invalid dependency har2@~\Coupled\har2 -> har2@1.0.0.
726
727Try the following:
728The name of an indirect dependency cannot be the same as the module name.
729```
730
731将HAR之间的**dependencies**和**runtimeOnly**配置转移到HAP中,解耦了包间循环依赖,程序能够正确运行。
732
733```json5
734// HAP's oh-package.json5
735"dependencies": {
736  "har1": "file:../har1",
737  "har2": "file:../har2",
738  "har3": "file:../har3"
739}
740// HAP's build-profiles.json5
741"buildOption": {
742  "arkOptions": {
743    "runtimeOnly": {
744      "packages" : [ // 仅用于变量动态加载的场景,静态加载或常量动态加载无需配置。
745        "har1",
746        "har2",
747        "har3"
748      ]
749    }
750  }
751}
752
753// HAR1's oh-package.json5
754"dependencies": {}
755// HAR1's build-profile.json5
756"buildOption": {}
757
758// HAR2's oh-package.json5
759"dependencies": {}
760// HAR2's build-profile.json5
761"buildOption": {}
762
763// HAR3's oh-package.json5
764"dependencies": {}
765// HAR3's build-profile.json5
766"buildOption": {}
767```
768
769**对应的运行日志如下:**
770
771```text
772[DynamicImport] classHar1.add(), 0 + 1 = 1
773[DynamicImport] hap -> har1, 0 + 1 = 1
774[DynamicImport] classHar2.add(), 1 + 2 = 3
775[DynamicImport] har1 -> har2, 1 + 2 = 3
776[DynamicImport] classHar1.add(), 2 + 1 = 3
777[DynamicImport] har2 -> har1, 2 + 1 = 3
778[DynamicImport] classHar3.add(), 2 + 3 = 5
779[DynamicImport] har2 -> har3, 2 + 3 = 5
780[DynamicImport] classHar1.add(), 3 + 1 = 4
781[DynamicImport] har3 -> har1, 3 + 1 = 4
782```
783