鸿蒙OpenHarmony【动态加载】 ArkTS运行

打印 上一主题 下一主题

主题 1006|帖子 1006|积分 3018

动态加载

动态import支持条件耽误加载,支持部分反射功能,可以提升页面的加载速率;动态import支持加载HSP模块/HAR模块/OHPM包/Native库等,而且HAR模块间只有变量动态import时还可以进行模块解耦。
技术实用场景先容

应用开发的有些场景中,假如希望根据条件导入模块或者按需导入模块,可以利用动态导入代替[静态导入]。下面是可能会必要动态导入的场景:


  • 当静态导入的模块很明显的降低了代码的加载速率且被利用的可能性很低,或者并不必要马上利用它。
  • 当静态导入的模块很明显的占用了大量的系统内存且被利用的可能性很低。
  • 当被导入的模块,在加载时并不存在,必要异步获取。
  • 当被导入的模块说明符,必要动态构建。(静态导入只能利用静态说明符)
  • 当被导入的模块有副作用(这里的副作用,可以理解为模块中会直接运行的代码),这些副作用只有在触发了某些条件才被必要时。
业务扩展场景先容

动态import在业务上除了能实现条件耽误加载,还可以实现部分反射功能。实例如下,HAP动态import HAR包harlibrary,并调用静态成员函数staticAdd()、成员函数instanceAdd(),以及全局方法addHarlibrary()。
  1. // harlibrary's src/main/ets/utils/Calc.ets
  2. export class Calc {
  3.   public static staticAdd(a:number, b:number):number {
  4.     let c = a + b;
  5.     console.info('DynamicImport I am harlibrary in staticAdd, %d + %d = %d', a, b, c);
  6.     return c;
  7.   }
  8.   public instanceAdd(a:number, b:number):number {
  9.     let c = a + b;
  10.     console.info('DynamicImport I am harlibrary in instanceAdd, %d + %d = %d', a, b, c);
  11.     return c;
  12.   }
  13. }
  14. export function addHarlibrary(a:number, b:number):number {
  15.   let c = a + b;
  16.   console.info('DynamicImport I am harlibrary in addHarlibrary, %d + %d = %d', a, b, c);
  17.   return c;
  18. }
复制代码
  1. // harlibrary's Index.ets
  2. export { Calc, addHarlibrary } from './src/main/ets/utils/Calc'
复制代码
  1. // HAP's oh-package.json5
  2. "dependencies": {
  3.   "harlibrary": "file:../harlibrary"
  4. }
复制代码
  1. // HAP's src/main/ets/pages/Index.ets
  2. import('harlibrary').then((ns:ESObject) => {
  3.   ns.Calc.staticAdd(8, 9);  // 调用静态成员函数staticAdd()
  4.   let calc:ESObject = new ns.Calc();  // 实例化类Calc
  5.   calc.instanceAdd(10, 11);  // 调用成员函数instanceAdd()
  6.   ns.addHarlibrary(6, 7);  // 调用全局方法addHarlibrary()
  7.   // 使用类、成员函数和方法的字符串名字进行反射调用
  8.   let className = 'Calc';
  9.   let methodName = 'instanceAdd';
  10.   let staticMethod = 'staticAdd';
  11.   let functionName = 'addHarlibrary';
  12.   ns[className][staticMethod](12, 13);  // 调用静态成员函数staticAdd()
  13.   let calc1:ESObject = new ns[className]();  // 实例化类Calc
  14.   calc1[methodName](14, 15);  // 调用成员函数instanceAdd()
  15.   ns[functionName](16, 17);  // 调用全局方法addHarlibrary()
  16. });
复制代码
动态import实现方案先容

动态import根据入参是常量还是变量,分成动态import常量表达式和动态import变量表达式两大特性规格。 以下是动态import支持的规格列表:
动态import场景动态import详细分类说明本地工程模块动态import模块内文件路径要求路径以./或…/开头本地工程模块动态import HSP模块名-本地工程模块动态import HSP模块文件路径暂仅支持动态import常量表达式,不支持动态import变量表达式本地工程模块动态import HAR模块名-本地工程模块动态import HAR模块文件路径暂仅支持动态import常量表达式,不支持动态import变量表达式远程包动态import远程HAR模块名-远程包动态import ohpm包名-API动态import @system.*-API动态import @ohos.*-API动态import @arkui-x.*-模块Native库动态import libNativeLibrary.so- 注:

  • 当前所有import中利用的模块名是依赖方oh-package.json5的dependencies中的别名;
  • 本地模块在依赖方的dependencies中设置的别名发起与moduleName以及packageName三者同等。moduleName指的是被依赖的HSP/HAR的module.json5中设置的名字,packageName指的是被依赖的HSP/HAR的oh-package.json5中设置的名字。
  • import一个模块名,实际的举动是import该模块的入口文件,一样平常为index.ets/ts。
动态import实现中的关键点

动态import常量表达式

动态import常量表达式是指动态import的入参为常量的场景。下面以HAP引用其他模块或API的示例来说明范例用法。
说明:本文示例代码中Index.ets等路径是按照当前DevEco Studio的模块设置设置,如后续发生厘革,请调解位置及其他文件相对路径。


  • HAP常量动态import HAR模块名
    1. // HAR's Index.ets
    2. export function add(a:number, b:number):number {
    3.   let c = a + b;
    4.   console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c);
    5.   return c;
    6. }
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. import('myHar').then((ns:ESObject) => {
    3.   console.info(ns.add(3, 5));
    4. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "myHar": "file:../myHar"
    4. }
    复制代码
  • HAP常量动态import HAR模块文件路径
    1. // HAR's Index.ets
    2. export function add(a:number, b:number):number {
    3.   let c = a + b;
    4.   console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c);
    5.   return c;
    6. }
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. import('myHar/Index').then((ns:ESObject) => {
    3.   console.info(ns.add(3, 5));
    4. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "myHar": "file:../myHar"
    4. }
    复制代码
  • HAP常量动态import HSP模块名
    1. // HSP's Index.ets
    2. export function add(a:number, b:number):number {
    3.   let c = a + b;
    4.   console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c);
    5.   return c;
    6. }
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. import('myHsp').then((ns:ESObject) => {
    3.   console.info(ns.add(3, 5));
    4. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "myHsp": "file:../myHsp"
    4. }
    复制代码
  • HAP常量动态import HSP模块名文件路径
    1. // HSP's Index.ets
    2. export function add(a:number, b:number):number {
    3.   let c = a + b;
    4.   console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c);
    5.   return c;
    6. }
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. import('myHsp/Index').then((ns:ESObject) => {
    3.   console.info(ns.add(3, 5));
    4. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "myHsp": "file:../myHsp"
    4. }
    复制代码
  • HAP常量动态import远程HAR模块名
    1. // HAP's src/main/ets/pages/Index.ets
    2. import('@ohos/crypto-js').then((ns:ESObject) => {
    3.   console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456));
    4. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "@ohos/crypto-js": "2.0.3-rc.0"
    4. }
    复制代码
  • HAP常量动态import ohpm包
    1. // HAP's src/main/ets/pages/Index.ets
    2. import('json5').then((ns:ESObject) => {
    3.   console.info('DynamicImport json5');
    4. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "json5": "1.0.2"
    4. }
    复制代码
  • HAP常量动态import自己的单文件
    1. // HAP's src/main/ets/Calc.ets
    2. export function add(a:number, b:number):number {
    3.   let c = a + b;
    4.   console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c);
    5.   return c;
    6. }
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. import('../Calc').then((ns:ESObject) => {
    3.   console.info(ns.add(3, 5));
    4. });
    复制代码
  • HAP常量动态import自己的Native库
    1. // libnativeapi.so's index.d.ts
    2. export const add: (a:number, b:number) => number;
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. import('libnativeapi.so').then((ns:ESObject) => {
    3.   console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3));
    4. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi"
    4. }
    复制代码
  • HAP常量动态import加载API
    1. // HAP's src/main/ets/pages/Index.ets
    2. import('@system.app').then((ns:ESObject) => { ns.default.terminate(); });
    3. import('@system.router').then((ns:ESObject) => { ns.default.clear(); });
    4. import('@ohos.curves').then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); });
    5. import('@ohos.matrix4').then((ns:ESObject) => { ns.default.identity(); });
    6. import('@ohos.hilog').then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); });
    复制代码
动态import变量表达式

DevEco Studio中模块间的依赖关系通过oh-package.json5中的dependencies进行设置。dependencies列表中所有模块默认都会进行安装(本地模块)或下载(远程模块),但是不会默认参与编译。HAP/HSP编译时会以入口文件(一样平常为Index.ets/ts)开始搜索依赖关系,搜索到的模块或文件才会加入编译。 在编译期,静态import和常量动态import可以被打包工具rollup及其插件辨认解析,加入依赖树中,参与到编译流程,终极天生方舟字节码。但是假如是变量动态import,该变量值可能必要进行运算或者外部传入才气得到,在编译态无法解析出其内容,也就无法加入编译。为了将这部分模块/文件加入编译,还必要额外增长一个runtimeOnly的buildOption设置,用于设置动态import的变量实际的模块名或者文件路径。
1. runtimeOnly字段schema设置格式
在HAP/HSP/HAR的build-profile.json5中的buildOption中增长runtimeOnly设置项,仅在通过变量动态import时设置,静态import和常量动态import无需设置;而且,通过变量动态import加载API时也无需设置runtimeOnly。 如下实例说明如何设置通过变量动态import其他模块,以及变量动态import本模块自己的单文件:
  1. // 变量动态import其他模块myHar
  2. let harName = 'myHar';
  3. import(harName).then(……);
  4. // 变量动态import本模块自己的单文件src/main/ets/index.ets
  5. let filePath = './Calc';
  6. import(filePath).then(……);
复制代码
对应的runtimeOnly设置:
  1. "buildOption": {
  2.   "arkOptions": {
  3.     "runtimeOnly": {
  4.       "packages": [ "myHar" ]  // 配置本模块变量动态import其他模块名,要求与dependencies中配置的名字一致。
  5.       "sources": [ "./src/main/ets/utils/Calc.ets" ]  // 配置本模块变量动态import自己的文件路径,路径相对于当前build-profile.json5文件。
  6.     }
  7.   }
  8. }
复制代码
“runtimeOnly"的"packages”:用于设置本模块变量动态import其他模块名,要求与dependencies中设置的名字同等。 “runtimeOnly"的"sources”:用于设置本模块变量动态import自己的文件路径,路径相对于当前build-profile.json5文件。
2. 利用实例


  • HAP变量动态import HAR模块名
    1. // HAR's Index.ets
    2. export function add(a:number, b:number):number {
    3.   let c = a + b;
    4.   console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c);
    5.   return c;
    6. }
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. let packageName = 'myHar';
    3. import(packageName).then((ns:ESObject) => {
    4.   console.info(ns.add(3, 5));
    5. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "myHar": "file:../myHar"
    4. }
    复制代码
    1. // HAP's build-profile.json5
    2. "buildOption": {
    3.   "arkOptions": {
    4.     "runtimeOnly": {
    5.       "packages": [
    6.         "myHar"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
    7.       ]
    8.     }
    9.   }
    10. }
    复制代码
  • HAP变量动态import HSP模块名
    1. // HSP's Index.ets
    2. export function add(a:number, b:number):number {
    3.   let c = a + b;
    4.   console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c);
    5.   return c;
    6. }
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. let packageName = 'myHsp';
    3. import(packageName).then((ns:ESObject) => {
    4.   console.info(ns.add(3, 5));
    5. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "myHsp": "file:../myHsp"
    4. }
    复制代码
    1. // HAP's build-profile.json5
    2. "buildOption": {
    3.   "arkOptions": {
    4.     "runtimeOnly": {
    5.       "packages": [
    6.         "myHsp"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
    7.       ]
    8.     }
    9.   }
    10. }
    复制代码
  • HAP变量动态import远程HAR模块名
    1. // HAP's src/main/ets/pages/Index.ets
    2. let packageName = '@ohos/crypto-js';
    3. import(packageName).then((ns:ESObject) => {
    4.   console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456));
    5. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "@ohos/crypto-js": "2.0.3-rc.0"
    4. }
    复制代码
    1. // HAP's build-profile.json5
    2. "buildOption": {
    3.   "arkOptions": {
    4.     "runtimeOnly": {
    5.       "packages": [
    6.         "@ohos/crypto-js"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
    7.       ]
    8.     }
    9.   }
    10. }
    复制代码
  • HAP变量动态import ohpm包
    1. // HAP's src/main/ets/pages/Index.ets
    2. let packageName = 'json5';
    3. import(packageName).then((ns:ESObject) => {
    4.   console.info('DynamicImport json5');
    5. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "json5": "1.0.2"
    4. }
    复制代码
    1. // HAP's build-profile.json5
    2. "buildOption": {
    3.   "arkOptions": {
    4.     "runtimeOnly": {
    5.       "packages": [
    6.         "json5"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
    7.       ]
    8.     }
    9.   }
    10. }
    复制代码
  • HAP变量动态import自己的单文件
    1. // HAP's src/main/ets/Calc.ets
    2. export function add(a:number, b:number):number {
    3.   let c = a + b;
    4.   console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c);
    5.   return c;
    6. }
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. let filePath = '../Calc';
    3. import(filePath).then((ns:ESObject) => {
    4.   console.info(ns.add(3, 5));
    5. });
    复制代码
    1. // HAP's build-profile.json5
    2. "buildOption": {
    3.   "arkOptions": {
    4.     "runtimeOnly": {
    5.       "sources": [
    6.         "./src/main/ets/Calc.ets"  // 仅用于使用变量动态import模块自己单文件场景,静态import或常量动态import无需配置。
    7.       ]
    8.     }
    9.   }
    10. }
    复制代码
  • HAP变量动态import自己的Native库
    1. // libnativeapi.so's index.d.ts
    2. export const add: (a:number, b:number) => number;
    复制代码
    1. // HAP's src/main/ets/pages/Index.ets
    2. let soName = 'libnativeapi.so';
    3. import(soName).then((ns:ESObject) => {
    4.   console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3));
    5. });
    复制代码
    1. // HAP's oh-package.json5
    2. "dependencies": {
    3.   "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi"
    4. }
    复制代码
    1. // HAP's build-profile.json5
    2. "buildOption": {
    3.   "arkOptions": {
    4.     "runtimeOnly": {
    5.       "packages": [
    6.         "libnativeapi.so"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
    7.       ]
    8.     }
    9.   }
    10. }
    复制代码
  • HAP变量动态import加载API
    1. // HAP's src/main/ets/pages/Index.ets
    2. let packageName = '@system.app';
    3. import(packageName).then((ns:ESObject) => { ns.default.terminate(); });
    4. packageName = '@system.router';
    5. import(packageName).then((ns:ESObject) => { ns.default.clear(); });
    6. packageName = '@ohos.curves';
    7. import(packageName).then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); });
    8. packageName = '@ohos.matrix4';
    9. import(packageName).then((ns:ESObject) => { ns.default.identity(); });
    10. packageName = '@ohos.hilog';
    11. import(packageName).then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); });
    复制代码
变量动态import加载API时无需设置runtimeOnly。
HAR模块间动态import依赖解耦

当应用包含多个HAR包,且HAR包之间依赖关系比较复杂。在IDE中设置依赖关系时,可能会形成循环依赖。这时,假如HAR之间的依赖关系中仅有变量动态import,可以将HAR包之间直接依赖关系转移到HAP/HSP中设置,HAR包之间无需设置依赖关系,从而到达HAR包间依赖解耦的目的。如下示意图:

HAR之间依赖关系转移到HAP/HSP后:

1. 利用限制


  • 仅限本地源码HAR包之间形成循环依赖时可利用该规避方案。
  • 被转移依赖的HAR之间只能通过变量动态import,不能有静态import或常量动态import。
  • 转移依赖时,dependencies和runtimeOnly依赖设置要同时转移。
  • HSP不支持转移依赖。即:HAP->HSP1->HSP2->HSP3,这里的HSP2和HSP3不能转移到HAP上面。
  • 转移依赖的整个链路上只能有HAR,不能跨越HSP转移。即:HAP->HAR1->HAR2->HSP->HAR3->HAR4。
    HAR1对HAR2的依赖可以转移到HAP上,HAR3对HAR4的依赖可以转移到HSP上,但是,不能将HAR3或HAR4转移到HAP上。
2. 利用实例
下面的实例HAP变量动态import HAR包har1,har1变量动态import另一个HAR包har2。
  1. // HAP's oh-package.json5
  2. "dependencies": {
  3.   "har1": "file:../har1"
  4. }
复制代码
  1. // HAP's build-profile.json5
  2. "buildOption": {
  3.   "arkOptions": {
  4.     "runtimeOnly": {
  5.       "packages": [
  6.         "har1"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
  7.       ]
  8.     }
  9.   }
  10. }
复制代码
  1. // HAP's src/main/ets/pages/Index.ets
  2. let harName = 'har1';
  3. import(harName).then((ns:ESObject) => {
  4.   console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5));
  5. });
复制代码
  1. // har1's oh-package.json5
  2. "dependencies": {
  3.   "har2": "file:../har2"
  4. }
复制代码
  1. // har1's build-profile.json5
  2. "buildOption": {
  3.   "arkOptions": {
  4.     "runtimeOnly": {
  5.       "packages": [
  6.         "har2"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
  7.       ]
  8.     }
  9.   }
  10. }
复制代码
  1. // har1's Index.ets
  2. export { addHar1 } from './src/main/ets/utils/Calc'
复制代码
  1. // har1's src/main/ets/utils/Calc.ets
  2. export function addHar1(a:number, b:number):number {
  3.   let c = a + b;
  4.   console.info('DynamicImport I am har1, %d + %d = %d', a, b, c);
  5.   let harName = 'har2';
  6.   import(harName).then((ns:ESObject) => {
  7.     console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5));
  8.   });
  9.   return c;
  10. }
复制代码
  1. // har2's Index.ets
  2. export { addHar2 } from './src/main/ets/utils/Calc'
复制代码
  1. // har2's src/main/ets/utils/Calc.ets
  2. export function addHar2(a:number, b:number):number {
  3.   let c = a + b;
  4.   console.info('DynamicImport I am har2, %d + %d = %d', a, b, c);
  5.   return c;
  6. }
复制代码
har1对har2的依赖dependencies和runtimeOnly设置转移到HAP中,har1不必要设置对har2的dependencies和runtimeOnly设置:
  1. // HAP's oh-package.json5
  2. "dependencies": {
  3.   "har1": "file:../har1",
  4.   "har2": "file:../har2"
  5. }
复制代码
  1. // HAP's build-profile.json5
  2. "buildOption": {
  3.   "arkOptions": {
  4.     "runtimeOnly": {
  5.       "packages": [
  6.         "har1",
  7.         "har2"
  8.       ]
  9.     }
  10.   }
  11. }
复制代码
  1. // HAP's src/main/ets/pages/Index.ets
  2. let harName = 'har1';
  3. import(harName).then((ns:ESObject) => {
  4.   console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5));
  5. });
复制代码
  1. // har1's Index.ets
  2. export { addHar1 } from './src/main/ets/utils/Calc'
  3. typescript
复制代码
  1. // har1's src/main/ets/utils/Calc.ets
  2. export function addHar1(a:number, b:number):number {
  3.   let c = a + b;
  4.   console.info('DynamicImport I am har1, %d + %d = %d', a, b, c);
  5.   let harName = 'har2';
  6.   import(harName).then((ns:ESObject) => {
  7.     console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5));
  8.   });
  9.   return c;
  10. }
复制代码
  1. // har2's Index.ets
  2. export { addHar2 } from './src/main/ets/utils/Calc'
  3. typescript
复制代码
  1. // har2's src/main/ets/utils/Calc.ets
  2. export function addHar2(a:number, b:number):number {
  3.   let c = a + b;
  4.   console.info('DynamicImport I am har2, %d + %d = %d', a, b, c);
  5.   return c;
  6. }
  7. ```**
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

滴水恩情

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表