react native 0.50 源码解析 再出发 持续更新
一个RCTRootView持有一个RCTBridge成员变量
RCTRootView : UIView RCTBridge *bridge; UIViewController *reactViewController; UIView *contentView; UIView *loadingView;
1.2 RCTBridge
一个RCTBridge持有一个RCTCxxBridge成员变量
RCTBridge.h @interface RCTBridge : NSObject <RCTInvalidating>RCTBridge+Private.h@interface RCTBridge () RCTBridge *batchedBridge;@endRCTBridge.m- (Class)bridgeClass return [RCTCxxBridge class];- (void)setUp Class bridgeClass = self.bridgeClass; self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self]; [self.batchedBridge start];
1.3 RCTCxxBridge
RCTCxxBridge继承自RCTBridge,是RCTBridge的一个变量,拥有弱引用parentBridge指向RCTBridge变量
RCTBridge+Private.h@interface RCTCxxBridge:RCTBridgeRCTCxxBridge.mm@interface RCTCxxBridge()RCTBridge *parentBridge;@end//@interface ViewController()后面 ,@end前面的是类扩展,就是创建本类中似有的属性和方法。其他类不能使用的
2.核心流程2.1 native注册模块表
一个native类需要向js暴露的过程,就是向全局静态数组RCTModuleClasses注册自身class的过程。工程启动后,自动生成全局静态数组RCTModuleClasses,储存注册的class
######RCTBridge
声明全局静态数组:
static NSMutableArray<Class> *RCTModuleClasses;
######native类
需要做到以下两点,
1.实现RCTBridgeModule协议
2.在m文件中放置RCT_EXPORT_MODULE()代码。
RCT_EXPORT_MODULE宏给native类置入load函数。native类在加载过程中,可以自动向RCTModuleClasses注册自身Class。实例如下
ClassA.h#import <React/RCTBridgeModule.h>@interface ClassA <RCTBridgeModule>@endClassA.mRCT_EXPORT_MODULE() ==>extern __attribute__((visibility("default"))) void RCTRegisterModule(Class); + (void)load { RCTRegisterModule(self); }========================================宏定义RCTBridgeModule.h#define RCT_EXPORT_MODULE(js_name) \RCT_EXTERN void RCTRegisterModule(Class); \+ (NSString *)moduleName { return @#js_name; } \+ (void)load { RCTRegisterModule(self); }#define RCT_EXPORT_MODULE(js_name) RCT_EXTERN void RCTRegisterModule(Class); + (NSString *)moduleName { return @#js_name; } + (void)load { RCTRegisterModule(self); }RCTDefindes.h#define RCT_EXTERN extern __attribute__((visibility("default")))注册RCTBridge.mstatic NSMutableArray<Class> *RCTModuleClasses;void RCTRegisterModule(Class moduleClass) [RCTModuleClasses addObject:moduleClass];
2.2 RCTCxxBridge初始化模块表
RCTCxxBridge有三个成员变量,_moduleDataByName,_moduleDataByID,_moduleClassesByID
RCTCxxBridgeNSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName; //字典,name:RCTModuleData键值对NSMutableArray<RCTModuleData *> *_moduleDataByID; //RCTModuleData数组NSMutableArray<Class> *_moduleClassesByID; //Class数组- (void)start [self _initModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];- (void)_initModules:(NSArray<id<RCTBridgeModule>> *)modules withDispatchGroup:(dispatch_group_t)dispatchGroup lazilyDiscovered:(BOOL)lazilyDiscovered NSArray<RCTModuleData *> *moduleDataById = [self registerModulesForClasses:modules]; //将modules转换成RCTCxxBridge的模块组- (NSArray<RCTModuleData *> *)registerModulesForClasses:(NSArray<Class> *)moduleClasses for (Class moduleClass in moduleClasses) { _moduleDataByName[moduleName] = moduleData; [_moduleClassesByID addObject:moduleClass]; [moduleDataByID addObject:moduleData]; } [_moduleDataByID addObjectsFromArray:moduleDataByID];
2.3 RCTCxxBridge 加载/执行JS资源
- (void)start [self loadSource:^(NSError *error, RCTSource *source) {sourceCode = source.data;}] // 加载JS [strongSelf executeSourceCode:sourceCode sync:NO]; //执行JS- (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad onProgress:(RCTSourceLoadProgressBlock)onProgress 发送通知RCTBridgeWillDownloadScriptNotification RCTSourceLoadBlock onSourceLoad = ^(NSError *error, RCTSource *source) { 发送通知RCTBridgeDidDownloadScriptNotification:RCTSource } [RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onProgress:onProgress onComplete:^(NSError *error, RCTSource *source) { onSourceLoad(error, source); }- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync - (void)executeApplicationScript:(NSData *)script url:(NSURL *)url async:(BOOL)async dispatch_block_t completion = ^{ [self _flushPendingCalls]; 广播通知RCTJavaScriptDidLoadNotification [self ensureOnJavaScriptThread:^{ [self->_displayLink addToRunLoop:[NSRunLoop currentRunLoop]]; }]; }- (void)executeApplicationScript:(NSData *)script url:(NSURL *)url async:(BOOL)async if (isRAMBundle(script)) self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr), sourceUrlStr.UTF8String, !async); else if (self->_reactInstance) self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script), sourceUrlStr.UTF8String, !async);- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules |=== - (NSArray<RCTModuleData *> *)registerModulesForClasses:(NSArray<Class> *)moduleClasses |---for (Class moduleClass in moduleClasses) { NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass); moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self]; }[RCTCxxBridge registerExtraModules]
(void)start
|--- 广播通知---
RCTJavaScriptWillStartLoadingNotification:@{@"bridge": self}
|--- 新建并启动js线程 _jsThread
|--- 注册moduleClass---
[self registerExtraModules];
[self _initModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];
|--- 创建工厂并配置---
std::shared_ptr<JSExecutorFactory> executorFactory;
|--- 加载js资源---
[self loadSource:^(NSError error, RCTSource source)
|--- 执行js---
[strongSelf executeSourceCode:sourceCode sync:NO];
启动
[AppDelegate didFinishLaunchingWithOptions]|---获取jsCodeLocation|---[RCTRootView initWithBundleURL..] |---[RCTBridge alloc+init] |---设置变量:delegate,bundleURL,moduleProvider, launchOptions |---[RCTBridge setUp] |---设置变量:bundleURL |---[RCTCxxBridge alloc+init] --> RCTBridge.batchedBridge |---[RCTCxxBridge start] |---[RCTRootView initWithBridge:...] |---注册三个通知,如下 |---[self bundleFinishedLoading:([_bridge batchedBridge] ?: _bridge)]; |---RCTRootContentView alloc |---[self runApplication:bridge]; |---[bridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[moduleName, appParameters] completion:NULL]; |---insertSubview:_contentView
RCTRootView 继承自UIView,内含RCTBridge变量,初始化参数BundleURL/moduleName/Properties/launchOptions。初始化的时候,初始化RCTBridge变量,自我初始化。自我初始化过程:注册三个通知,RCTJavaScriptWillStartLoadingNotification/RCTJavaScriptDidLoadNotification/RCTContentDidAppearNotification
RCTBridge native call js
[RCTBridge enqueueJSCall:(NSString *)module method:(NSString *)method args:(NSArray *)args completion:(dispatch_block_t)completion]|---[self.batchedBridge enqueueJSCall:module method:method args:args completion:completion];
RCTCxxBridge 成员:
_moduleClassesByID
_moduleDataByID
_moduleDataByName 可变字典:string(moduleName):RCTModuleData(Data)的键值队
RCTCxxBridge native call js,可以从任意线程中调起
RCTBridge - (void)setUp URL转换 self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self]; [self.batchedBridge start];- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules [self.batchedBridge registerAdditionalModuleClasses:modules];
RCTJavaScriptLoader + (void)loadBundleAtURL:(NSURL *)scriptURL onProgress:(RCTSourceLoadProgressBlock)onProgress onComplete:(RCTSourceLoadBlock)onComplete|---NSData *data = [self attemptSynchronousLoadOfBundleAtURL:scriptURL runtimeBCVersion:JSNoBytecodeFileFormatVersion sourceLength:&sourceLength error:&error];|---onComplete(nil, RCTSourceCreate(scriptURL, data, sourceLength));+ (NSData *)attemptSynchronousLoadOfBundleAtURL:(NSURL *)scriptURL runtimeBCVersion:(int32_t)runtimeBCVersion sourceLength:(int64_t *)sourceLength error:(NSError **)error|---FILE *bundle = fopen(scriptURL.path.UTF8String, "r"); size_t readResult = fread(&header, sizeof(header), 1, bundle);
[RCTCxxBridge enqueueJSCall:(NSString *)module method:(NSString *)method args:(NSArray *)args completion:(dispatch_block_t)completion]|---
NSInvocation 调用 native 方法
调用原生代码生成UI控件
RCTUIManager RCT_EXPORT_METHOD(createView:(nonnull NSNumber *)reactTag viewName:(NSString *)viewName rootTag:(nonnull NSNumber *)rootTag props:(NSDictionary *)props)|---createViewBlock |---[RCTComponentData createViewWithTag:reactTag]; |--- [self.manager view] #此处self.manager是实际需要生成的UI类,如RCTTextView等 #所以,所有RN的原生UI都必须实现view功能 |---RCTUIManager->_viewRegistry[reactTag] = preliminaryCreatedView; #保存至注册数组,reactTag:preliminaryCreatedView #RCTUIManager->_viewRegistry # {1 = "<RCTRootContentView: 0x7faf12c015d0; reactTag: 1; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x60000024eaf0>; layer = <CALayer: 0x6040002376c0>>"; # 2 = "<UIView: 0x7faf12f0a6d0; frame = (0 0; 0 0); layer = <CALayer: 0x600000621300>>";}
Instance C++ 类void Instance::loadRAMBundle(std::unique_ptr<RAMBundleRegistry> bundleRegistry, std::unique_ptr<const JSBigString> startupScript, std::string startupScriptSourceURL, bool loadSynchronously)
RCTModuleMethod C++ 类
通过NSInvocation动态调用相应的OC模块方法
- (id)invokeWithBridge:(RCTBridge *)bridge module:(id)module arguments:(NSArray *)arguments [self processMethodSignature]; //set blocks block(bridge, index, RCTNilIfNull(json(arguments)) //set arguments [_invocation invokeWithTarget:module]; //调起函数 [_invocation getReturnValue:&returnValue]; //获取返回值
RN 支持功能
tabbar,nagigator,text,image,数据库?,ar?,真机调试日志?,网络,摄像头拍照,图片剪裁,音频,视频,下载,
添加RN库
tabbar
官方组件 TabBarIOS,TabBarIOS.Item,只支持iOS,弃用
流行组件
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。