一個RCTRootView持有一個RCTBridge成員變量
成都創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的維西網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
RCTRootView : UIView
RCTBridge *bridge;
UIViewController *reactViewController;
UIView *contentView;
UIView *loadingView;
一個RCTBridge持有一個RCTCxxBridge成員變量
RCTBridge.h
@interface RCTBridge : NSObject
RCTBridge+Private.h
@interface RCTBridge ()
RCTBridge *batchedBridge;
@end
RCTBridge.m
- (Class)bridgeClass
return [RCTCxxBridge class];
- (void)setUp
Class bridgeClass = self.bridgeClass;
self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self];
[self.batchedBridge start];
RCTCxxBridge繼承自RCTBridge,是RCTBridge的一個變量,擁有弱引用parentBridge指向RCTBridge變量
RCTBridge+Private.h
@interface RCTCxxBridge:RCTBridge
RCTCxxBridge.mm
@interface RCTCxxBridge()
RCTBridge *parentBridge;
@end
//@interface ViewController()后面 ,@end前面的是類擴展,就是創(chuàng)建本類中似有的屬性和方法。其他類不能使用的
一個native類需要向js暴露的過程,就是向全局靜態(tài)數(shù)組RCTModuleClasses注冊自身class的過程。工程啟動后,自動生成全局靜態(tài)數(shù)組RCTModuleClasses,儲存注冊的class
######RCTBridge
聲明全局靜態(tài)數(shù)組:
static NSMutableArray
######native類
需要做到以下兩點,
1.實現(xiàn)RCTBridgeModule協(xié)議
2.在m文件中放置RCT_EXPORT_MODULE()代碼。
RCT_EXPORT_MODULE宏給native類置入load函數(shù)。native類在加載過程中,可以自動向RCTModuleClasses注冊自身Class。實例如下
ClassA.h
#import
@interface ClassA
@end
ClassA.m
RCT_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.m
static NSMutableArray *RCTModuleClasses;
void RCTRegisterModule(Class moduleClass)
[RCTModuleClasses addObject:moduleClass];
RCTCxxBridge有三個成員變量,_moduleDataByName,_moduleDataByID,_moduleClassesByID
RCTCxxBridge
NSMutableDictionary *_moduleDataByName; //字典,name:RCTModuleData鍵值對
NSMutableArray *_moduleDataByID; //RCTModuleData數(shù)組
NSMutableArray *_moduleClassesByID; //Class數(shù)組
- (void)start
[self _initModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];
- (void)_initModules:(NSArray> *)modules
withDispatchGroup:(dispatch_group_t)dispatchGroup
lazilyDiscovered:(BOOL)lazilyDiscovered
NSArray *moduleDataById = [self registerModulesForClasses:modules]; //將modules轉(zhuǎn)換成RCTCxxBridge的模塊組
- (NSArray *)registerModulesForClasses:(NSArray *)moduleClasses
for (Class moduleClass in moduleClasses) {
_moduleDataByName[moduleName] = moduleData;
[_moduleClassesByID addObject:moduleClass];
[moduleDataByID addObject:moduleData];
}
[_moduleDataByID addObjectsFromArray:moduleDataByID];
- (void)start
[self loadSource:^(NSError *error, RCTSource *source)
{sourceCode = source.data;}] // 加載JS
[strongSelf executeSourceCode:sourceCode sync:NO]; //執(zhí)行JS
- (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad onProgress:(RCTSourceLoadProgressBlock)onProgress
發(fā)送通知RCTBridgeWillDownloadScriptNotification
RCTSourceLoadBlock onSourceLoad = ^(NSError *error, RCTSource *source)
{
發(fā)送通知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(script),
sourceUrlStr.UTF8String, !async);
- (void)registerAdditionalModuleClasses:(NSArray *)modules
|=== - (NSArray *)registerModulesForClasses:(NSArray *)moduleClasses
|---for (Class moduleClass in moduleClasses)
{
NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];
}
[RCTCxxBridge registerExtraModules]
啟動
[AppDelegate didFinishLaunchingWithOptions]
|---獲取jsCodeLocation
|---[RCTRootView initWithBundleURL..]
|---[RCTBridge alloc+init]
|---設(shè)置變量:delegate,bundleURL,moduleProvider, launchOptions
|---[RCTBridge setUp]
|---設(shè)置變量: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,內(nèi)含RCTBridge變量,初始化參數(shù)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,可以從任意線程中調(diào)起
RCTBridge
- (void)setUp
URL轉(zhuǎn)換
self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self];
[self.batchedBridge start];
- (void)registerAdditionalModuleClasses:(NSArray *)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 調(diào)用 native 方法
調(diào)用原生代碼生成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都必須實現(xiàn)view功能
|---RCTUIManager->_viewRegistry[reactTag] = preliminaryCreatedView;
#保存至注冊數(shù)組,reactTag:preliminaryCreatedView
#RCTUIManager->_viewRegistry
# {1 = "; layer = >";
# 2 = ">";}
Instance C++ 類
void Instance::loadRAMBundle(std::unique_ptr bundleRegistry,
std::unique_ptr startupScript,
std::string startupScriptSourceURL,
bool loadSynchronously)
RCTModuleMethod C++ 類
通過NSInvocation動態(tài)調(diào)用相應(yīng)的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]; //調(diào)起函數(shù)
[_invocation getReturnValue:&returnValue]; //獲取返回值
RN 支持功能
tabbar,nagigator,text,image,數(shù)據(jù)庫?,ar?,真機調(diào)試日志?,網(wǎng)絡(luò),攝像頭拍照,圖片剪裁,音頻,視頻,下載,
添加RN庫
tabbar
官方組件 TabBarIOS,TabBarIOS.Item,只支持iOS,棄用
流行組件