原理
原生端和JS端都保存了一份模塊配置表,里面標記了所有原生暴露的模塊和方法。
-
實例
JS調(diào)用原生模塊方法時,通過模塊配置表把請求分解為模塊ID、方法ID和參數(shù)傳給原生培他,原生通過模塊配置表找到對應的方法并執(zhí)行
React Native結構
React Native啟動流程
創(chuàng)建RCTBridge
- 橋接對象,管理JS和OC交互,它內(nèi)部持有一個RCTBatchBridge對象
創(chuàng)建RCTBatchBridge
- JS和OC交互主要是由它實現(xiàn)的
執(zhí)行[RCTBatchedBridge loadSource]
- 加載JS源碼
執(zhí)行[RCTBatchedBridge initModulesWithDispatchGroup]
- 創(chuàng)建模塊配置表
執(zhí)行[RCTJSCExecutor injectJSONText]
- 往js中注入模塊配置表
執(zhí)行完JS代碼遗座,回調(diào)OC舀凛,調(diào)用OC中的組件
實現(xiàn)過程
原生向js端發(fā)消息
-
RCTEventDispatcher
- 通過RCTJSExecutor,主動發(fā)起調(diào)用了JS
原生端生成模塊配置表
-
使用RCT_EXPORT_MODULE宏注冊要暴露的類
-
宏定義
-
RCT_EXPORT_MODULE宏中途蒋,app運行時調(diào)用load方法猛遍,注冊自己
-
把宏展開后的類
-
-
-
使用RCT_EXPORT_METHOD宏注冊方法
-
宏定義
-
該宏返回一個數(shù)組,里面包含方法內(nèi)容
-
實例
-
把宏展開后的方法
-
-
-
全局單例數(shù)組RCTModuleClasses保存了所有的原生類信息
-
從RCTModuleClasses生成三個配置表,保存所有的原生模塊信息懊烤,便于后續(xù)查找
- moduleClassesByID數(shù)組表梯醒,存儲原生類的class
- moduleDataByID數(shù)組表,保存由原生類生成的RCTModuleData對象
- moduleDataByName字典表腌紧,以+methodName方法的返回值為key茸习,保存由原生類生成的RCTModuleData對象
- RCTModuleData保存類moduleClass、name壁肋、methods号胚、instance、confige
-
生成moduleConfig
- 從moduleDataByName表中浸遗,取出所有項猫胁,放到一個數(shù)組中。
模塊配置表傳到js端
將moduleConfig配置信息跛锌,通過RCTJSExecutor弃秆,注入到JS環(huán)境JSContext里
在JS的global全局變量里面加入一個__fbBatchedBridgeConfig對象,是一個數(shù)組髓帽,里面記錄著所有原生模塊信息
js端調(diào)用原生模塊
-
在模塊配置表內(nèi)菠赚,找到js請求中的ModuleID、MethodID氢卡、arguments
-
js端把方法回調(diào)存入callback數(shù)組中锈至,原生端執(zhí)行完畢,調(diào)用此回調(diào)
-
把js請求放到MessageQueue中译秦,等待原生調(diào)用
- 間隔5毫秒后才能調(diào)用
-
原生收到消息峡捡,通過模塊配置表,找到對應的模塊和方法筑悴,調(diào)用執(zhí)行
js一次性傳來多條消息们拙,分別識別出每一條消息的module信息
-
查找到對應的模塊、方法阁吝,執(zhí)行
-
- 原生方法執(zhí)行完畢砚婆,再主動調(diào)用js,js端通過callbackId突勇,找到對應callback調(diào)用
js調(diào)用原生UI組件
-
原生UI組件注冊
-
原生UI組件繼承自RCTViewManager
RCTViewManager是上面的一個原生模塊装盯,作為基類暴露公用屬性如backgroundColor、opacity甲馋、shadowColor等
子類可以添加自定義的屬性埂奈,供js調(diào)用
-
RCT_EXPORT_VIEW_PROPERTY
-
宏定義
-
RCTUIManager是上面的一個原生模塊,它管理著所有的原生UI組件的生成定躏、更新
-
RCTUIManager初始化
- 從模塊配置表中账磺,循環(huán)查找其中繼承自RCTViewManager的對象芹敌,放到_viewManagers字典和_viewConfigs數(shù)組中,key是viewName
-
-
RCTRootView
-
js環(huán)境加載完成后垮抗,創(chuàng)建subview RCTContentRootView
-
RCTContentRootView通過allocateRootTag方法創(chuàng)建了root得reactTag氏捞,規(guī)則是從1開始,每次累加10
-
-
- 把reactTag放到RCTUIManager的_viewRegistry字典中冒版,key為reactTag
- 通知js開始繪制頁面
-
-
RCTUIManager
-
對js暴露的方法
-
createView
- 創(chuàng)建各種原生View液茎,并且把傳過來的JS的屬性參數(shù)一一賦值
-
updateView
- JS通知原生View來更新對應的屬性、樣式變化
......
-
-
js操縱原生view的實現(xiàn)過程
-
從js端傳來reactTag辞嗡、viewName豁护、props
-
以createView為例
-
通過viewName,在_viewManagers中找到對應的原生view data
創(chuàng)建原生view欲间,指定它的tag為reactTag,方便后續(xù)查找
-
通過props断部,給原生view賦值
通過propConfig判斷是否注冊過該屬性
如果已注冊猎贴,則通過運行時invocation的方式,生成了一個block函數(shù)蝴光,每次調(diào)用這個block她渴,就會以運行時的方式,setter給對應屬性
-
-
參考資料:
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/