React Native跨平台鸿蒙开发高级应用原理:生成bundle 文件,多Bundle打包
本文探讨了React Native多Bundle打包方案在HarmonyOS NEXT应用中的实现。通过Metro工具将应用拆分为基础包和业务包,解决单个Bundle过大导致的加载性能问题。文章详细介绍了多Bundle应用的资源加载机制,包括Bundle路径配置和RN实例创建过程,并提出了当前存在的资源路径设置未生效问题。同时分析了多Bundle应用的预加载必要性,给出了ArkTS环境下基于Loa
多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
}

更多推荐


所有评论(0)