背景:
因为公司的RN库版本是0.4.x,调研后决定升级到0.6.x。之前没有接触过RN,在上手之前,现在网上大概进行一下基础知识的学习,并将总结性的结论统一放在这里,方便以后查阅。
参考:
整体架构、流程
- 首先写好JSX代码(React框架就是使用JSX语法)
- 把JSX代码解析成javaScript代码
- OC读取JS文件
- 把javaScript代码读取出来,利用JavaScriptCore执行
- javaScript代码返回一个数组,数组中会描述OC对象,OC对象的属性,OC对象所需要执行的方法,这样就能让这个对象设置属性,并且调用方法。
- 如果你了解这些东西的本质其实就很清楚了。动态或者脚本语言要跟本地语言互通要具备如下几点:
- 本地语言有一个runtime机制来对对象的方法调用进行动态解析。
- 本地语言一定有一个脚本的解析引擎
- 建立一个脚本语言到本地语言的映射表,KEY是脚本语言认识的符号,VALUE是本地语言认识的符号。通过这个映射表来构建从脚本到本地的调用。
- 通过上述3个原则,无论是RN, JSPATCH, WEEKS, WEX都是使用同样的机制。。没有什么神秘可言,也没有什么复杂度可言了。。。
启动流程
React Native启动流程(iOS)
React Native加载JS源码流程(iOS)
渲染原理
通信机制
ReactNative 的初始化
native module 注册
- 要将 Native module(类、接口)曝露给 JS,module需要实现
RCTBridgeModule
协议,并且在实现中要插入RCT_EXPORT_MODULE
宏。具体曝露的方法也需要通过RCT_EXPORT_METHOD
宏定义。 RCT_EXPORT_MODULE
的源码:RCT_EXTERN void RCTRegisterModule(Class); +(NSString *)moduleName { return @ #js_name; } +(void)load { RCTRegisterModule(self); } 复制代码
- 通过上图流程,native module注册最终定位到
RCTCxxBridge._initModulesWithDispatchGroup
:- (void)_initModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup { NSMutableArray<Class> *moduleClassesByID = [NSMutableArray new]; NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new]; NSMutableDictionary<NSString *, RCTModuleData *> *moduleDataByName = [NSMutableDictionary new]; // Set up moduleData for automatically-exported modules for (Class moduleClass in RCTGetModuleClasses()) { NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass); moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self]; moduleDataByName[moduleName] = moduleData; [moduleClassesByID addObject:moduleClass]; [moduleDataByID addObject:moduleData]; } // Store modules _moduleDataByID = [moduleDataByID copy]; _moduleDataByName = [moduleDataByName copy]; _moduleClassesByID = [moduleClassesByID copy]; } 复制代码
- 上述代码第
8
行RCTGetModuleClasses()
即是获取通过RCTRegisterModule
注册的 module 类(即所有曝露给 JS 的类) - 至此,所有需要曝露给 JS 的 module 都已注册完成,并以
RCTModuleData
格式存储在RCTCxxBridge
中。 - 大部分 module 都是
懒加载
,只有那些需要在主线程完成初始化以及有常量需要导出的 module才会在注册时实例化。
JS 获取 native module 信息
- 收集了所有曝露给 JS 的 module(也可称之为生成了一份 native module 注册表);
- 在 JS Context 中设置了
nativeModuleProxy
以及nativeFlushQueueImmediate
; - 初始化了相关的类,如:
NativeToJsBridge
、JsToNativeBridge
以及JSCExecutor
等
JS 调用 native module
- NativeModules.moduleName — 该过程主要是获取 native module 的信息(moduleID、methodID),最终封装为 JS object ({methodName: fn});
- NativeModules.moduleName.methodName(params) — 执行调用。
总结
- RN 项目中涉及多种语言,但 Native 与 JS 的通信发生在
C++
与JavaScript
间; - 双方具体负责通信的分别是:Native 的
JSCExecutor
与 JS 的MessageQueue
; - 在 Native 侧维护了一份曝露给 JS 的 module 注册表,在 JS 侧维护了一份曝露给 Native 的 module 注册表;
- RN 中 Native to JS 的通信没有使用
JavaScriptCore
提供的机制(block
、JSExport
),而是自己实现了一套跨平台通信机制。