![](https://img.haomeiwen.com/i292976/1fa66611c3fbc4e0.png)
原理
原生端和JS端都保存了一份模块配置表,里面标记了所有原生暴露的模块和方法。
-
实例
1A8A13D4-E61B-44E5-A33C-FA2990276B5F.png
JS调用原生模块方法时,通过模块配置表把请求分解为模块ID、方法ID和参数传给原生,原生通过模块配置表找到对应的方法并执行
React Native结构
![](https://img.haomeiwen.com/i292976/b4c9279cf787a4d4.png)
React Native启动流程
![](https://img.haomeiwen.com/i292976/d3e695115b091c93.png)
创建RCTBridge
- 桥接对象,管理JS和OC交互,它内部持有一个RCTBatchBridge对象
创建RCTBatchBridge
- JS和OC交互主要是由它实现的
执行[RCTBatchedBridge loadSource]
- 加载JS源码
执行[RCTBatchedBridge initModulesWithDispatchGroup]
- 创建模块配置表
执行[RCTJSCExecutor injectJSONText]
- 往js中注入模块配置表
执行完JS代码,回调OC,调用OC中的组件
实现过程
原生向js端发消息
-
RCTEventDispatcher
- 通过RCTJSExecutor,主动发起调用了JS
原生端生成模块配置表
-
使用RCT_EXPORT_MODULE宏注册要暴露的类
-
宏定义
A321DE3C-03D1-4B70-A990-D75AA22D90DD.png
-
RCT_EXPORT_MODULE宏中,app运行时调用load方法,注册自己
-
把宏展开后的类
45B5D309-A638-4A9C-B571-1DC9308ED224.png
-
-
-
使用RCT_EXPORT_METHOD宏注册方法
-
宏定义
A5EDE7B5-7DEA-4263-9C40-5A678DB7BCB8.png
-
该宏返回一个数组,里面包含方法内容
-
实例
0C596D90-B24F-44F1-9817-69F3DFD56784.png
-
把宏展开后的方法
961D10E6-0CA0-465A-BE68-50AD6388A144.png
-
-
-
全局单例数组RCTModuleClasses保存了所有的原生类信息
![](https://img.haomeiwen.com/i292976/072c34aeea0f5839.png)
-
从RCTModuleClasses生成三个配置表,保存所有的原生模块信息,便于后续查找
![](https://img.haomeiwen.com/i292976/9a46ef2c2152bae3.png)
- moduleClassesByID数组表,存储原生类的class
- moduleDataByID数组表,保存由原生类生成的RCTModuleData对象
- moduleDataByName字典表,以+methodName方法的返回值为key,保存由原生类生成的RCTModuleData对象
- RCTModuleData保存类moduleClass、name、methods、instance、confige
-
生成moduleConfig
- 从moduleDataByName表中,取出所有项,放到一个数组中。
模块配置表传到js端
![](https://img.haomeiwen.com/i292976/46c462f0504ca1cf.png)
-
将moduleConfig配置信息,通过RCTJSExecutor,注入到JS环境JSContext里
-
在JS的global全局变量里面加入一个__fbBatchedBridgeConfig对象,是一个数组,里面记录着所有原生模块信息
js端调用原生模块
-
在模块配置表内,找到js请求中的ModuleID、MethodID、arguments
![](https://img.haomeiwen.com/i292976/7a0ea1042cf01bcb.png)
-
js端把方法回调存入callback数组中,原生端执行完毕,调用此回调
![](https://img.haomeiwen.com/i292976/2cfc57eae4d864dd.png)
-
把js请求放到MessageQueue中,等待原生调用
![](https://img.haomeiwen.com/i292976/76df4e40470559f5.png)
- 间隔5毫秒后才能调用
![](https://img.haomeiwen.com/i292976/14cdaebf80c5b3f8.png)
-
原生收到消息,通过模块配置表,找到对应的模块和方法,调用执行
-
js一次性传来多条消息,分别识别出每一条消息的module信息
-
查找到对应的模块、方法,执行
-
![](https://img.haomeiwen.com/i292976/dfab553b02e13414.png)
-
![](https://img.haomeiwen.com/i292976/1d7f736de312b122.png)
- 原生方法执行完毕,再主动调用js,js端通过callbackId,找到对应callback调用
js调用原生UI组件
-
原生UI组件注册
-
原生UI组件继承自RCTViewManager
-
RCTViewManager是上面的一个原生模块,作为基类暴露公用属性如backgroundColor、opacity、shadowColor等
-
子类可以添加自定义的属性,供js调用
-
-
RCT_EXPORT_VIEW_PROPERTY
-
宏定义
887B22C6-7485-4061-971F-69E6363D00EF.png
-
-
RCTUIManager是上面的一个原生模块,它管理着所有的原生UI组件的生成、更新
-
RCTUIManager初始化
- 从模块配置表中,循环查找其中继承自RCTViewManager的对象,放到_viewManagers字典和_viewConfigs数组中,key是viewName
-
-
RCTRootView
-
js环境加载完成后,创建subview RCTContentRootView
-
RCTContentRootView通过allocateRootTag方法创建了root得reactTag,规则是从1开始,每次累加10
-
-
![](https://img.haomeiwen.com/i292976/008512e08f78b367.png)
- 把reactTag放到RCTUIManager的_viewRegistry字典中,key为reactTag
- 通知js开始绘制页面
-
![](https://img.haomeiwen.com/i292976/c9b1ac6730bde320.png)
-
RCTUIManager
-
对js暴露的方法
-
createView
- 创建各种原生View,并且把传过来的JS的属性参数一一赋值
-
updateView
- JS通知原生View来更新对应的属性、样式变化
-
......
-
-
js操纵原生view的实现过程
-
从js端传来reactTag、viewName、props
-
以createView为例
0A075817-0BA1-400D-95A4-3479D96E2551.png
-
-
通过viewName,在_viewManagers中找到对应的原生view data
-
创建原生view,指定它的tag为reactTag,方便后续查找
-
通过props,给原生view赋值
-
通过propConfig判断是否注册过该属性
-
如果已注册,则通过运行时invocation的方式,生成了一个block函数,每次调用这个block,就会以运行时的方式,setter给对应属性
-
-
-
![](https://img.haomeiwen.com/i292976/268bdc879411853a.png)
参考资料:
http://blog.cnbang.net/tech/2698/
http://taobaofed.org/blog/2015/12/30/the-communication-scheme-of-react-native-in-ios/
http://awhisper.github.io/2016/07/02/ReactNative%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%902/
网友评论