从RN的架构来看,之所以它在java和js层中间使用一层C++来实现桥接,主要是为了让RN的代码在两个平台中尽量复用。IOS中OC可以和C++任意的相互调用,而在Android中,Java和C++之间也可以通过JNI来进行相互的调用。在早期的RN版本中C++的代码还不是很多,越到后来C++层的代码占比越大,这说明facebook逐步在将所有的可以共用的代码逐渐迁移到C++中,而不需要oc和java写两套。当然由于平台的差异性,很多东西还是得分开。在RN源码的文件夹的组织结构中可以看到,其中React文件夹下就是使用OC编写的IOS端的代码,ReactAndroid是用Java写的Android的,而ReactCommon则是公用的C++代码。
IOS的很多流程其实和Android端的类似,主要流程如下:
React Native各个版本间的代码差异不小,现在网上流行的代码解读,基本上都是0.4X或者以前的,虽然从原理上讲大同小异,但是在实现过程中却又不小的变化。本文就以一个基于0.5X版本的官方示例Awesomeproject来看一下它从启动到最终绘制的整个过程。
启动流程
首先,AppDelegate获取js文件的url地址
其次,创建RCTRootView
最后,将RCTRootView设置为rootViewController的rootView显示
其中最主要的东西都是在创建RootView过程中实现的
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"AwesomeProject"
initialProperties:nil
launchOptions:launchOptions];
继续跟进下去发现,RCTRootView的创建过程主要是首先创建RTCBridge,然后使用RTCBridge初始化RCTRootView。
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
launchOptions:(NSDictionary *)launchOptions
{
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL
moduleProvider:nil
launchOptions:launchOptions];
return [self initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
}
这个方法首先创建RCTBridge,然后初拥bridge初始化。
我们首先分析RCTBridge的创建过程:
我们跟踪RTCBridge的调用他的最终实现如下
- (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;
}
setUp方法
- (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];
self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self];
[self.batchedBridge start];
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
其中我们可以看到bridgeClass的类型是RCTCxxBridge
- (Class)bridgeClass
{
return [RCTCxxBridge class];
}
因此setUp方法中的 [self.batchedBridge start];实际调用的是[RCTCxxBridge start]方法。start 方法很长,我们来详细分析一下:
- (void)start
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge start]", nil);
//发送RCTJavaScriptWillStartLoadingNotification的消息
[[NSNotificationCenter defaultCenter]
postNotificationName:RCTJavaScriptWillStartLoadingNotification
object:_parentBridge userInfo:@{@"bridge": self}];
// Set up the JS thread early,创建JS线程
_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_t prepareBridge = dispatch_group_create();
[_performanceLogger markStartForTag:RCTPLNativeModuleInit];
[self registerExtraModules];
// Initialize all native modules that cannot be loaded lazily, 初始化Native module
(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.
_reactInstance.reset(new Instance);
__weak RCTCxxBridge *weakSelf = self;
// Prepare executor factory (shared_ptr for copy into block)
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<JSIExecutorFactory>(
makeJSCRuntime(),
[](const std::string &message, unsigned int logLevel) {
_RCTLogJavaScriptInternal(
static_cast<RCTLogLevel>(logLevel),
[NSString stringWithUTF8String:message.c_str()]);
}, 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)
dispatch_group_enter(prepareBridge);
[self ensureOnJavaScriptThread:^{
[weakSelf _initializeBridge:executorFactory];
dispatch_group_leave(prepareBridge);
}];
// Load the source asynchronously, then store it for later execution.
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
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, @"");
}
代码很长,我们一步步看,他实现的功能主要是:
1.创建JS线程
2.初始化NativeModule
[self _initializeModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];
其中,RCTGetModuleClasses() 会返回一个NSArray RCTModuleClasses,而RCTModuleClasses的创建函数是
void RCTRegisterModule(Class moduleClass)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
RCTModuleClasses = [NSMutableArray new];
RCTModuleClassesSyncQueue = dispatch_queue_create("com.facebook.react.ModuleClassesSyncQueue", DISPATCH_QUEUE_CONCURRENT);
});
RCTAssert([moduleClass conformsToProtocol:@protocol(RCTBridgeModule)],
@"%@ does not conform to the RCTBridgeModule protocol",
moduleClass);
// Register module
dispatch_barrier_async(RCTModuleClassesSyncQueue, ^{
[RCTModuleClasses addObject:moduleClass];
});
}
而源码中有对整个函数的宏定义:
define RCT_EXPORT_MODULE(js_name) \
RCT_EXTERN void RCTRegisterModule(Class); \
- (NSString *)moduleName { return @#js_name; } \
- (void)load { RCTRegisterModule(self); }
因此所有通过RCT_EXPORT_MODULE()定义的类(也就是所有对JS层开放的类)都会在初始化的时候加入到RCTModuleClasses的类中。
最终会调用如下的方法返回一个NSArray<RCTModuleData *> 。其中它会遍历所有的RN module然后创建各自的moduleData。而RCTModuleData中会有Module的所有的对外暴露的方法、属性和一些其他标识位(implementsBatchDidComplete、implementsPartialBatchDidFlush等)。
- (NSArray<RCTModuleData *> *)_registerModulesForClasses:(NSArray<Class> *)moduleClasses
lazilyDiscovered:(BOOL)lazilyDiscovered
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways,
@"-[RCTCxxBridge initModulesWithDispatchGroup:] autoexported moduleData", nil);
NSArray *moduleClassesCopy = [moduleClasses copy];
NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray arrayWithCapacity:moduleClassesCopy.count];
for (Class moduleClass in moduleClassesCopy) {
if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {
continue;
}
NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
// Check for module name collisions
RCTModuleData *moduleData = _moduleDataByName[moduleName];
if (moduleData) {
if (moduleData.hasInstance || lazilyDiscovered) {
// Existing module was preregistered, so it takes precedence
continue;
} else if ([moduleClass new] == nil) {
// The new module returned nil from init, so use the old module
continue;
} else if ([moduleData.moduleClass new] != nil) {
// Both modules were non-nil, so it's unclear which should take precedence
RCTLogError(@"Attempted to register RCTBridgeModule class %@ for the "
"name '%@', but name was already registered by class %@",
moduleClass, moduleName, moduleData.moduleClass);
}
}
// Instantiate moduleData
// TODO #13258411: can we defer this until config generation?
moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];
_moduleDataByName[moduleName] = moduleData;
[_moduleClassesByID addObject:moduleClass];
[moduleDataByID addObject:moduleData];
}
[_moduleDataByID addObjectsFromArray:moduleDataByID];
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
return moduleDataByID;
}
3.创建<JSIExecutorFactory> executorFactory
4.在js线程初始化通讯桥
[weakSelf _initializeBridge:executorFactory]->Instance::initializeBridge->nativeToJsBridge:: nativeToJsBridge->jsExecutorFactory->createJSExecutor(m_delegate, jsQueue)->JSIExecutorFactory::createJSExecutor->JSIExecutor::JSIExecutor
JSIExecutor::JSIExecutor(
std::shared_ptr<jsi::Runtime> runtime,
std::shared_ptr<ExecutorDelegate> delegate,
Logger logger,
const JSIScopedTimeoutInvoker& scopedTimeoutInvoker,
RuntimeInstaller runtimeInstaller)
: runtime_(runtime),
delegate_(delegate),
nativeModules_(delegate ? delegate->getModuleRegistry() : nullptr),
logger_(logger),
scopedTimeoutInvoker_(scopedTimeoutInvoker),
runtimeInstaller_(runtimeInstaller) {
runtime_->global().setProperty(
*runtime, "__jsiExecutorDescription", runtime->description());
}
5.加载js文件
- (void)loadSource:(RCTSourceLoadBlock)onSourceLoad onProgress:(RCTSourceLoadProgressBlock)onProgress
6.运行js文件
[strongSelf executeSourceCode:sourceCode sync:NO];->[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion]->[self executeApplicationScript:script url:url async:YES]->self->reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async);->Instance::loadScriptFromString->loadApplication->nativeToJsBridge->loadApplication->JSIExecutor::loadApplicationScript->runtime->evaluateJavaScript
创建完RCTBridge之后,就是初始化:
[self initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]-> [self bundleFinishedLoading:([_bridge batchedBridge] ?: _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;
}
}
它主要是两个功能,
一是创建RCTRootContentView
二是加载应用
我们先看创建RCTRootContentView
- (instancetype)initWithFrame:(CGRect)frame
bridge:(RCTBridge *)bridge
reactTag:(NSNumber *)reactTag
sizeFlexiblity:(RCTRootViewSizeFlexibility)sizeFlexibility
{
if ((self = [super initWithFrame:frame])) {
_bridge = bridge;
self.reactTag = reactTag;
_sizeFlexibility = sizeFlexibility;
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
[_touchHandler attachToView:self];
[_bridge.uiManager registerRootView:self];
}
return self;
}
在view上加上一个手势识别器,然后在bridge.uiManager中注册自己。
然后,再看加载应用:[self runApplication:bridge];->[bridge enqueueJSCall:@"AppRegistry"
method:@"runApplication"
args:@[moduleName, appParameters]
completion:NULL];->strongSelf->reactInstance->callJSFunction([module UTF8String], [method UTF8String],
convertIdToFollyDynamic(args ?: @[]));->ativeToJsBridge->callFunction(std::move(module), std::move(method),std::move(params));->executor->callFunction->callFunctionReturnFlushedQueue->call()-> callFunctionReturnFlushedQueue(module: string, method: string, args: any[])
执行完后,执行回调方法callNativeModules(ret, true);- >JSIExecutor::callNativeModules->delegate_->callNativeModules->m_callback->onBatchComplete();最终回调给native模块
网友评论