首先来讲一下,我们必须清楚React Native本质是使用React的思想
只不过React渲染的是真实的Dom,而React Native是使用虚拟Dom通过桥接调用原生的渲染
下面就从index.js的
AppRegistry.registerComponent到AppRegistry.runApplication来分析下程序运行的原理
几个核心概念
1、AppRegistry
RN程序入口,相当于main函数
2、RCTRootView
1、创建RCTBridge
2、初始化视图 ,监听RCTJavaScriptDidLoadNotification通知,执行AppRegistry.runApplication
3、RCTBridge(主要是其父类RCTCxxBridge在操作)
使用了多线程
4、ModuleRegistry
模块注册,js通过他查找资源
5、GCD
1、创建RCTBridge(NativeToJSBridge JSToNativeBridge ModuleRegistry),
2、加载js
3、(group_notify)前两者完成后发出资源加载完成通知RCTJavaScriptDidLoadNotification)
6、RCTJavaScriptDidLoadNotification
资源加载完成,桥接创建好之后发送执行程序通知(AppRegistry.runApplication)
备注:
1、创建了两条线程
js线程 执行js 创建bridge
jsmessage线程 js原生通信 NativeToJSBridge JSToNativeBridge
2、模块注册
ModuleRegistry
3、多线程
dispatch_group
4、通知
执行程序通知,目的是调用AppRegistry.runApplication
大致流程图
React Native
index.js
AppRegistry.registerComponent(appName, () => App);
AppRegistry 是运行所有 React Native 应用程序的 JS 入口点。
应用程序根组件需要通过 AppRegistry.registerComponent 来注册它们自身,
然后本地系统就可以加载应用程序的包,
准备就绪后会自动调用AppRegistry.runApplication就可以真正的运行该应用程序了。
* `AppRegistry` is the JS entry point to running all React Native apps. App
* root components should register themselves with
* `AppRegistry.registerComponent`, then the native system can load the bundle
* for the app and then actually run the app when it's ready by invoking
* `AppRegistry.runApplication`.
iOS端
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL: jsCodeLocation moduleName: sBundleView initialProperties: @{ @"initapp" : structjson } launchOptions: nil]; self.view = rootView;
React Native库
RCTRootView
- (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties launchOptions:(NSDictionary *)launchOptions { // 创建RCTBridge 内部通过父类RCTCxxBridge(C++)创建 // NativeToJSBridge JSToNativeBridge ModuleRegistry 加载执行js资源都在该方法完成 // 会发出js资源加载完成的通知RCTJavaScriptDidLoadNotification RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL moduleProvider:nil launchOptions:launchOptions]; // 初始化视图 // 最终在这个方法中调用runApplication,即index.js中的自动调用AppRegistry.runApplication // 本质是监听资源加载完成的通知,此通知发出时说明一切都已准备好 // 会监听RCTJavaScriptDidLoadNotification通知,然后调用runApplication,即AppRegistry.runApplication() return [self initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]; }
//初始化视图 - (instancetype)initWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties { RCTAssertMainQueue(); RCTAssert(bridge, @"A bridge instance is required to create an RCTRootView"); RCTAssert(moduleName, @"A moduleName is required to create an RCTRootView"); RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTRootView init]", nil); if (!bridge.isLoading) { [bridge.performanceLogger markStartForTag:RCTPLTTI]; } if (self = [super initWithFrame:CGRectZero]) { self.backgroundColor = [UIColor whiteColor]; _bridge = bridge; _moduleName = moduleName; _appProperties = [initialProperties copy]; _loadingViewFadeDelay = 0.25; _loadingViewFadeDuration = 0.25; _sizeFlexibility = RCTRootViewSizeFlexibilityNone; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(bridgeDidReload) name:RCTJavaScriptWillStartLoadingNotification object:_bridge]; // 监听资源加载完成通知RCTJavaScriptDidLoadNotification 调用javaScriptDidLoad方法 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(javaScriptDidLoad:) name:RCTJavaScriptDidLoadNotification object:_bridge]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hideLoadingView) name:RCTContentDidAppearNotification object:self]; #if TARGET_OS_TV self.tvRemoteHandler = [RCTTVRemoteHandler new]; for (NSString *key in [self.tvRemoteHandler.tvRemoteGestureRecognizers allKeys]) { [self addGestureRecognizer:self.tvRemoteHandler.tvRemoteGestureRecognizers[key]]; } #endif [self showLoadingView]; // Immediately schedule the application to be started. // (Sometimes actual `_bridge` is already batched bridge here.) [self bundleFinishedLoading:([_bridge batchedBridge] ?: _bridge)]; } RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @""); return self; }
- (void)javaScriptDidLoad:(NSNotification *)notification { RCTAssertMainQueue(); // Use the (batched) bridge that's sent in the notification payload, so the // RCTRootContentView is scoped to the right bridge RCTBridge *bridge = notification.userInfo[@"bridge"]; if (bridge != _contentView.bridge) { [self bundleFinishedLoading:bridge]; } } - (void)bundleFinishedLoading:(RCTBridge *)bridge { RCTAssert(bridge != nil, @"Bridge cannot be nil"); if (!bridge.valid) { return; } [_contentView removeFromSuperview]; _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds bridge:bridge reactTag:self.reactTag sizeFlexiblity:_sizeFlexibility]; // 运行程序 [self runApplication:bridge]; _contentView.passThroughTouches = _passThroughTouches; [self insertSubview:_contentView atIndex:0]; if (_sizeFlexibility == RCTRootViewSizeFlexibilityNone) { self.intrinsicContentSize = self.bounds.size; } } //运行程序 AppRegistry.runApplication() - (void)runApplication:(RCTBridge *)bridge { NSString *moduleName = _moduleName ?: @""; NSDictionary *appParameters = @{ @"rootTag": _contentView.reactTag, @"initialProps": _appProperties ?: @{}, }; RCTLogInfo(@"Running application %@ (%@)", moduleName, appParameters); [bridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[moduleName, appParameters] completion:NULL]; }
RCTBridge
//1 - (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleProvider:(RCTBridgeModuleListProvider)block launchOptions:(NSDictionary *)launchOptions { return [self initWithDelegate:nil bundleURL:bundleURL moduleProvider:block launchOptions:launchOptions]; } //2 - (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate bundleURL:(NSURL *)bundleURL moduleProvider:(RCTBridgeModuleListProvider)block launchOptions:(NSDictionary *)launchOptions { // if (self = [super init]) { _delegate = delegate; _bundleURL = bundleURL; _moduleProvider = block; _launchOptions = [launchOptions copy]; // [self setUp]; } return self; }
- (void)setUp { RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBridge setUp]", nil); _performanceLogger = [RCTPerformanceLogger new]; [_performanceLogger markStartForTag:RCTPLBridgeStartup]; [_performanceLogger markStartForTag:RCTPLTTI]; Class bridgeClass = self.bridgeClass; #if RCT_DEV RCTExecuteOnMainQueue(^{ RCTRegisterReloadCommandListener(self); }); #endif // Only update bundleURL from delegate if delegate bundleURL has changed NSURL *previousDelegateURL = _delegateBundleURL; _delegateBundleURL = [self.delegate sourceURLForBridge:self]; if (_delegateBundleURL && ![_delegateBundleURL isEqual:previousDelegateURL]) { _bundleURL = _delegateBundleURL; } // Sanitize the bundle URL _bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString]; // 弱引用父类 RCTCxxBridge self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self]; // RCTCxxBridge [self.batchedBridge start]; RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @""); }
RCTCxxBridge
- (void)start { RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge start]", nil); [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptWillStartLoadingNotification object:_parentBridge userInfo:@{@"bridge": self}]; // 创建js线程 // Set up the JS thread early _jsThread = [[NSThread alloc] initWithTarget:[self class] selector:@selector(runRunLoop) object:nil]; _jsThread.name = RCTJSThreadName; _jsThread.qualityOfService = NSOperationQualityOfServiceUserInteractive; #if RCT_DEBUG _jsThread.stackSize *= 2; #endif [_jsThread start]; // 多线程 dispatch_group 创建队列组prepareBridge // 1、初始化bridge ensureOnJavaScriptThread // 2、加载资源 loadSource dispatch_group_t prepareBridge = dispatch_group_create(); [_performanceLogger markStartForTag:RCTPLNativeModuleInit]; // 注册module 包括我们原生导出的模块RCTBridgeModule协议 RCT_EXTERN宏导出的 [self registerExtraModules]; // Initialize all native modules that cannot be loaded lazily (void)[self _initializeModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO]; [self registerExtraLazyModules]; [_performanceLogger markStopForTag:RCTPLNativeModuleInit]; // This doesn't really do anything. The real work happens in initializeBridge. // react实例对象 _reactInstance.reset(new Instance); __weak RCTCxxBridge *weakSelf = self; // Prepare executor factory (shared_ptr for copy into block) // 创建执行js的工厂方法 指定js引擎 std::shared_ptr<JSExecutorFactory> executorFactory; if (!self.executorClass) { if ([self.delegate conformsToProtocol:@protocol(RCTCxxBridgeDelegate)]) { id<RCTCxxBridgeDelegate> cxxDelegate = (id<RCTCxxBridgeDelegate>) self.delegate; executorFactory = [cxxDelegate jsExecutorFactoryForBridge:self]; } if (!executorFactory) { executorFactory = std::make_shared<JSCExecutorFactory>(nullptr); } } else { id<RCTJavaScriptExecutor> objcExecutor = [self moduleForClass:self.executorClass]; executorFactory.reset(new RCTObjcExecutorFactory(objcExecutor, ^(NSError *error) { if (error) { [weakSelf handleError:error]; } })); } // Dispatch the instance initialization as soon as the initial module metadata has // been collected (see initModules) // 初始化bridge dispatch_group_enter(prepareBridge); [self ensureOnJavaScriptThread:^{ [weakSelf _initializeBridge:executorFactory]; dispatch_group_leave(prepareBridge); }]; // Load the source asynchronously, then store it for later execution. // 加载资源 RCTJavaScriptLoader加载器 dispatch_group_enter(prepareBridge); __block NSData *sourceCode; [self loadSource:^(NSError *error, RCTSource *source) { if (error) { [weakSelf handleError:error]; } sourceCode = source.data; dispatch_group_leave(prepareBridge); } onProgress:^(RCTLoadingProgress *progressData) { #if RCT_DEV && __has_include("RCTDevLoadingView.h") // Note: RCTDevLoadingView should have been loaded at this point, so no need to allow lazy loading. RCTDevLoadingView *loadingView = [weakSelf moduleForName:RCTBridgeModuleNameForClass([RCTDevLoadingView class]) lazilyLoadIfNecessary:NO]; [loadingView updateProgress:progressData]; #endif }]; // Wait for both the modules and source code to have finished loading // 多线程结束 bridge创建完成 资源加载完成 dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{ RCTCxxBridge *strongSelf = weakSelf; if (sourceCode && strongSelf.loading) { // 执行代码 [strongSelf executeSourceCode:sourceCode sync:NO]; } }); RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @""); }
//初始化Bridage 在之前创建的js线程 - (void)_initializeBridge:(std::shared_ptr<JSExecutorFactory>)executorFactory { if (!self.valid) { return; } RCTAssertJSThread(); __weak RCTCxxBridge *weakSelf = self; // jsmessage js通信线程 用于跟js通讯 NativeToJSBridge JSToNativeBridge都在这个线程 _jsMessageThread = std::make_shared<RCTMessageThread>([NSRunLoop currentRunLoop], ^(NSError *error) { if (error) { [weakSelf handleError:error]; } }); RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge initializeBridge:]", nil); // This can only be false if the bridge was invalidated before startup completed if (_reactInstance) { #if RCT_DEV executorFactory = std::make_shared<GetDescAdapter>(self, executorFactory); #endif // 初始化Bridage核心方法 NativeToJSBridge JSToNativeBridge ModuleRegistry都在该方法完成 [self _initializeBridgeLocked:executorFactory]; #if RCT_PROFILE if (RCTProfileIsProfiling()) { _reactInstance->setGlobalVariable( "__RCTProfileIsProfiling", std::make_unique<JSBigStdString>("true")); } #endif } RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @""); } //jsMessageThread NativeToJSBridge JSToNativeBridge ModuleRegistry - (void)_initializeBridgeLocked:(std::shared_ptr<JSExecutorFactory>)executorFactory { std::lock_guard<std::mutex> guard(_moduleRegistryLock); // This is async, but any calls into JS are blocked by the m_syncReady CV in Instance // initializeBridge是在之前创建的线程执行的 // 创建ModuleRegistry(映射表,原生模块要映射到js,可以理解为对应表) 并返回给_reactInstance // _reactInstance利用ModuleRegistry,_jsMessageThread // 创建nativeToJSBridge对象(后续原生向js发送消息主要靠他), // NativeToJSBridge初始化的时候顺便把JSToNativeBridge也初始化了(后学js向原生发消息主要靠他), // 至此NativeToJSBridge JSToNativeBridge 通信(在_jsMessageThread线程)渠道打通 // 通信、映射表全部给了_reactInstance 至此初始化bridge完成 _reactInstance->initializeBridge( std::make_unique<RCTInstanceCallback>(self), executorFactory, _jsMessageThread, [self _buildModuleRegistryUnlocked]); _moduleRegistryCreated = YES; }
//回到主线程 发出RCTJavaScriptDidLoadNotification通知, - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync { // This will get called from whatever thread was actually executing JS. dispatch_block_t completion = ^{ // Log start up metrics early before processing any other js calls [self logStartupFinish]; // Flush pending calls immediately so we preserve ordering [self _flushPendingCalls]; // Perform the state update and notification on the main thread, so we can't run into // timing issues with RCTRootView dispatch_async(dispatch_get_main_queue(), ^{ // 发出RCTJavaScriptDidLoadNotification [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification object:self->_parentBridge userInfo:@{@"bridge": self}]; // Starting the display link is not critical to startup, so do it last [self ensureOnJavaScriptThread:^{ // Register the display link to start sending js calls after everything is setup [self->_displayLink addToRunLoop:[NSRunLoop currentRunLoop]]; }]; }); }; if (sync) { [self executeApplicationScriptSync:sourceCode url:self.bundleURL]; completion(); } else { [self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion]; } #if RCT_DEV if (self.devSettings.isHotLoadingAvailable && self.devSettings.isHotLoadingEnabled) { NSString *path = [self.bundleURL.path substringFromIndex:1]; // strip initial slash NSString *host = self.bundleURL.host; NSNumber *port = self.bundleURL.port; [self enqueueJSCall:@"HMRClient" method:@"enable" args:@[@"ios", path, host, RCTNullIfNil(port)] completion:NULL]; } #endif }
标签:bridge,moduleName,self,js,React,原理,bundleURL,AppRegistry,Native From: https://www.cnblogs.com/lijianyi/p/16789205.html