多Bundle打包

​ 在开发过程中,有些开发场景应用的 bundle 文件过大,出现 bundle 文件加载缓慢,无法按需加载 bundle 等情况,这时就需要进行拆包打包,生成多 bundle 的过程。为了实现多 bundle 打包的过程,我们选择使用 Metro 工具对工程进行拆包打包。

bundle 代码拆分类型:基础包与业务包。

  • 基础包:将一些重复的 JS 代码与第三方依赖库打成一个包。
  • 业务包:根据应用内的不同业务逻辑,拆分出一个或多个包。

应用中包括多个bundle时如何加载不同路径的资源文件

基于RN开发的HamonyNext应用,具有多个bundle包,现在希望不同的bundle加载不同的资源文件。bundle放在…/entry/src/main/resources/rawfile/bundle路径下,可以通过类似以下方式加载不同的bundle

new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle/metro/bundle.harmony.js')

在这里插入图片描述

每个bundle对应的资源文件放在…/entry/src/main/resources/rawfile/asset下,但在初始化rninstance的时候指定assetsDest最终无效,还是只能读取rawfile下作为默认的资源文件路径

 const metroInstance = await this.rnohCoreContext.createAndRegisterRNInstance({
   createRNPackages: createRNPackages,
   enableNDKTextMeasuring: true,
   enableBackgroundExecutor: true,
   enableCAPIArchitecture: ENABLE_CAPI_ARCHITECTURE,
   arkTsComponentNames: arkTsComponentNames,
   assetsDest:'assets/metro/.'
 });

尝试了在打包的时候添加–assets-dest ‘./harmony/entry/src/main/resources/rawfile/assets/metro’,按照想要的目录去加载对应资源文件。


单bundle应用很好理解:整个应用基于一个bundle。多bundle应用有通过"A-RN跳转到B-RN"方式的实现,或是界面干脆由多个bundle共同绘制。

对于多bundle应用来说往往需要考虑bundle的预加载。如果跳转对象bundle体积较大在看到界面前会有一定时间的白屏等待(多个bundle已经事先预下载到本地)。虽然可以通过加载动画等方式来缓解,但不能满足部分对延迟较为敏感的客户。鸿蒙上对于多bundle的预加载处理较为简单,下面来看看ArkTS下是如何加载多个bundle的。

还是以index.ets为入口页面进行说明。

在aboutToAppear生命周期中进行单/多个bundle的创建。其中rnohCoreContext是RN自身的上下文,我们加载的bundle都在它下面。

@StorageLink('RNOHCoreContext') rnohCoreContext: RNOHCoreContext | undefined = undefined
aboutToAppear() {
......
// 多bundle
if (!this.rnohCoreContext) return;
this.loadMetroBundle()
}

loadMetroBundle方法是bundle加载的实现,通过LoadManager进行了封装,其中_rnInstance始终指向当前显示的RN对象用于原生和RN的交互(项目中不存在多个bundle同时活跃的情况)。注意assetsDest的设置,在例子中两个bundle的资源文件指向了不同的路径,这里面存在一个未解决问题,下面会提到。

LoadManager.ets封装的loadMetroBundle用于创建RN实例与上下文。注意enableCAPIArchitecture的设置,现在只有ture这个选项,HarmonyOS NEXT由于不再支持java,turboModule在原生端只有cpp实现。

    public static async loadMetroBundle(bundle:BundleBean): Promise<boolean> {
    const rnohCoreContext: RNOHCoreContext | undefined = AppStorage.get('RNOHCoreContext')
    if (LoadManager.shouldResetMetroInstance && rnohCoreContext && !LoadManager.instanceMap.has(bundle.appName)) {
      let  rnInstance = await rnohCoreContext.createAndRegisterRNInstance({
        createRNPackages: createRNPackages,
        enableNDKTextMeasuring: true,
        enableBackgroundExecutor: true,
        enableCAPIArchitecture: ENABLE_CAPI_ARCHITECTURE,
        arkTsComponentNames: arkTsComponentNames,
        assetsDest:bundle.assetsDest
      });
      LoadManager.ctx = new RNComponentContext(
        RNOHContext.fromCoreContext(rnohCoreContext!, rnInstance),
        wrapBuilder(buildCustomComponent),
        wrapBuilder(buildRNComponentForTag),
        new Map()
      );

      let provider:JSBundleProvider |null = null;
      if(bundle.debugMode){
        provider = new MetroJSBundleProvider();
      }else {
        provider = new ResourceJSBundleProvider(rnohCoreContext.uiAbilityContext.resourceManager, bundle.bundlePath);
      }

      await rnInstance.runJSBundle(provider)

      const jsBundleExecutionStatus: string = rnInstance.getBundleExecutionStatus(provider.getURL()) as string
      console.log(" getBundleExecutionStatus = ", jsBundleExecutionStatus);
      // LoadManager.shouldResetMetroInstance = false
      if (jsBundleExecutionStatus === "DONE") {
        // 缓存bundle
        LoadManager.loadedBundle.add(bundle);
        // 缓存rnInstance
        LoadManager.instanceMap.set(bundle.appName,rnInstance);
        return true
      } else {
        return false
      }
    }
    return true
  }

在这里插入图片描述

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐