React Native 资源包拆分实践(二)

Native加载多个 JS Bundle

客户端会先加载公共基础包,加载完成后,再加载业务包。

安卓端加载多个 JS Bundle

先加载公共基础包,安卓端需要在创建 ReactNativeHost 实例的时候重写 getBundleAssetName()方法或 getJSBundleFile() 方法,返回公共基础包的本地路径,然后再调用 ReactNativeHost实例的 getReactInstanceManager() 方法触发 ReactInstanceManager 实例的创建,最后调用 createReactContextInBackground() 方法来触发 ReactNative 的初始化流程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 安卓端代码示例 - 加载公共基础包
ReactNativeHost RNHost = new ReactNativeHost(application) {
@Nullable
@Override
protected String getBundleAssetName() {
return "Assets目录下的common.android.bundle路径";
}
@Nullable
@Override
protected String getJSBundleFile() {
return "本地磁盘中的common.android.bundle路径";
}
}
ReactInstanceManager bridge = RNHost.getReactInstanceManager();
if (!bridge.hasStartedCreatingInitialContext()) {
bridge.createReactContextInBackground();
}

安卓端ReactNative在加载完公共基础包后,会回调ReactInstanceManager 实例中注册的所有 ReactInstanceEventListeneronReactContextInitialized() 方法,可以在onReactContextInitialized() 回调方法中加载业务包。

通过使用上文中的 ReactInstanceManager 实例的 getCurrentReactContext() 获取到当前的 ReactContext 上下文对象,再调用上下文对象的 getCatalystInstance() 方法获取 CatalystInstance 实例,最终调用该实例的 loadScriptFromFile() 方法完成业务包的加载。

1
2
3
4
5
// 安卓端代码示例 - 加载业务包
ReactContext context = RNHost.getReactInstanceManager().getCurrentReactContext();
CatalystInstance catalyst = context.getCatalystInstance();
String fileName = "本地业务包business.android.bundle路径"
catalyst.loadScriptFromFile(fileName, fileName, false);
iOS端加载多个 JS Bundle

先加载公共基础包,iOS端可以使用 RCTBridge 的实例化方法 [RCTBridge initWithBundleURL: moduleProvider: launchOptions:] ,传入公共基础包的本地路径。

1
2
3
// iOS端代码示例 - 加载公共基础包
NSURL *commonBundleURL = [[NSBundle mainBundle] URLForResource:@"common" withExtension:@"ios.bundle"];//公共基础包路径
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:commonBundleURL moduleProvider:nil launchOptions:launchOptions];

iOS端ReactNative在加载完公共基础包后,会发送 RCTJavaScriptDidLoadNotification 事件全局通知。
可以通过注册监听 RCTJavaScriptDidLoadNotification 事件,然后加载业务包,可以使用RCTCxxBridgeexecuteSourceCode() 方法来加载。这里需要注意的是: executeSourceCode() 方法是 RCTCxxBridge 的私有方法。可以用过 Category 的方式将executeSourceCode() 方法暴露出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
// iOS端代码示例 - Category暴露私有方法
@interface RCTBridge (MyCustomerBridge)
- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync;
@end

// iOS端代码示例 - 加载业务包
NSURL *businessBundleURL = [[NSBundle mainBundle] URLForResource:@"business" withExtension:@"ios.bundle"];//业务包路径
NSError *error = nil;
NSData *sourceData = [NSData dataWithContentsOfURL:businessBundleURL options:NSDataReadingMappedIfSafe error:&error];
if (error) {
return
}
[bridge.batchedBridge executeSourceCode:sourceData sync:NO];