React Native技术剖析(一)
来源:互联网 发布:淘宝窗帘拍摄地点 编辑:程序博客网 时间:2024/05/22 12:53
前言
React Native(简称RN)的由来、优势、安装使用等等不在这里啰嗦,可以自行Google/百度。笔者整理了一下之前学习RN过程中记录的笔记,结合RN源代码来分析RN框架里面的一些技术思路,这对于理解和更好地使用RN都是很有益处的。由于水平有限,肯定有一些理解不对的地方欢迎指正。
今天主要讲一下,RN初始化过程是什么步骤,都做了哪些事情。
RN初始化过程
以iOS为例,RN的渲染主要在RCTRootView中,初始化代码非常简单,就是创建RootVIew对象. (由于函数调用层次比较深,一层层讲解很容易不清楚当前在那个函数,请读者谅解)
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"LarkRN" initialProperties:nil launchOptions:launchOptions];
我们看一下RCTRootView的initWithBundleURL函数做了什么:
函数中创建一个Bridge对象,并调用initWithBridge函数。
- (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:moduleNameinitialProperties:initialProperties];}
Bridge对象创建过程中又调用了[self setUp],setUp函数调用createBatchedBridge函数创建了一个BatchedBridge对象
- (void)createBatchedBridge{ self.batchedBridge = [[RCTBatchedBridge alloc] initWithParentBridge:self];}
BatchedBridge对象初始化中又调用了[self start],Start函数调用moduleConfig函数
config = [weakSelf moduleConfig];
BatchedBridge对象的moduleConfig函数主要是收集所有原生模块配置信息,返回格式化字符串。
NSMutableArray<NSArray *> *config = [NSMutableArray new]; for (RCTModuleData *moduleData in _moduleDataByID) { if (self.executorClass == [RCTJSCExecutor class]) { [config addObject:@[moduleData.name]]; } else { [config addObject:RCTNullIfNil(moduleData.config)]; } } return RCTJSONStringify(@{ @"remoteModuleConfig": config, }, NULL);
每个原生模块的配置信息由RCTModuleData 对象config属性管理,config是个数组,其中的元素依次为模块名,导出常量数组,导出函数数组,导出异步函数(类型为RCTFunctionTypePromise的函数)索引数组
NSDictionary<NSString *, id> *constants;NSMutableArray<NSString *> *methods;NSMutableArray<NSNumber *> *asyncMethods; NSMutableArray *config = [NSMutableArray new]; [config addObject:self.name]; if (constants.count) { [config addObject:constants]; } if (methods) { [config addObject:methods]; if (asyncMethods) { [config addObject:asyncMethods]; } }
BatchedBridge对象Start函数调用injectJSONConfiguration函数
[weakSelf injectJSONConfiguration:config onComplete:nil]
BatchedBridge对象injectJSONConfiguration函数就是向JSC中添加一个全局变量__fbBatchedBridgeConfig
[_javaScriptExecutor injectJSONText:configJSON asGlobalObjectNamed:@"__fbBatchedBridgeConfig" callback:onComplete];
接下来执行BatchedBridge对象的executeSourceCode函数,执行RN Bundle文件(JS代码)
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:^(NSError *loadError) {…此处省略}
BatchedBridge对象的executeSourceCode函数调用JSC的executeApplicationScript函数来运行JS代码
[_javaScriptExecutor executeApplicationScript:script sourceURL:url onComplete:^(NSError *scriptLoadError) {…}
JSC对象的executeApplicationScript函数将下载的RN Bundle文件放入JSC中执行
RCTJSCExecutor *strongSelf = weakSelf; JSValueRef jsError = NULL; JSStringRef execJSString = JSStringCreateWithUTF8CString((const char *)script.bytes); JSValueRef result = JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, _bundleURL, 0, &jsError); JSStringRelease(execJSString);
JS的BatchedBridge对象实际上是MessageQueue对象,使用前面的__fbBatchedBridgeConfig(原生模块配置列表)变量进行初始化
constBatchedBridge=new MessageQueue( ()=>global.__fbBatchedBridgeConfig );
MessageQueue对象的初始化过程中创建一个RemoteModules属性
lazyProperty(this,'RemoteModules',()=>{ Let {remoteModuleConfig}=configProvider(); Let modulesConfig=this._genModulesConfig(remoteModuleConfig); Let modules=this._genModules(modulesConfig); this._genLookupTables( modulesConfig,this._remoteModuleTable,this._remoteMethodTable ); returnmodules; }); _genModules(remoteModules){ Let modules={}; remoteModules.forEach((config,moduleID)=>{ Let info=this._genModule(config,moduleID); if(info){ modules[info.name]=info.module; } }); Return modules; }
MessageQueue对象的_genModules函数生成模型信息对象,key值为模型名,如果模块没有导出任何属性(常量或函数),则仅记录模块ID;处理模型中导出的函数,对函数进行包装。
_genModule(config,moduleID):?Object{ Let moduleName,constants,methods,asyncMethods,syncHooks; if(moduleHasConstants(config)){ [moduleName,constants,methods,asyncMethods,syncHooks]=config; }else{ [moduleName,methods,asyncMethods,syncHooks]=config; } Let module={}; Methods && methods.forEach((methodName,methodID)=>{ Const isAsync = asyncMethods && arrayContains(asyncMethods,methodID); Const isSyncHook = syncHooks && arrayContains(syncHooks,methodID); Const methodType=isAsync? MethodTypes.remoteAsync: isSyncHook ? MethodTypes.syncHook: MethodTypes.remote; module[methodName]=this._genMethod(moduleID,methodID,methodType); }); Object.assign(module,constants); if(!constants&&!methods&&!asyncMethods){ module.moduleID=moduleID; } return{name:moduleName,module}; }
MessageQueue对象的_genLookupTables函数生成模块名检索表和函数检索表
_genLookup(config,moduleID,moduleTable,methodTable){ Let moduleName,methods; if(moduleHasConstants(config)){ [moduleName,,methods]=config; }else{ [moduleName,methods]=config; } moduleTable[moduleID]=moduleName; methodTable[moduleID]=Object.assign({},methods); }
MessageQueue对象registerCallableModule注册JS端可调用模块,记录每个模块名和可用的函数列表,供原生端调用
BatchedBridge.registerCallableModule('Systrace',Systrace); registerCallableModule(name,methods){ this._callableModules[name]=methods; }
MessageQueue对象初始化完成后,会放入到一个全局变量”__fbBatchedBridge”中,供后续使用。
Object.defineProperty(global,'__fbBatchedBridge',{value:BatchedBridge});
到此,RN初始化过程全部结束。简单来说,就是收集原生和JS模块配置信息,然后生成每个模块及其可用函数的检索表, 并放入JSC中全局变量中保存起来。
- React Native技术剖析(一)
- React Native技术剖析(二)
- React Native技术周报一
- react-native学习(一)
- 自学React Native(一)
- React Native 入门(一)
- react native 技术栈
- react-native技术调研:react-native是什么?
- [深入剖析React Native]React Native组件之Touchable*源码解析(1)
- [深入剖析React Native]React 初探
- React Native (一) --React 入门
- React Native学习一:初识React Native
- React Native(iOS)一、环境篇
- react native 样式初学~(一)
- React Native项目初窥(一)
- React Native Android(一)环境搭建
- React Native Android(一)环境搭建
- React Native初步学习(一)
- android studio常用的插件
- insertAfter函数
- Android之MVP架构总结
- C#基础知识简单梳理
- Tomcat SSL配置及Tomcat CA证书安装
- React Native技术剖析(一)
- Object类toString方法重写,equals方法重写
- Mysql常用操作
- redis 与 数据库(Mysql)同步
- Navicat Premium 连接本地oracle
- 开启数据库外部访问
- 关于android客户端中webview调试的方法
- 傻瓜式的百度定位
- 任务调度器之azkaban(二)