前言
本文跟隨上一篇RN拆包解決方案(一) bundle拆分,已打出common.bundle和patch.bundle文件為前提,引入工程項(xiàng)目中
iOS原生加載流程
RCTBridge開(kāi)放私有方法
@interface RCTBridge (ReactExecuteScript)
- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync;
@end
預(yù)先加載common包
在App項(xiàng)目完全啟動(dòng)完成后,可預(yù)先加載通用包仆邓,緩存到內(nèi)存中
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"common" withExtension:@"jsbundle"];
bridge = [[RCTBridge alloc] initWithBundleURL:jsCodeLocation
moduleProvider:nil
launchOptions:launchOptions];
加載業(yè)務(wù)包
當(dāng)用戶跳轉(zhuǎn)路由到某個(gè)RN頁(yè)面時(shí)加載patch部分
NSURL *jsCodeLocationBiz = [[NSBundle mainBundle] URLForResource:@"patch" withExtension:@"jsbundle"];
NSError *error = nil;
NSData *sourceBuz = [NSData dataWithContentsOfFile:jsCodeLocationBiz.path
options:NSDataReadingMappedIfSafe
error:&error];
[bridge.batchedBridge executeSourceCode:sourceBuz sync:NO];
需要注意的是,加載業(yè)務(wù)包的流程必須在common完全加載完畢后執(zhí)行佳魔,否則會(huì)出現(xiàn)加載異常;由于沒(méi)有提供加載完成的回調(diào)凭迹,只能通過(guò)偵聽(tīng)isLoading狀態(tài)變化來(lái)處理
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//加載common
while (bridge.isLoading) {//偵聽(tīng)common加載完成
}
//...
//加載業(yè)務(wù)包
});
綁定到視圖RCTRootView
RCTRootView *view = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:nil];
由此可見(jiàn)罚屋,加載common和patch都在同一個(gè)RCTBridge容器中執(zhí)行,最終綁定到RCTRootView展示
Android原生加載流程
使用ReactInstanceManager加載基礎(chǔ)包
首先需要初始化RN的運(yùn)行環(huán)境嗅绸。加載common使公共的模塊代碼優(yōu)先執(zhí)行脾猛,不會(huì)涉及視圖的綁定渲染
jsbundleFile = "assets://common.bundle";
final ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
.setApplication(application)
.addPackage(new MainReactPackage())
.setJSBundleFile(jsbundleFile);
ReactInstanceManager manager = builder.build();
按需加載業(yè)務(wù)包
通過(guò)ReactInstanceManager獲取CatalystInstance實(shí)例,此實(shí)例負(fù)責(zé)繼續(xù)加載業(yè)務(wù)包
ReactContext context = manager.getCurrentReactContext();
CatalystInstance instance = context.getCatalystInstance();
String source = "assets://patch.bundle";
((CatalystInstanceImpl)instance).loadScriptFromAssets(context.getAssets(), source,loadSynchronously);
同理鱼鸠,加載業(yè)務(wù)包需要在common加載完成后執(zhí)行
//加載common包
//...
if (!manager.hasStartedCreatingInitialContext()) {
manager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext context) {
manager.removeReactInstanceEventListener(this);
//...
//加載業(yè)務(wù)包
}
});
manager.createReactContextInBackground();
}
綁定到視圖
當(dāng)用戶進(jìn)入RN頁(yè)面時(shí)在activity層創(chuàng)建并顯示
reactRootView = new ReactRootView(this);
reactRootView.startReactApplication(manager, moduleName, null);
setContentView(reactRootView);
總結(jié)
RN拆包流程猛拴,最終還是要?dú)w功于 RN 基于 javascript 設(shè)計(jì)的靈活性。分步的執(zhí)行方式能夠讓我們輕松的將 Bundle 的加載蚀狰、視圖的渲染分步進(jìn)行愉昆,互不影響;