实现加载 jsbundle 的方法 RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions 实现加载 jsbundle 的方法 利用 RCTBridge 初始化一个 RCTRootView 将 RCTRootView 赋值给 UIViewController 的 view 实现 UI 的挂载 分析到这里,我们发现 RCTRootView.m 只是实现了对 RCTBridge 的的各种事件监听,并不是初始化的核心,所以我们就又要转到 RCTBridge 这个文件上去。 3.RCTBridge.m RCTBridge.m 里,初始化的调用路径有些长,全贴源码有些长,总之最后调用的是 (void)setUp,核心代码如下: - (Class)bridgeClass { 因为在 RCTBridge 里调用了 RTCxxBridge 的 start 方法,我们就从 start 方法来看看做了些什么。
NSString*)module { self = [super initWithFrame:frame]; if (self){ _moduleName = module; RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil]; _rootView = [[RCTRootView = self.bounds; return self; } #pragma mark -- RCTBridgeDelegate -- - (NSURL *)sourceURLForBridge:(RCTBridge platform=ios&dev=true&withoutSource=true"]; } - (void)loadSourceForBridge:(RCTBridge *)bridge withBlock // ReactNativePackageManager.m #import "ReactNativePackageManager.h" #import "RCTBridge.h" #import "
AppRegistry.registerComponent("App", () => App); AppRegistry.registerComponent("App2", () => App2); iOS中OC核心代码: 设置RCTBridge 的代理 实现代理方法- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge; 最关键的:通常情况下我们会使用initWithBundleURL创建一个RCTRootView React/RCTRootView.h> @interface ViewController ()<RCTBridgeDelegate> @property (nonatomic, strong) RCTBridge *bridge; @end @implementation ViewController - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge platform=ios"];// 模拟器 } - (void)viewDidLoad { [super viewDidLoad]; _bridge = [[RCTBridge alloc
RCTBridge的创建:在RN示例中RCTRootView创建时,会创建RCTBridge相关实例。 RCTBridge的销毁:当RCTRootView销毁时,则会释放RCTBridge实例。 Turbo Modules的生命周期也是与RCTBridge绑定的,当RCTBridge对象被释放时,会发通知清除当前创建的Turbo Modules实例。 在官方示例的AppDelete及RCTRootView创建时都会创建RCTBridge对象,也就是说Turbo Modules的生命周期是与RCTRootView的生命周期一致。 上迁移)中都有初始化,所以当RCTRootView释放时其对应的RCTBridge对象也会被释放,此刻就会发通知然后清除缓存。 而在AppDelete中的didFinishLaunching方法中,创建了RCTBridge对象,并将RCTBridge实例已参数的形式传入了RCTRootView的构造方法中。
实现加载 jsbundle 的方法 RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions 实现加载 jsbundle 的方法 利用 RCTBridge 初始化一个 RCTRootView 将 RCTRootView 赋值给 UIViewController 的 view 实现 UI 的挂载 分析到这里,我们发现 RCTRootView.m 只是实现了对 RCTBridge 的的各种事件监听,并不是初始化的核心,所以我们就又要转到 RCTBridge 这个文件上去。 3.RCTBridge.m RCTBridge.m 里,初始化的调用路径有些长,全贴源码有些长,总之最后调用的是 (void)setUp,核心代码如下: - (Class)bridgeClass { 因为在 RCTBridge 里调用了 RTCxxBridge 的 start 方法,我们就从 start 方法来看看做了些什么。
一、拆包关键之bridge 1、bridge 原理 RCTBridge 是对 JavaScriptCore 中 Bridge 的封装,每个 bridge 都是一个独立的js环境。 这里需要考虑两个问题: RCTBridge 需要叠加加载 bundle 由于 RCTBridge 并没有提供多次加载 bunlde 的方法,但是其内部又一个私有方法实现了该功能( - (void)executeSourceCode 然而 RCTBridge 并没有提供回调入口,但是其有一个 loading 属性,我们可以使用一个 do while 循环阻塞线程,直到 loading 为 false 代码再往下走 如果是多 bridge
没什么可说的,本片文章我们主要窥探初始化RCTBridge和RCTRootView。 RCTBridge初始化 RCTBridge初始化是重点也是难点,虽然叫RCTBridge的初始化,但实际上不仅仅是初始化一个RCTBridge实例那么简单,在其背后还有RCTCxxBridge、NativeToJSBridge 先来看一下appDelegate中调用的RCTBridge的初始化的源码实现: // RCTBridge.m - (instancetype)initWithDelegate:(id<RCTBridgeDelegate 的初始化方法是创建了一个RCTBridge实例,通过调用私有方法setUp对bridge进行配置。 在APPDelegate的启动方法中创建了RCTBridge和一个RCTRootView,然后在RCTBridge中创建了一个名为batchedBridge的RCTCxxBridge实例,并调用了self.batchedBridge
RCTRootView.m - (void)javaScriptDidLoad:(NSNotification *)notification { RCTAssertMainQueue(); RCTBridge [self runApplication:bridge]; // 省略添加一个RCTRootContentView... } - (void)runApplication:(RCTBridge 通过上面类图可以看出,RCTBridge依赖了RCTModuleData。RCTModuleData依赖(实现)了RCTBridgeModule协议。 且RCTViewManager、RCTUIManager、NativeModule都依赖了RCTBridge。 // RCTUIManager.m - (void)setBridge:(RCTBridge *)bridge { _bridge = bridge; // 省略若干行代码... //
请参考下面代码中的注释: /* ios/SplashScreen/AppDelegate.m */ #import "AppDelegate.h" #import <React/RCTBridge.h NSDictionary *)launchOptions { #ifdef FB_SONARKIT_ENABLED InitializeFlipper(application); #endif RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; RCTRootView *rootView [RNSplashScreen show]; return YES; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG
1) 创建RN的桥接管理类(单例)实现RCTBridgeDelegate协议 // .h文件 #import <React/RCTBridgeModule.h> #import <React/RCTBridge.h RCTBridgeDelegate> + (instancetype)shareInstance; // 全局唯一的bridge @property (nonatomic, readonly, strong) RCTBridge } return _instance; } -(instancetype)init{ if (self = [super init]) { _bridge = [[RCTBridge #pragma mark - RCTBridgeDelegate - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { # if DEBUG 在初始化RCTRootView之时,通过initWithBridge:(RCTBridge *)bridge方法将要展示的页面路径通过属性传递给RN。
OC层实现这个类的是RCTBridge,目前的代码是使用RCTContextExecutor作为具体的执行者。 这个机制,可以通过查看 -[RCTBridge enqueueJSCall:args:]这个函数的Callers来验证(这个函数是OC层调用JS的入口函数),它的 Callers包括了:Device Event 通信协议 JS调用OC的协议,是-[RCTBridge setUp]的时候,通过 RCTRemoteModulesConfig()创建并传给JS层的。
module.exports = ActionSheetIOS; 我们看到关键是引入底层oc的方式,其他的跟写前端没啥差别 然后再看RCTActionSheetManager的实现 #import "RCTBridge.h
RCTRootView.m - (void)javaScriptDidLoad:(NSNotification *)notification { RCTAssertMainQueue(); RCTBridge contentView.bridge) { [self bundleFinishedLoading:bridge]; } } - (void)bundleFinishedLoading:(RCTBridge [self runApplication:bridge]; // 省略添加一个RCTRootContentView... } - (void)runApplication:(RCTBridge completion:NULL]; } 上面的源码(iOS)可以看出 RCTRootView 其实做了这些事情: 创建了负责 React Native 和 Native 通信的 RCTBridge
然后,修改AppDelegate.m文件,添加如下代码: - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [
之间的mapping关系; 2、打业务模块包的时候,判断,如果已经在mapping文件里面的模块,不要打包到业务包中 改造页面加载流程: 1、因为要能够后台加载,所以需分离UI和JS加载引擎<iOS-RCTBridge 从上文的优化可以看出,缓存了common.js部分的JS执行引擎(iOS RCTBridge, Android ReactInstanceManager),页面加载可以大大提速,那对于已经被业务使用过的
让我们再来看看RCTRegisterModule函数的实现(该函数定义在RCTBridge.m中): static NSMutableArray<Class> *RCTModuleClasses; void
(2)对于iOS来说,在RN的iOS端源码中,RCTBridge的PerformanceLogger会在重要事件的起始和结束时设置tag并统计耗时,通过它可以直接取出各项事件的耗时数据。 ? (需要注意的是,往往重新加载bundle文件的时候bundle文件位置可能不是原来那个位置) (1)对于iOS来说,在RN的iOS端源码中RCTBridge提供了reload方法来重新加载bundle文件
让我们再来看看RCTRegisterModule函数的实现(该函数定义在RCTBridge.m中): static NSMutableArray<Class> *RCTModuleClasses; void
这些内容是可以在运行时获取到的,在RCTBridge.m的RCTExportedMethodsByModuleID()方法里获取这些内容,提取每个方法的类名和方法名,就完成了提取模块里暴露给JS方法的工作
改造页面加载流程: 因为要能够后台加载,所以需分离 UI 和 JS 加载引擎\<iOS-RCTBridge, Android-ReactInstanceManager\>; 进入业务 RN 页面时候,获取预加载好的 从上文的优化可以看出,缓存了common.js部分的 JS 执行引擎(iOS RCTBridge, Android ReactInstanceManager),页面加载可以大大提速,那对于已经被业务使用过的