鸿蒙next开发:ArkTS语言-动态加载

往期鸿蒙全套实战文章必看:(附带鸿蒙全栈学习资料)


动态加载

动态import支持条件延迟加载,支持部分反射功能,可以提升页面的加载速度;动态import支持加载HSP模块/HAR模块/OHPM包/Native库等,并且HAR模块间只有变量动态import时还可以进行模块解耦。

技术适用场景介绍

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

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

业务扩展场景介绍

动态import在业务上除了能实现条件延迟加载,还可以实现部分反射功能。实例如下,HAP动态import HAR包harlibrary,并调用静态成员函数staticAdd()、成员函数instanceAdd(),以及全局方法addHarlibrary()。

// harlibrary's src/main/ets/utils/Calc.ets
export class Calc {
  public static staticAdd(a:number, b:number):number {
    let c = a + b;
    console.info('DynamicImport I am harlibrary in staticAdd, %d + %d = %d', a, b, c);
    return c;
  }

  public instanceAdd(a:number, b:number):number {
    let c = a + b;
    console.info('DynamicImport I am harlibrary in instanceAdd, %d + %d = %d', a, b, c);
    return c;
  }
}

export function addHarlibrary(a:number, b:number):number {
  let c = a + b;
  console.info('DynamicImport I am harlibrary in addHarlibrary, %d + %d = %d', a, b, c);
  return c;
}
// harlibrary's Index.ets
export { Calc, addHarlibrary } from './src/main/ets/utils/Calc'
// HAP's oh-package.json5
"dependencies": {
  "harlibrary": "file:../harlibrary"
}
// HAP's src/main/ets/pages/Index.ets
import('harlibrary').then((ns:ESObject) => {
  ns.Calc.staticAdd(8, 9);  // 调用静态成员函数staticAdd()
  let calc:ESObject = new ns.Calc();  // 实例化类Calc
  calc.instanceAdd(10, 11);  // 调用成员函数instanceAdd()
  ns.addHarlibrary(6, 7);  // 调用全局方法addHarlibrary()

  // 使用类、成员函数和方法的字符串名字进行反射调用
  let className = 'Calc';
  let methodName = 'instanceAdd';
  let staticMethod = 'staticAdd';
  let functionName = 'addHarlibrary';
  ns[className][staticMethod](12, 13);  // 调用静态成员函数staticAdd()
  let calc1:ESObject = new ns[className]();  // 实例化类Calc
  calc1[methodName](14, 15);  // 调用成员函数instanceAdd()
  ns[functionName](16, 17);  // 调用全局方法addHarlibrary()
});

动态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-

说明

1.当前所有import中使用的模块名是依赖方oh-package.json5的dependencies中的别名。

2.本地模块在依赖方的dependencies中配置的别名建议与moduleName以及packageName三者一致。moduleName指的是被依赖的HSP/HAR的module.json5中配置的名字,packageName指的是被依赖的HSP/HAR的oh-package.json5中配置的名字。

3.import一个模块名,实际的行为是import该模块的入口文件,一般为index.ets/ts。

动态import实现中的关键点

动态import常量表达式

动态import常量表达式是指动态import的入参为常量的场景。下面以HAP引用其他模块或API的示例来说明典型用法。

说明:本文示例代码中Index.ets等路径是按照当前DevEco Studio的模块配置设置,如后续发生变化,请调整位置及其他文件相对路径。

  • HAP常量动态import HAR模块名

    // HAR's Index.ets
    export function add(a:number, b:number):number {
      let c = a + b;
      console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c);
      return c;
    }
    // HAP's src/main/ets/pages/Index.ets
    import('myHar').then((ns:ESObject) => {
      console.info(ns.add(3, 5));
    });
    
    // 可使用 await 处理动态导入 (必须在 async 函数内使用)
    async function asyncDynamicImport() {
      let ns:ESObject = await import('myHar');
      console.info(ns.add(3, 5));
    }
    // HAP's oh-package.json5
    "dependencies": {
      "myHar": "file:../myHar"
    }
  • HAP常量动态import HAR模块文件路径

    // HAR's Index.ets
    export function add(a:number, b:number):number {
      let c = a + b;
      console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c);
      return c;
    }
    // HAP's src/main/ets/pages/Index.ets
    import('myHar/Index').then((ns:ESObject) => {
      console.info(ns.add(3, 5));
    });
    // HAP's oh-package.json5
    "dependencies": {
      "myHar": "file:../myHar"
    }
  • HAP常量动态import HSP模块名

    // HSP's Index.ets
    export function add(a:number, b:number):number {
      let c = a + b;
      console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c);
      return c;
    }
    // HAP's src/main/ets/pages/Index.ets
    import('myHsp').then((ns:ESObject) => {
      console.info(ns.add(3, 5));
    });
    // HAP's oh-package.json5
    "dependencies": {
      "myHsp": "file:../myHsp"
    }
  • HAP常量动态import HSP模块名文件路径

    // HSP's Index.ets
    export function add(a:number, b:number):number {
      let c = a + b;
      console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c);
      return c;
    }
    // HAP's src/main/ets/pages/Index.ets
    import('myHsp/Index').then((ns:ESObject) => {
      console.info(ns.add(3, 5));
    });
    // HAP's oh-package.json5
    "dependencies": {
      "myHsp": "file:../myHsp"
    }
  • HAP常量动态import远程HAR模块名

    // HAP's src/main/ets/pages/Index.ets
    import('@ohos/crypto-js').then((ns:ESObject) => {
      console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456));
    });
    // HAP's oh-package.json5
    "dependencies": {
      "@ohos/crypto-js": "2.0.3-rc.0"
    }
  • HAP常量动态import ohpm包

    // HAP's src/main/ets/pages/Index.ets
    import('json5').then((ns:ESObject) => {
      console.info('DynamicImport json5');
    });
    // HAP's oh-package.json5
    "dependencies": {
      "json5": "1.0.2"
    }
  • HAP常量动态import自己的单文件

    // HAP's src/main/ets/Calc.ets
    export function add(a:number, b:number):number {
      let c = a + b;
      console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c);
      return c;
    }
    // HAP's src/main/ets/pages/Index.ets
    import('../Calc').then((ns:ESObject) => {
      console.info(ns.add(3, 5));
    });
  • HAP常量动态import自己的Native库

    // libnativeapi.so's index.d.ts
    export const add: (a:number, b:number) => number;
    // HAP's src/main/ets/pages/Index.ets
    import('libnativeapi.so').then((ns:ESObject) => {
      console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3));
    });
    // HAP's oh-package.json5
    "dependencies": {
      "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi"
    }
  • HAP常量动态import加载API

    // HAP's src/main/ets/pages/Index.ets
    import('@system.app').then((ns:ESObject) => { ns.default.terminate(); });
    import('@system.router').then((ns:ESObject) => { ns.default.clear(); });
    import('@ohos.curves').then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); });
    import('@ohos.matrix4').then((ns:ESObject) => { ns.default.identity(); });
    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本模块自己的单文件:

// 变量动态import其他模块myHar
let harName = 'myHar';
import(harName).then(……);

// 变量动态import本模块自己的单文件src/main/ets/index.ets
let filePath = './Calc';
import(filePath).then(……);

对应的runtimeOnly配置:

"buildOption": {
  "arkOptions": {
    "runtimeOnly": {
      "packages": [ "myHar" ]  // 配置本模块变量动态import其他模块名,要求与dependencies中配置的名字一致。
      "sources": [ "./src/main/ets/utils/Calc.ets" ]  // 配置本模块变量动态import自己的文件路径,路径相对于当前build-profile.json5文件。
    }
  }
}

"runtimeOnly"的"packages":用于配置本模块变量动态import其他模块名,要求与dependencies中配置的名字一致。

"runtimeOnly"的"sources":用于配置本模块变量动态import自己的文件路径,路径相对于当前build-profile.json5文件。

2. 使用实例

  • HAP变量动态import HAR模块名

    // HAR's Index.ets
    export function add(a:number, b:number):number {
      let c = a + b;
      console.info('DynamicImport I am a HAR, %d + %d = %d', a, b, c);
      return c;
    }
    // HAP's src/main/ets/pages/Index.ets
    let packageName = 'myHar';
    import(packageName).then((ns:ESObject) => {
      console.info(ns.add(3, 5));
    });
    // HAP's oh-package.json5
    "dependencies": {
      "myHar": "file:../myHar"
    }
    // HAP's build-profile.json5
    "buildOption": {
      "arkOptions": {
        "runtimeOnly": {
          "packages": [
            "myHar"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
          ]
        }
      }
    }
  • HAP变量动态import HSP模块名

    // HSP's Index.ets
    export function add(a:number, b:number):number {
      let c = a + b;
      console.info('DynamicImport I am a HSP, %d + %d = %d', a, b, c);
      return c;
    }
    // HAP's src/main/ets/pages/Index.ets
    let packageName = 'myHsp';
    import(packageName).then((ns:ESObject) => {
      console.info(ns.add(3, 5));
    });
    // HAP's oh-package.json5
    "dependencies": {
      "myHsp": "file:../myHsp"
    }
    // HAP's build-profile.json5
    "buildOption": {
      "arkOptions": {
        "runtimeOnly": {
          "packages": [
            "myHsp"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
          ]
        }
      }
    }
  • HAP变量动态import远程HAR模块名

    // HAP's src/main/ets/pages/Index.ets
    let packageName = '@ohos/crypto-js';
    import(packageName).then((ns:ESObject) => {
      console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456));
    });
    // HAP's oh-package.json5
    "dependencies": {
      "@ohos/crypto-js": "2.0.3-rc.0"
    }
    // HAP's build-profile.json5
    "buildOption": {
      "arkOptions": {
        "runtimeOnly": {
          "packages": [
            "@ohos/crypto-js"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
          ]
        }
      }
    }
  • HAP变量动态import ohpm包

    // HAP's src/main/ets/pages/Index.ets
    let packageName = 'json5';
    import(packageName).then((ns:ESObject) => {
      console.info('DynamicImport json5');
    });
    // HAP's oh-package.json5
    "dependencies": {
      "json5": "1.0.2"
    }
    // HAP's build-profile.json5
    "buildOption": {
      "arkOptions": {
        "runtimeOnly": {
          "packages": [
            "json5"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
          ]
        }
      }
    }
  • HAP变量动态import自己的单文件

    // HAP's src/main/ets/Calc.ets
    export function add(a:number, b:number):number {
      let c = a + b;
      console.info('DynamicImport I am a HAP, %d + %d = %d', a, b, c);
      return c;
    }
    // HAP's src/main/ets/pages/Index.ets
    let filePath = '../Calc';
    import(filePath).then((ns:ESObject) => {
      console.info(ns.add(3, 5));
    });
    // HAP's build-profile.json5
    "buildOption": {
      "arkOptions": {
        "runtimeOnly": {
          "sources": [
            "./src/main/ets/Calc.ets"  // 仅用于使用变量动态import模块自己单文件场景,静态import或常量动态import无需配置。
          ]
        }
      }
    }
  • HAP变量动态import自己的Native库

    // libnativeapi.so's index.d.ts
    export const add: (a:number, b:number) => number;
    // HAP's src/main/ets/pages/Index.ets
    let soName = 'libnativeapi.so';
    import(soName).then((ns:ESObject) => {
      console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3));
    });
    // HAP's oh-package.json5
    "dependencies": {
      "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi"
    }
    // HAP's build-profile.json5
    "buildOption": {
      "arkOptions": {
        "runtimeOnly": {
          "packages": [
            "libnativeapi.so"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
          ]
        }
      }
    }
  • HAP变量动态import加载API

    // HAP's src/main/ets/pages/Index.ets
    let packageName = '@system.app';
    import(packageName).then((ns:ESObject) => { ns.default.terminate(); });
    packageName = '@system.router';
    import(packageName).then((ns:ESObject) => { ns.default.clear(); });
    packageName = '@ohos.curves';
    import(packageName).then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); });
    packageName = '@ohos.matrix4';
    import(packageName).then((ns:ESObject) => { ns.default.identity(); });
    packageName = '@ohos.hilog';
    import(packageName).then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); });

变量动态import加载API时无需配置runtimeOnly。

HAR模块间动态import依赖解耦

当应用包含多个HAR包,且HAR包之间依赖关系比较复杂。在DevEco Studio中配置依赖关系时,可能会形成循环依赖。这时,如果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。

// HAP's oh-package.json5
"dependencies": {
  "har1": "file:../har1"
}
// HAP's build-profile.json5
"buildOption": {
  "arkOptions": {
    "runtimeOnly": {
      "packages": [
        "har1"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
      ]
    }
  }
}
// HAP's src/main/ets/pages/Index.ets
let harName = 'har1';
import(harName).then((ns:ESObject) => {
  console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5));
});
// har1's oh-package.json5
"dependencies": {
  "har2": "file:../har2"
}
// har1's build-profile.json5
"buildOption": {
  "arkOptions": {
    "runtimeOnly": {
      "packages": [
        "har2"  // 仅用于使用变量动态import其他模块名场景,静态import或常量动态import无需配置。
      ]
    }
  }
}
// har1's Index.ets
export { addHar1 } from './src/main/ets/utils/Calc'
// har1's src/main/ets/utils/Calc.ets
export function addHar1(a:number, b:number):number {
  let c = a + b;
  console.info('DynamicImport I am har1, %d + %d = %d', a, b, c);

  let harName = 'har2';
  import(harName).then((ns:ESObject) => {
    console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5));
  });
  return c;
}
// har2's Index.ets
export { addHar2 } from './src/main/ets/utils/Calc'
// har2's src/main/ets/utils/Calc.ets
export function addHar2(a:number, b:number):number {
  let c = a + b;
  console.info('DynamicImport I am har2, %d + %d = %d', a, b, c);
  return c;
}

har1对har2的依赖dependencies和runtimeOnly配置转移到HAP中,har1不需要配置对har2的dependencies和runtimeOnly配置:

// HAP's oh-package.json5
"dependencies": {
  "har1": "file:../har1",
  "har2": "file:../har2"
}
// HAP's build-profile.json5
"buildOption": {
  "arkOptions": {
    "runtimeOnly": {
      "packages": [
        "har1",
        "har2"
      ]
    }
  }
}
// HAP's src/main/ets/pages/Index.ets
let harName = 'har1';
import(harName).then((ns:ESObject) => {
  console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5));
});
// har1's Index.ets
export { addHar1 } from './src/main/ets/utils/Calc'
// har1's src/main/ets/utils/Calc.ets
export function addHar1(a:number, b:number):number {
  let c = a + b;
  console.info('DynamicImport I am har1, %d + %d = %d', a, b, c);

  let harName = 'har2';
  import(harName).then((ns:ESObject) => {
    console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5));
  });
  return c;
}
// har2's Index.ets
export { addHar2 } from './src/main/ets/utils/Calc'
// har2's src/main/ets/utils/Calc.ets
export function addHar2(a:number, b:number):number {
  let c = a + b;
  console.info('DynamicImport I am har2, %d + %d = %d', a, b, c);
  return c;
}

<think>好的,我现在需要帮助用户在鸿蒙Next环境下,使用ArkTS实现基于HTTPS客户端的P12证书配置。首先,我需要整理用户提供的引用内容,看看里面有没有相关的信息。 引用[1]和[2]提到了生成.p12和.csr文件,以及申请应用证书.cer的过程。这说明用户可能已经生成了必要的证书文件,但需要知道如何在代码中配置这些证书。引用[3]提到配置代理设置,可能涉及网络请求的配置。引用[4]有关在module.json5中配置client_id,这可能涉及到应用的身份验证设置。引用[5]是阿里云的镜像链接,可能和网络请求或证书获取有关。 接下来,我需要考虑鸿蒙NextArkTS开发中HTTPS客户端的配置方法。通常,配置HTTPS客户端需要加载P12证书,设置SSL上下文,然后在网络请求中使用这个配置。根据鸿蒙的文档,可能需要使用系统提供的网络模块和相关API。 首先,用户需要将.p12证书文件放到工程的合适位置,比如rawfile目录。然后,在代码中读取这个证书文件,可能使用资源管理器。接着,配置SSL选项,指定证书路径、密码和别名。然后创建HttpClient实例时应用这些SSL配置。 需要注意证书的加载方式是否正确,密码和别名是否匹配生成证书时的设置。同时,处理可能的异常,比如证书加载失败或SSL握手错误。还要检查网络权限是否在config.json中正确配置,否则请求会被阻止。 可能的问题包括证书路径错误、密码不正确、SSL配置未正确应用等。需要确保所有步骤都按照文档指导进行,并参考官方示例代码。此外,用户可能需要将.cer证书配置到服务器端,或者处理双向认证的情况,但根据问题描述,用户主要关注客户端P12配置,因此重点放在客户端设置上。 最后,生成的相关问题需要围绕证书配置的步骤、常见错误、调试方法和证书管理展开,帮助用户进一步理解和解决问题。</think>在鸿蒙Next中使用ArkTS配置HTTPS客户端P12证书的步骤如下: ### 一、证书准备阶段 1. 将生成的`.p12`证书文件放入工程目录的`entry/src/main/resources/rawfile`目录下[^1][^2] 2. 在`module.json5`中添加网络权限声明: ```json "requestPermissions": [ { "name": "ohos.permission.INTERNET" } ] ``` ### 二、证书配置核心代码 ```typescript import http from '@ohos.net.http'; import { BusinessError } from '@ohos.base'; // 创建带证书的HttpClient let sslOpts: http.HttpSSLOptions = { certPath: 'entry/src/main/resources/rawfile/client.p12', // 证书路径 certPassword: 'your_password', // 生成证书时设置的密码 certAlias: 'client_cert' // 证书别名 }; let httpClient = http.createHttp({ sslOptions: sslOpts }); // 发起HTTPS请求示例 async function secureRequest() { let request: http.HttpRequestOptions = { method: http.RequestMethod.GET, url: 'https://api.example.com/secure-endpoint', extraData: "" }; try { let response = await httpClient.request(request); console.info('Response Code:' + response.responseCode); console.info('Response Data:' + response.result); } catch (error) { let err: BusinessError = error as BusinessError; console.error('Request Error:' + JSON.stringify(err)); } } ``` ### 三、关键配置说明 1. **证书加载**:系统会自动从指定路径加载PKCS12格式证书[^2] 2. **SSL握手**:使用TLS 1.2协议进行加密通信[^3] 3. **证书验证**:需要确保服务端证书链完整且可验证[^5] ### 四、常见问题处理 1. 证书路径错误:检查`certPath`是否与工程目录结构一致 2. SSL握手失败:确认证书密码和别名是否正确 3. 网络连接问题:检查`INTERNET`权限是否声明[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值