RN源碼探索筆記

可能大家都知道RN的實現(xiàn)機制主要是兩個常駐線程焦影,一個JS線程,一個UI線程封断,相互通信斯辰,js處理計算,給主線程發(fā)消息渲染坡疼”蛏耄基于這一點的基礎上探索RN的實現(xiàn)細節(jié)。

首先因為不清楚RN工程中如何將JS標簽轉變成原生的RCTView,所以想到斷點調(diào)試數(shù)據(jù)闸氮,看調(diào)用順序是怎樣的剪况。因為涉及線程頻繁的切換,斷點調(diào)試的探索過程還是花費了較久的時間蒲跨。

由于斷點了RCTView 的init 方法發(fā)現(xiàn)译断,所有的視圖創(chuàng)建都是有RCTUIManager調(diào)用createView方法,傳代一個tag標志或悲,一個props字典創(chuàng)建的view∷镞洌現(xiàn)在問題是誰調(diào)用了RCTUIManager呢,又是如何調(diào)用的呢巡语,看程序的調(diào)用棧發(fā)現(xiàn)翎蹈,是由RCTBatchBridge 解析找到RCTUIManager ,并調(diào)用對應的createView方法的男公,打印了RTCBatchBridge的結構和內(nèi)容發(fā)現(xiàn):

RCT中記錄了幾個主要的數(shù)組荤堪,一組數(shù)組名為 _moduleDataByID,裝了原生最主要的一些處理Module枢赔,其中包括了RCTUIManager 的module澄阳,長度為80,此處RCTUIManager在數(shù)組中的下標為70 糠爬,下文中會用到這個序號寇荧。應該可以猜想到,這個數(shù)組的長度肯定可以變大执隧。


RCTBatchBridge類結構.png

從 RCTBatchBridge 的類結構中可以看到揩抡,記錄Module的數(shù)組中裝的并不是RCTUIManager這些類的實例,而是RCTModuleData的實例镀琉。
作者用 RCTModuleData 對象類來描述了一個 例如RCTUIManager Module的實例峦嗤,記錄了每個Module的class,暴露那些方法(NSArray)屋摔,


RCTModuleData部分屬性.png

這樣RCTBatchBridge就記錄了原生主要的功能Module的表了烁设。

JS要想訪問原生的Module類,一定得利用JSContext钓试,暴露原生方法装黑,所以在RN的工程代碼中搜索關健詞,找到一下一段代碼:


原生對js暴露的方法呼叫function

于是在此處斷點弓熏,并重新進入RN頁面恋谭,發(fā)現(xiàn)此處穿戴的參數(shù)call數(shù)字里記錄的都是數(shù)字,例如下圖:


JS呼叫原生傳代的方法

此處圖上對于參數(shù)的解析是猜想挽鞠,這就是最初要特意提到RCTUIManager在 RCTBatchBridge 的module數(shù)組中的下標為70的原因疚颊。

在RCTBatchBridge調(diào)用Module的實現(xiàn)工程中可以看到狈孔,bridge用JS傳代的序號,在自己的module數(shù)組中材义,使用序號作為下標均抽,取出對應的Module,并調(diào)用Module中對應方法列表的序號的function其掂。


RCTBatchBridge 調(diào)用Module.png

那么又有一個問題油挥,原生代碼,為什么可以直接使用js傳代過來的序號呢清寇,或者說喘漏,js怎么知道原生module列表中的序號對應的Module是什么呢?這個可能就需要在js代碼中去找答案了华烟。

首先原生要聲明那些nativeModule要向js暴露翩迈,暴露哪些方法。我們可以先看看RCTUIManager的部分聲明盔夜。
宏聲明導出module

RCT_EXPORT_MODULE() 

#define RCT_EXPORT_MODULE(js_name) \
RCT_EXTERN void RCTRegisterModule(Class); \
+ (NSString *)moduleName { return @#js_name; } \
+ (void)load { RCTRegisterModule(self); }

及在+load方法中注冊负饲。
暴露方法

在看原生RCTUIManager的部分export聲明


OCExportFuncs.png

前面宏生成的方法名前綴都為rct_export,原生使用動態(tài)運行時喂链,找到改Module export的所有方法列表

export方法查找.png

以上是原生注冊moduleclass和function的注冊部分返十,那么js如何知道原生到底export了那些module呢,包括順序如何獲取呢椭微?

我在RCTBatchBridge的start方法中看到調(diào)用了一個叫injectJSONConfiguration的方法洞坑,方法的是現(xiàn)實


injectJSONConfiguration實現(xiàn).png

原生調(diào)用了js的 global 對象下注冊了 __fbBatchedBridgeConfig 的對象,對象打印如下:

 {"remoteModuleConfig":
   [["ExceptionsManager"],
   ["JSCExecutor"],
   ["ViewManager"],
   ["ARTNodeManager"],
   ["ARTGroupManager"],
   ["ARTRenderableManager"],
   ["ARTShapeManager"],
   ["ARTSurfaceViewManager"],
   ["ARTTextManager"],
   ["AccessibilityManager"],
   ["ActionSheetManager"],
   ["ActivityIndicatorViewManager"],
   ["AdSupport"],
   ["AlertManager"],
   ["AppState"],
   ["AssetsLibraryRequestHandler"],
   ["AsyncLocalStorage"],
   ["CameraRollManager"],
   ["Clipboard"],
   ["DataRequestHandler"],
   ["DatePickerManager"],
   ["DeviceInfo"],
   ["DevLoadingView"],
   ["DevMenu"],
   ["DevSettings"],
   ["EventDispatcher"],
   ["FileRequestHandler"],
   ["GIFImageDecoder"],
   ["HTTPRequestHandler"],
   ["I18nManager"],
   ["ImageEditingManager"],
   ["ImageLoader"],
   ["ImagePickerIOS"],
   ["ImageStoreManager"],
   ["ImageViewManager"],
   ["JSCSamplingProfiler"],
   ["KeyboardObserver"],
   ["LinkingManager"],
   ["LocalAssetImageLoader"],
   ["LocationObserver"],
   ["ModalHostViewManager"],
   ["NativeAnimatedModule"],
   ["NavigatorManager"],
   ["NavItemManager"],
   ["NetInfo"],
   ["Networking"],
   ["PerfMonitor"],
   ["PhotoLibraryImageLoader"],
   ["PickerManager"],
   ["PlatformConstants"],
   ["ProgressViewManager"],
   ["PushNotificationManager"],
   ["RawTextManager"],
   ["RedBox"],
   ["RefreshControlManager"],
   ["ScrollContentViewManager"],
   ["ScrollViewManager"],
   ["SegmentedControlManager"],
   ["SettingsManager"],
   ["SliderManager"],
   ["SourceCode"],
   ["StatusBarManager"],
   ["SwitchManager"],
   ["TabBarItemManager"],
   ["TabBarManager"],
   ["TextFieldManager"],
   ["TextManager"],
   ["TextViewManager"],
   ["Timing"],
   ["TVNavigationEventEmitter"],
   ["UIManager"],
   ["Vibration"],
   ["WebSocketExecutor"],
   ["WebSocketModule"],
   ["WebViewManager"],
   ["DevModule"],
   ["ImagePickerManager"],
   ["UiModule"],
   ["NetModule"],
   ["MapModule"]]}

也就是說蝇率,原生Module在 +load方法中將自己的class向原生RCTModuleClasses靜態(tài)數(shù)組中注冊迟杂,bridge創(chuàng)建啟動時會讀取RCTModuleClasses數(shù)組的值,構建原生希望暴露給JS的所有對象的Module對象數(shù)組本慕,start方法中調(diào)用injectJSONConfiguration方法排拷,將數(shù)據(jù)寫到global對象中,供js調(diào)用锅尘。

下面是NativeModule.js中在global.__fbBatchedBridgeConfig對象中讀取原生module的信息监氢,if分支是安卓的分支,else是iOS的邏輯分支藤违。

global.__fbBatchedBridgeConfig.png

這樣便是由原生向js傳帶了NativeModule的順序浪腐。
并且在NativeModule.js中找到了應證:


NativeModule.js.png

在上面的js注視信息中說到

 // Initially this config will only contain the module name when running in JSC. The actual
    // configuration of the module will be lazily loaded.

module的具體信息是懶加載的,用的時候才會去構建顿乒,也就是议街,此時js只拿到了module的classname,如何拿到module的function信息呢淆游?
我在NativeModule.js中找到loadModule的function

function loadModule(name: string, moduleID: number): ?Object {
  invariant(global.nativeRequireModuleConfig,
    'Can\'t lazily create module without nativeRequireModuleConfig');
  const config = global.nativeRequireModuleConfig(name);
  const info = genModule(config, moduleID);
  return info && info.module;
}

js調(diào)用了glaobal下的nativeRequireModuleConfig的方法傍睹,傳入了ModuleName,那方法實現(xiàn)是什么樣的呢犹菱?

context[@"nativeRequireModuleConfig"] = ^NSArray *(NSString *moduleName) {
      RCTJSCExecutor *strongSelf = weakSelf;
      if (!strongSelf.valid) {
        return nil;
      }

      RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"nativeRequireModuleConfig", @{ @"moduleName": moduleName });
      NSArray *result = [strongSelf->_bridge configForModuleName:moduleName];
      RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"js_call,config");
      return RCTNullIfNil(result);
    };

從上面一段代碼中可以看到拾稳,是由原生向js暴露了查詢Module詳細方法列表的方法,返回方法的列表腊脱。

所以js調(diào)用原生Module的方法時傳帶的信息是一串id的數(shù)組了访得。

通過以上的一些嘗試算是明白了RN的大致調(diào)用的實現(xiàn)方式,此處只是淺顯的描述了view的構建過程陕凹。其他Module的調(diào)用原理也是類似的悍抑。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市杜耙,隨后出現(xiàn)的幾起案子搜骡,更是在濱河造成了極大的恐慌,老刑警劉巖佑女,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件记靡,死亡現(xiàn)場離奇詭異,居然都是意外死亡团驱,警方通過查閱死者的電腦和手機摸吠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嚎花,“玉大人寸痢,你說我怎么就攤上這事∥裳。” “怎么了啼止?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長丛楚。 經(jīng)常有香客問我族壳,道長,這世上最難降的妖魔是什么趣些? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任仿荆,我火速辦了婚禮,結果婚禮上坏平,老公的妹妹穿的比我還像新娘拢操。我一直安慰自己,他們只是感情好舶替,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布令境。 她就那樣靜靜地躺著,像睡著了一般顾瞪。 火紅的嫁衣襯著肌膚如雪舔庶。 梳的紋絲不亂的頭發(fā)上抛蚁,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音惕橙,去河邊找鬼瞧甩。 笑死,一個胖子當著我的面吹牛弥鹦,可吹牛的內(nèi)容都是我干的肚逸。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼彬坏,長吁一口氣:“原來是場噩夢啊……” “哼朦促!你這毒婦竟也來了?” 一聲冷哼從身側響起栓始,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤务冕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后幻赚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洒疚,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年坯屿,在試婚紗的時候發(fā)現(xiàn)自己被綠了油湖。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡领跛,死狀恐怖乏德,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吠昭,我是刑警寧澤喊括,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站矢棚,受9級特大地震影響郑什,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蒲肋,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一蘑拯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兜粘,春花似錦申窘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至路鹰,卻和暖如春贷洲,著一層夾襖步出監(jiān)牢的瞬間收厨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工优构, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帽氓,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓俩块,卻偏偏與公主長得像,于是被迫代替她去往敵國和親浓领。 傳聞我的和親對象是個殘疾皇子玉凯,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,310評論 25 707
  • 本篇文章是講述 iOS 無埋點數(shù)據(jù)收集 SDK 系列的第二篇。在第一篇 中主要介紹了 SDK 整體實現(xiàn)思路以及...
    zerygao閱讀 12,213評論 4 64
  • 1.總論 1.怎樣理解公共空間联贩、城市公共空間漫仆、城市空間、開放空間和外部空間等概念以及它們之間的關系泪幌? 公共空間:有...
    Sriyhan閱讀 527評論 0 2
  • 笑來老師在這篇里給我們講了絕大多數(shù)人都會遇到的那三個大坑(湊熱鬧盲厌、隨大流、操別人的心)祸泪,不想把話說滿吗浩,但確實幾乎無...
    照進來的光閱讀 228評論 0 1
  • 夢里夢見夢是夢懂扼,心里心念心是心。愛留愛意愛是愛右蒲》空留空白空是空。 如果有一天瑰妄,我老了陷嘴,還是空無一人,你懂我的寂寞就...
    圖格那黎99閱讀 801評論 2 15