React Native 实现原理

RCTRootView 创建前到中

获取URL

从localhost/ip获取,或者从本地获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" 
fallbackResource:nil] = {
return [self jsBundleURLForBundleRoot:bundleRoot
fallbackResource:resourceName
fallbackExtension:nil] = {
NSString *packagerServerHost = [self packagerServerHost] = {
// debug模式下如果没有内置ip.txt,则返回localhost,release则返回nil
NSString *location = [self jsLocation];
if (location != nil) {
return location;
}
#if RCT_DEV
NSString *host = [self guessPackagerHost] = {
// ...
NSString *ipPath = [[NSBundle mainBundle] pathForResource:@"ip"
ofType:@"txt"];
// ...

NSString *host = ipGuess ?: @"localhost";
// ...
};
if (host) {
return host;
}
#endif
return nil;
};
if (!packagerServerHost) {
return [self jsBundleURLForFallbackResource:resourceName
fallbackExtension:extension];
} else {
// http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false
return [RCTBundleURLProvider jsBundleURLForBundleRoot:bundleRoot
packagerHost:packagerServerHost
enableDev:[self enableDev]
enableMinification:[self enableMinification]];
};
};

创建 Bridge

1
2
3
4
5
6
7
8
9
10
11
12
13
[[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"demo3"
initialProperties:nil
launchOptions:launchOptions] = {
RCTBridge *bridge =
[[RCTBridge alloc] initWithBundleURL:bundleURL
moduleProvider:nil
launchOptions:launchOptions];

return [self initWithBridge:bridge
moduleName:moduleName
initialProperties:initialProperties];
};
RCTBridge 创建
1
2
3
4
5
6
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL
moduleProvider:nil
launchOptions:launchOptions];
// RCTBridge 的 setUp
// ...
[self setUp];
RCTBridge setUp

RCTCxxBridge 创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (instancetype)initWithParentBridge:(RCTBridge *)bridge {
// ...

/**
* 设置可用状态、加载状态,以及一些数组的初始化,并将bridge设置成自己
*/
_valid = YES;
_loading = YES;
_pendingCalls = [NSMutableArray new];
_displayLink = [RCTDisplayLink new];

_moduleDataByName = [NSMutableDictionary new];
_moduleClassesByID = [NSMutableArray new];
_moduleDataByID = [NSMutableArray new];

[RCTBridge setCurrentBridge:self];
// ...
}
RCTCxxBridge start
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
- (void)start {
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge start]", nil);

[[NSNotificationCenter defaultCenter]
postNotificationName:RCTJavaScriptWillStartLoadingNotification
object:_parentBridge userInfo:@{@"bridge": self}];

// 创建一个启动runloop的名为com.facebook.react.JavaScript的线程,并运行
// 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_t prepareBridge = dispatch_group_create();

[_performanceLogger markStartForTag:RCTPLNativeModuleInit];

[self registerExtraModules];
// 初始化所有的本地模块,先非主线程后主线程
// RCTGetModuleClasses() 实际上是 RCTModuleClasses 的拷贝
(void)[self _initializeModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];

[_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)
// 创建JSC实例
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) {
BOOL useCustomJSC =
[self.delegate respondsToSelector:@selector(shouldBridgeUseCustomJSC:)] &&
[self.delegate shouldBridgeUseCustomJSC:self];
// We use the name of the device and the app for debugging & metrics
NSString *deviceName = [[UIDevice currentDevice] name];
NSString *appName = [[NSBundle mainBundle] bundleIdentifier];
// The arg is a cache dir. It's not used with standard JSC.
executorFactory.reset(new JSCExecutorFactory(folly::dynamic::object
("OwnerIdentity", "ReactNative")
("AppIdentity", [(appName ?: @"unknown") UTF8String])
("DeviceIdentity", [(deviceName ?: @"unknown") UTF8String])
("UseCustomJSC", (bool)useCustomJSC)
#if RCT_PROFILE
("StartSamplingProfilerOnInit", (bool)self.devSettings.startSamplingProfilerOnLaunch)
#endif
));
}
} else {
id<RCTJavaScriptExecutor> objcExecutor = [self moduleForClass:self.executorClass];
executorFactory.reset(new RCTObjcExecutorFactory(objcExecutor, ^(NSError *error) {
if (error) {
[weakSelf handleError:error];
}
}));
}

// 初始化JSC
dispatch_group_enter(prepareBridge);
[self ensureOnJavaScriptThread:^{
[weakSelf _initializeBridge:executorFactory];
dispatch_group_leave(prepareBridge);
}];

// 开始加载JS数据
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")
RCTDevLoadingView *loadingView = [weakSelf moduleForClass:[RCTDevLoadingView class]];
[loadingView updateProgress:progressData];
#endif
}];

// 最后开始执行JS数据
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, @"");
}
RCTModuleClasses

每一个导出类都会实现RCTBridgeModule的代理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@protocol RCTBridgeModule <NSObject>

/**
* Place this macro in your class implementation to automatically register
* your module with the bridge when it loads. The optional js_name argument
* will be used as the JS module name. If omitted, the JS module name will
* match the Objective-C class name.
*/
#define RCT_EXPORT_MODULE(js_name) \
RCT_EXTERN void RCTRegisterModule(Class); \
+ (NSString *)moduleName { return @#js_name; } \
+ (void)load { RCTRegisterModule(self); }

+ (NSString *)moduleName;

//...
@end

RCT_EXPORT_MODULE里实现了moduleName方法,同时也在类的load方法里注册本类,下面来看下RCTRegisterModule里的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void RCTRegisterModule(Class moduleClass) {
// 线程安全地注册所有的模块类,加入到RCTModuleClasses数组中
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
NSLog(@"%@", NSStringFromClass(moduleClass));
dispatch_barrier_async(RCTModuleClassesSyncQueue, ^{
[RCTModuleClasses addObject:moduleClass];
});
}

RCTModuleData 创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
- (NSArray<RCTModuleData *> *)_initializeModules:(NSArray<id<RCTBridgeModule>> *)modules
withDispatchGroup:(dispatch_group_t)dispatchGroup
lazilyDiscovered:(BOOL)lazilyDiscovered {
RCTAssert(!(RCTIsMainQueue() && lazilyDiscovered), @"Lazy discovery can only happen off the Main Queue");

// Set up moduleData for automatically-exported modules
NSArray<RCTModuleData *> *moduleDataById = [self registerModulesForClasses:modules] = {
// ...

NSArray *moduleClassesCopy = [moduleClasses copy];
NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray arrayWithCapacity:moduleClassesCopy.count];
for (Class moduleClass in moduleClassesCopy) {
NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass); //去掉RK和RCT

// Check for module name collisions
RCTModuleData *moduleData = _moduleDataByName[moduleName];
// 如果已经有moduleData了,并且已经有实例或new方法返回空时丢弃
if (moduleData) {
// ...
}

// 创建 moduleData ,并判断是否需要在主线程上初始化
moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];

/*
_moduleDataByName 记录模块数据,以模块名为key
_moduleClassesByID 模块类名列表
_moduleDataByID 模块数据列表
*/

_moduleDataByName[moduleName] = moduleData;
[_moduleClassesByID addObject:moduleClass];
[moduleDataByID addObject:moduleData];
}
[_moduleDataByID addObjectsFromArray:moduleDataByID];

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

return moduleDataByID;
};

// ...
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways,
@"-[RCTCxxBridge initModulesWithDispatchGroup:] moduleData.hasInstance", nil);
/*
先是遍历不需要在主线程上执行的模块,并初始化这些模块;
后在_prepareModulesWithDispatchGroup方法里在主线程上执行模块的初始化
*/
for (RCTModuleData *moduleData in _moduleDataByID) {
if (moduleData.hasInstance && (!moduleData.requiresMainQueueSetup || RCTIsMainQueue())) {
// Modules that were pre-initialized should ideally be set up before
// bridge init has finished, otherwise the caller may try to access the
// module directly rather than via `[bridge moduleForClass:]`, which won't
// trigger the lazy initialization process. If the module cannot safely be
// set up on the current thread, it will instead be async dispatched
// to the main thread to be set up in _prepareModulesWithDispatchGroup:.
(void)[moduleData instance];
}
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

// From this point on, RCTDidInitializeModuleNotification notifications will
// be sent the first time a module is accessed.
_moduleSetupComplete = YES;
[self _prepareModulesWithDispatchGroup:dispatchGroup];
// ...
return moduleDataById;
}

executorFactory.reset()初始化JS执行环境,以及初始化devSettings模块以便调试用

RCTModuleData 创建Module时,通过runtime查找出所有方法名前缀是 __rct_export__ 的方法生成RCTBridgeMethod对象,当需要调用本地方法时,调用processMethodSignature,先生成方法的签名(NSMethodSignature),再生成 NSInvocation, 设置参数,调用 invoke 方法,完成调用。

下面是JS需要原生回调数据时的情况:

_initializeBridge
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
- (void)_initializeBridge:(std::shared_ptr<JSExecutorFactory>)executorFactory {
// ...
// 创建JS消息线程
__weak RCTCxxBridge *weakSelf = self;
_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
// 调试模式下,初始化RCTObjcExecutor执行器,
executorFactory = std::make_shared<GetDescAdapter>(self, executorFactory) = {
std::unique_ptr<JSExecutor> createJSExecutor(
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> jsQueue) override {
auto ret = factory_->createJSExecutor(delegate, jsQueue) = {
return std::unique_ptr<JSExecutor>(
new RCTObjcExecutor(m_jse, m_errorBlock, jsQueue, dele
};
bridge_.bridgeDescription =
[NSString stringWithFormat:@"RCTCxxBridge %s",
ret->getDescription().c_str()];
return std::move(ret);
};

/*
与此同时之前需要在主线程上初始化的模块开始初始化
RCTDevMenu开始注册摇晃手机和键盘事件监听
*/
#endif

// This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
_reactInstance->initializeBridge(
std::make_unique<RCTInstanceCallback>(self),
executorFactory,
_jsMessageThread,
[self _buildModuleRegistry]);

#if RCT_PROFILE
if (RCTProfileIsProfiling()) {
_reactInstance->setGlobalVariable(
"__RCTProfileIsProfiling",
std::make_unique<JSBigStdString>("true"));
}
#endif

[self installExtraJSBinding];
}

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}

在JSCExecutor的构造函数中调用initOnJSVMThread()installGlobalProxy()两个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void JSCExecutor::initOnJSVMThread() throw(JSException) {
const bool useCustomJSC =
m_jscConfig.getDefault("UseCustomJSC", false).getBool(); // false
if (useCustomJSC) {
JSC_configureJSCForIOS(true, toJson(m_jscConfig));
}

// 创建JS上下文
// ...
{
SystraceSection s_("JSGlobalContextCreateInGroup");
m_context =
JSC_JSGlobalContextCreateInGroup(useCustomJSC, nullptr, globalClass);
}
JSC_JSClassRelease(useCustomJSC, globalClass);

// Add a pointer to ourselves so we can retrieve it later in our hooks
Object::getGlobalObject(m_context).setPrivate(this);

// ...
/*
绑定nativeFlushQueueImmediate,nativeCallSyncHook的本地方法,
以及创建了nativeLoggingHook、nativePerformanceNow、nativeInjectHMRUpdate JS函数
*/

installNativeHook<&JSCExecutor::nativeFlushQueueImmediate>(
"nativeFlushQueueImmediate");
installNativeHook<&JSCExecutor::nativeCallSyncHook>("nativeCallSyncHook");

installGlobalFunction(
m_context, "nativeLoggingHook", JSCNativeHooks::loggingHook);
installGlobalFunction(
m_context, "nativePerformanceNow", JSCNativeHooks::nowHook);

#if DEBUG
installGlobalFunction(
m_context, "nativeInjectHMRUpdate", nativeInjectHMRUpdate);
#endif

// ...
}
1
2
3
4
5
6
7
8
9
10
11
// 绑定nativeModuleProxy为NativeModules
installGlobalProxy(
m_context,
"nativeModuleProxy",
exceptionWrapMethod<&JSCExecutor::getNativeModule>()) = {
if (JSC_JSStringIsEqualToUTF8CString(m_context, propertyName, "name")) {
return Value(m_context, String(m_context, "NativeModules"));
}

return m_nativeModules.getModule(m_context, propertyName);
};
loadSource

loadBundleAtURL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
+ (void)loadBundleAtURL:(NSURL *)scriptURL onProgress:(RCTSourceLoadProgressBlock)onProgress onComplete:(RCTSourceLoadBlock)onComplete {
int64_t sourceLength;
NSError *error;
// 远程数据异步下载,本地数据同步读取
NSData *data = [self attemptSynchronousLoadOfBundleAtURL:scriptURL
runtimeBCVersion:JSNoBytecodeFileFormatVersion
sourceLength:&sourceLength
error:&error];
if (data) {
onComplete(nil, RCTSourceCreate(scriptURL, data, sourceLength));
return;
}

const BOOL isCannotLoadSyncError =
[error.domain isEqualToString:RCTJavaScriptLoaderErrorDomain]
&& error.code == RCTJavaScriptLoaderErrorCannotBeLoadedSynchronously;

if (isCannotLoadSyncError) {
attemptAsynchronousLoadOfBundleAtURL(scriptURL, onProgress, onComplete);
} else {
onComplete(error, nil);
}
}

这里以远程数据为例,调用attemptAsynchronousLoadOfBundleAtURL方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
static void attemptAsynchronousLoadOfBundleAtURL(NSURL *scriptURL, RCTSourceLoadProgressBlock onProgress, RCTSourceLoadBlock onComplete) {
scriptURL = sanitizeURL(scriptURL);
// 如果本地数据,则切后台线程读取
if (scriptURL.fileURL) {
// Reading in a large bundle can be slow. Dispatch to the background queue to do it.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSError *error = nil;
NSData *source = [NSData dataWithContentsOfFile:scriptURL.path
options:NSDataReadingMappedIfSafe
error:&error];
onComplete(error, RCTSourceCreate(scriptURL, source, source.length));
});
return;
}
// 创建RCTMultipartDataTask并执行
RCTMultipartDataTask *task = [[RCTMultipartDataTask alloc] initWithURL:scriptURL partHandler:^(NSInteger statusCode, NSDictionary *headers, NSData *data, NSError *error, BOOL done) {
if (!done) {
if (onProgress) {
// 调试模式下绿色条显示的内容
onProgress(progressEventFromData(data));
}
return;
}

// 出错时的处理
if (error) {
// ...
return;
}

// 成功响应会执行下面的代码
// 200表示已成功下载,解析并验证数据,无误就返回RCTSource
NSString *statusCodeHeader = headers[@"X-Http-Status"];
if (statusCodeHeader) {
statusCode = [statusCodeHeader integerValue];
}

if (statusCode != 200) {
error = [NSError errorWithDomain:@"JSServer"
code:statusCode
userInfo:userInfoForRawResponse([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding])];
onComplete(error, nil);
return;
}

// Validate that the packager actually returned javascript.
NSString *contentType = headers[@"Content-Type"];
NSString *mimeType = [[contentType componentsSeparatedByString:@";"] firstObject];
if (![mimeType isEqualToString:@"application/javascript"] &&
![mimeType isEqualToString:@"text/javascript"]) {
NSString *description = [NSString stringWithFormat:@"Expected MIME-Type to be 'application/javascript' or 'text/javascript', but got '%@'.", mimeType];
error = [NSError errorWithDomain:@"JSServer"
code:NSURLErrorCannotParseResponse
userInfo:@{
NSLocalizedDescriptionKey: description,
@"headers": headers,
@"data": data
}];
onComplete(error, nil);
return;
}

RCTSource *source = RCTSourceCreate(scriptURL, data, data.length);
parseHeaders(headers, source);
onComplete(nil, source);
} progressHandler:^(NSDictionary *headers, NSNumber *loaded, NSNumber *total) {
// Only care about download progress events for the javascript bundle part.
if ([headers[@"Content-Type"] isEqualToString:@"application/javascript"]) {
onProgress(progressEventFromDownloadProgress(loaded, total));
}
}];

[task startTask];
}

下载完JS数据后,开始执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync {
// ...
self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async) = {
// ...
loadApplication(nullptr, std::move(string), std::move(sourceURL)) = {
// ...
nativeToJsBridge_->loadApplication(std::move(bundleRegistry), std::move(string),
std::move(sourceURL)) = {
// ...
executor->loadApplicationScript(std::move(*startupScript),
std::move(startupScriptSourceURL));
};
};
};
// ...
}

JSCExecutor::loadApplicationScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void JSCExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) {
// ...
// 开始执行JS脚本
evaluateScript(m_context, jsScript, jsSourceURL);

flush() = {
// ...
bindBridge();
callNativeModules(m_flushedQueueJS->callAsFunction({}));
// ...
};
// ...
}

bindBridge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// __fbBatchedBridge 对应 JS 中 BatchedBridge

auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
// ...
auto batchedBridge = batchedBridgeValue.asObject();
m_callFunctionReturnFlushedQueueJS =
batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
m_invokeCallbackAndReturnFlushedQueueJS =
batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue")
.asObject();
m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
m_callFunctionReturnResultAndFlushedQueueJS =
batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue")
.asObject();

映射了JS中的callFunctionReturnFlushedQueue、invokeCallbackAndReturnFlushedQueue、flushedQueue和callFunctionReturnResultAndFlushedQueue四个方法

m_flushedQueueJS->callAsFunction({})从JS中取出待处理的队列

callNativeModules()映射成调用本地方法

RCTRootView 创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties {
// ...
if (self = [super initWithFrame:CGRectZero]) {
self.backgroundColor = [UIColor whiteColor];

_bridge = bridge;
_moduleName = moduleName;
_appProperties = [initialProperties copy];
_loadingViewFadeDelay = 0.25;
_loadingViewFadeDuration = 0.25;
_sizeFlexibility = RCTRootViewSizeFlexibilityNone;
// 注册loading view 的开始、JS数据获取完毕和已经渲染UI的通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(bridgeDidReload)
name:RCTJavaScriptWillStartLoadingNotification
object:_bridge];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(javaScriptDidLoad:)
name:RCTJavaScriptDidLoadNotification
object:_bridge];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(hideLoadingView)
name:RCTContentDidAppearNotification
object:self];

// 显示loading View
[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;
}

bundleFinishedLoading

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
- (void)bundleFinishedLoading:(RCTBridge *)bridge {
RCTAssert(bridge != nil, @"Bridge cannot be nil");
if (!bridge.valid) {
return;
}

// 创建RCTRootContentView,RCTRootContentView是一切React Native的父控件,本质上就是UIView
[_contentView removeFromSuperview];
_contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds
bridge:bridge
reactTag:self.reactTag
sizeFlexiblity:_sizeFlexibility] = {
if ((self = [super initWithFrame:frame])) {
_bridge = bridge;
// 设置根控件的reactTag为1
self.reactTag = reactTag;
_sizeFlexibility = sizeFlexibility;
// 创建RCTTouchHandler,并加到根控件上
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
[_touchHandler attachToView:self];
// 创建RCTUIManager,并绑定根控件
[_bridge.uiManager registerRootView:self];
}
return self;
};
[self runApplication:bridge] = {
NSString *moduleName = _moduleName ?: @"";
NSDictionary *appParameters = @{
@"rootTag": _contentView.reactTag,
@"initialProps": _appProperties ?: @{},
};

RCTLogInfo(@"Running application %@ (%@)", moduleName, appParameters);
/* 启动Application */
[bridge enqueueJSCall:@"AppRegistry"
method:@"runApplication"
args:@[moduleName, appParameters]
completion:NULL];
};

_contentView.passThroughTouches = _passThroughTouches;
[self insertSubview:_contentView atIndex:0];

if (_sizeFlexibility == RCTRootViewSizeFlexibilityNone) {
self.intrinsicContentSize = self.bounds.size;
}
}

调用JS里的AppRegistry.runApplication方法,RCTCxxBridge 初始化完成,调用RCTInstanceCallback中的onBatchComplete方法,然后调用RCTUIManager_layoutAndMount

RCTUIManager

负责处理UI相关的一切事务,包括控件的创建、更新和动画等

setBridge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (void)setBridge:(RCTBridge *)bridge {
// ...
// 获取所有的ViewManager
for (Class moduleClass in _bridge.moduleClasses) {
if ([moduleClass isSubclassOfClass:[RCTViewManager class]]) {
RCTComponentData *componentData = [[RCTComponentData alloc] initWithManagerClass:moduleClass
bridge:_bridge];
componentDataByName[componentData.name] = componentData;
}
}

_componentDataByName = [componentDataByName copy];

// 监听RCTAccessibilityManagerDidUpdateMultiplierNotification、设备方向以及键盘弹出/消失的通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didReceiveNewContentSizeMultiplier)
name:RCTAccessibilityManagerDidUpdateMultiplierNotification
object:_bridge.accessibilityManager];
#if !TARGET_OS_TV
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(namedOrientationDidChange)
name:UIDeviceOrientationDidChangeNotification
object:nil];
#endif
[RCTLayoutAnimation initializeStatics];
}

registerRootView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- (void)registerRootView:(RCTRootContentView *)rootView {
// ...

// _viewRegistry保存所有的view,key是reactTag
_viewRegistry[reactTag] = rootView;

// Register shadow view
RCTExecuteOnUIManagerQueue(^{
if (!self->_viewRegistry) {
return;
}
// _shadowViewRegistry保存所有的shadowView,shadowView与rootView一一对应,负责更新rootView的属性或动画执行
RCTRootShadowView *shadowView = [RCTRootShadowView new];
shadowView.availableSize = availableSize;
shadowView.reactTag = reactTag;
shadowView.viewName = NSStringFromClass([rootView class]);
self->_shadowViewRegistry[shadowView.reactTag] = shadowView;
// 保存reactTag
[self->_rootViewTags addObject:reactTag];
});
}

_layoutAndMount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)_layoutAndMount {
// RCTShadowView解析所有的props,并设置rootView的props
[self _dispatchPropsDidChangeEvents];
// 处理其子视图的props
[self _dispatchChildrenDidChangeEvents];

[_observerCoordinator uiManagerWillPerformLayout:self];

// 开始计算(yoga库)并更新rootView属性,具体的有兴趣可以去看一看
for (NSNumber *reactTag in _rootViewTags) {
RCTRootShadowView *rootView = (RCTRootShadowView *)_shadowViewRegistry[reactTag];
[self addUIBlock:[self uiBlockWithLayoutUpdateForRootView:rootView]];
}

[_observerCoordinator uiManagerDidPerformLayout:self];

[_observerCoordinator uiManagerWillPerformMounting:self];

[self flushUIBlocksWithCompletion:^{
[self->_observerCoordinator uiManagerDidPerformMounting:self];
}];
}


接下来会调用RCTUIManager createView:viewName:rootTag:props:方法创建子视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
RCT_EXPORT_METHOD(createView:(nonnull NSNumber *)reactTag
viewName:(NSString *)viewName
rootTag:(nonnull NSNumber *)rootTag
props:(NSDictionary *)props) {
RCTComponentData *componentData = _componentDataByName[viewName];
if (componentData == nil) {
RCTLogError(@"No component found for view with name \"%@\"", viewName);
}

// 先注册shadowView
RCTShadowView *shadowView = [componentData createShadowViewWithTag:reactTag];
if (shadowView) {
[componentData setProps:props forShadowView:shadowView];
_shadowViewRegistry[reactTag] = shadowView;
RCTShadowView *rootView = _shadowViewRegistry[rootTag];
RCTAssert([rootView isKindOfClass:[RCTRootShadowView class]] ||
[rootView isKindOfClass:[RCTSurfaceRootShadowView class]],
@"Given `rootTag` (%@) does not correspond to a valid root shadow view instance.", rootTag);
shadowView.rootView = (RCTRootShadowView *)rootView;
}

// 在主线程上创建对应的view,并加到_viewRegistry数组中,并设置props
__block UIView *preliminaryCreatedView = nil;

void (^createViewBlock)(void) = ^{
// Do nothing on the second run.
if (preliminaryCreatedView) {
return;
}

preliminaryCreatedView = [componentData createViewWithTag:reactTag];

if (preliminaryCreatedView) {
self->_viewRegistry[reactTag] = preliminaryCreatedView;
}
};

// We cannot guarantee that asynchronously scheduled block will be executed
// *before* a block is added to the regular mounting process (simply because
// mounting process can be managed externally while the main queue is
// locked).
// So, we positively dispatch it asynchronously and double check inside
// the regular mounting block.

RCTExecuteOnMainQueue(createViewBlock);

[self addUIBlock:^(__unused RCTUIManager *uiManager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) {
createViewBlock();

if (preliminaryCreatedView) {
// 设置view的props
[componentData setProps:props forView:preliminaryCreatedView];
}
}];

// 将需要更新的props增加到_shadowViewsWithUpdatedProps里
[self _shadowView:shadowView didReceiveUpdatedProps:[props allKeys]];
}

在导出视图的Manager中,如果需要暴露一些属性设置,一般会加RCT_EXPORT_VIEW_PROPERTY宏,这个宏会把方法名加上propConfig_的前缀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowView *)shadowView {
if (!shadowView) {
return;
}

[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id json, __unused BOOL *stop) {
[self propBlockForKey:key isShadowView:YES](shadowView, json) = {
RCTPropBlockDictionary *propBlocks = isShadowView ? _shadowPropBlocks : _viewPropBlocks;
RCTPropBlock propBlock = propBlocks[name];
if (!propBlock) {
创建props的block,也是通过runtime获取对应方法名,通过NSInvocation来完成调用,具体的有兴趣可以去看看
propBlock = [self createPropBlock:name isShadowView:isShadowView];

propBlocks[name] = [propBlock copy];
}
return propBlock;
};
}];
}

创建完视图后,开始设置每个视图的子视图(setChildren:reactTags:),不断地循环 createView 和 setChildren 直到整个页面渲染完毕

RCTTouchHandler

手势事件的捕获者并把事件传递给事件分发者RCTEventDispatcher进行分发

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- (instancetype)initWithBridge:(RCTBridge *)bridge {
RCTAssertParam(bridge);

if ((self = [super initWithTarget:nil action:NULL])) {
// 每一个实例都有RCTEventDispatcher的实例,RCTEventDispatcher负责把事件传给JS,包括手势事件和输入框文本相关事件
_eventDispatcher = [bridge moduleForClass:[RCTEventDispatcher class]];

_nativeTouches = [NSMutableOrderedSet new];
_reactTouches = [NSMutableArray new];
_touchViews = [NSMutableArray new];

// 落在控件内的事件不被取消,任何事件都被立即处理
self.cancelsTouchesInView = NO;
self.delaysTouchesBegan = NO; // This is default value.
self.delaysTouchesEnded = NO;

self.delegate = self;
}

return self;
}

当有点击事件时,RCTEventDispatcher调用sendEvent:方法,加入到事件队列中,开始调用dispatchEvent:方法,调用JS对应方法

1
[_bridge enqueueJSCall:[[event class] moduleDotMethod] args:[event arguments]]; // event 有view的reactTag,以便JS中查找到对应方法

enqueueJSCall: RCTEventEmitter.receiveTouches,事实上是RN里RCTEventEmitter的监听事件负责分发
args: RCTNormalizeInputEventName(_eventName), _reactTouches, _changedIndexes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
- (void)sendEvent:(id<RCTEvent>)event {
[_observersLock lock];

for (id<RCTEventDispatcherObserver> observer in _observers) {
[observer eventDispatcherWillDispatchEvent:event];
}

[_observersLock unlock];

[_eventQueueLock lock];

NSNumber *eventID = RCTGetEventID(event);

id<RCTEvent> previousEvent = _events[eventID];
if (previousEvent) {
RCTAssert([event canCoalesce], @"Got event %@ which cannot be coalesced, but has the same eventID %@ as the previous event %@", event, eventID, previousEvent);
event = [previousEvent coalesceWithEvent:event];
} else {
[_eventQueue addObject:eventID];
}
_events[eventID] = event;

BOOL scheduleEventsDispatch = NO;
if (!_eventsDispatchScheduled) {
_eventsDispatchScheduled = YES;
scheduleEventsDispatch = YES;
}

// We have to release the lock before dispatching block with events,
// since dispatchBlock: can be executed synchronously on the same queue.
// (This is happening when chrome debugging is turned on.)
[_eventQueueLock unlock];

if (scheduleEventsDispatch) {
[_bridge dispatchBlock:^{
[self flushEventsQueue] = {
[_eventQueueLock lock];
NSDictionary *events = _events;
_events = [NSMutableDictionary new];
NSMutableArray *eventQueue = _eventQueue;
_eventQueue = [NSMutableArray new];
_eventsDispatchScheduled = NO;
[_eventQueueLock unlock];

for (NSNumber *eventId in eventQueue) {
[self dispatchEvent:events[eventId]] = {
[_bridge enqueueJSCall:[[event class] moduleDotMethod] args:[event arguments]];
};
}
};
} queue:RCTJSThread];
}
}

当有输入事件时,RCTEventDispatcher则会调用sendTextEventWithType:reactTag:text:key:eventCount:方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
- (void)sendTextEventWithType:(RCTTextEventType)type
reactTag:(NSNumber *)reactTag
text:(NSString *)text
key:(NSString *)key
eventCount:(NSInteger)eventCount
{
static NSString *events[] = {
@"focus", // 获取焦点
@"blur", // 终止编辑之后
@"change", // 文本改变
@"submitEditing", // 当按下右下角最后一个键时
@"endEditing", // 终止编辑
@"keyPress" // 按下键盘上的键
};

NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:@{
@"eventCount": @(eventCount),
@"target": reactTag
}];

if (text) {
body[@"text"] = text;
}

if (key) {
if (key.length == 0) {
key = @"Backspace"; // 当按下删除键时
} else {
switch ([key characterAtIndex:0]) {
case '\t':
key = @"Tab";
break;
case '\n':
key = @"Enter";
default:
break;
}
}
body[@"key"] = key;
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self sendInputEventWithName:events[type] body:body] = {
name = RCTNormalizeInputEventName(name);
// 由于输入比较慢,不需要考虑并发的问题
[_bridge enqueueJSCall:@"RCTEventEmitter"
method:@"receiveEvent"
args:body ? @[body[@"target"], name, body] : @[body[@"target"], name]
completion:NULL];
};
#pragma clang diagnostic pop
}

从上面的代码可以看出输入事件和手势事件最终都是调用bridge enqueueJSCall:method:args:completion方法,模块都是RCTEventEmitter,但是方法名一个是 receiveEvent,另一个是 receiveTouches。

-------------本文结束感谢您的阅读-------------