亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

React Native通信機制詳解

2019-11-09 15:02:43
字體:
來源:轉載
供稿:網友
React Native是Facebook剛開源的框架,可以使用javaScript直接開發原生APP。

概覽

React Native用iOS自帶的JavascriptCore作為JS的解析引擎,使用JavaScriptCore提供的一些可以讓JS與OC互調的特性,來實現JS和OC之間的交互。React Native通過各種手段,實現了在OC定義一個模塊方法,JS可以直接調用這個模塊方法并還可以無縫銜接回調。

舉個例子,OC定義了一個模塊RCTSQLManager,里面有個方法-query:successCallback:,JS可以直接調用RCTSQLManager.query并通過回調獲取執行結果:

123456789//OC:@implement RCTSQLManager- (void)query:(NSString *)queryData successCallback:(RCTResponseSenderBlOCk)responseSender{     RCT_EXPORT();     NSString *ret = @"ret"     responseSender(ret);}@end

接下來看看它是怎樣實現的。

模塊配置表

首先OC要告訴JS它有什么模塊,模塊里有什么方法,JS才知道有這些方法后才有可能去調用這些方法。這里的實現是OC生成一份模塊配置表傳給JS,配置表里包括了所有模塊和模塊里方法的信息。例:

1234567891011121314{    "remoteModuleConfig": {        "RCTSQLManager": {            "methods": {                "query": {                    "type""remote",                    "methodID": 0                }            },            "moduleID": 4        },        ...     },}

OC端和JS端分別各有一個bridge,兩個bridge都保存了同樣一份模塊配置表,JS調用OC模塊方法時,通過bridge里的配置表把模塊方法轉為模塊ID和方法ID傳給OC,OC通過bridge的模塊配置表找到對應的方法執行之,以上述代碼為例,流程大概是這樣(先不考慮callback):

1.jpg

在了解這個調用流程之前,我們先來看看OC的模塊配置表式怎么來的。我們在新建一個OC模塊時,JS和OC都不需要為新的模塊手動去某個地方添加一些配置,模塊配置表是自動生成的,只要項目里有一個模塊,就會把這個模塊加到配置表上,那這個模塊配置表是怎樣自動生成的呢?分兩個步驟:

1.取所有模塊類

每個模塊類都實現了RCTBridgeModule接口,可以通過runtime接口objc_getClassList或objc_copyClassList取出項目里所有類,然后逐個判斷是否實現了RCTBridgeModule接口,就可以找到所有模塊類。通過class_conformsToPRotocol方法。

2.取模塊里暴露給JS的方法

一個模塊里可以有很多方法,一些是可以暴露給JS直接調用的,一些是私有的不想暴露給JS,怎樣做到提取這些暴露的方法呢?我能想到的方法是對要暴露的方法名制定一些規則,比如用RCTExport_作為前綴,然后用runtime方法class_getInstanceMethod取出所有方法名字,提取以RCTExport_為前綴的方法,但這樣做惡心的地方是每個方法必須加前綴。React Native用了另一種黑魔法似的方法解決這個問題:編譯屬性__attribute__。

在上述例子中我們看到模塊方法里有句代碼:RCT_EXPORT(),模塊里的方法加上這個宏就可以實現暴露給JS,無需其他規則,那這個宏做了什么呢?來看看它的定義:

12#define RCT_EXPORT(JS_name) __attribute__((used, section("__DATA,RCTExport" /))) static const char *__rct_export_entry__[] = { __func__, #JS_name }

這個宏的作用是用編譯屬性__attribute__給二進制文件新建一個section,屬于__DATA數據段,名字為RCTExport,并在這個段里加入當前方法名。編譯器在編譯時會找到__attribute__進行處理,為生成的可執行文件加入相應的內容。效果可以從linkmap看出來:

1234567891011121314# Sections:# Address Size Segment Section0x100001670 0x000C0180 __TEXT __text...0x10011EFA0 0x00000330 __DATA RCTExport0x10011F2D0 0x00000010 __DATA __common0x10011F2E0 0x000003B8 __DATA __bss...  0x10011EFA0 0x00000010 [ 4] -[RCTStatusBarManager setStyle:animated:].__rct_export_entry__0x10011EFB0 0x00000010 [ 4] -[RCTStatusBarManager setHidden:withAnimation:].__rct_export_entry__0x10011EFC0 0x00000010 [ 5] -[RCTSourceCode getScriptText:failureCallback:].__rct_export_entry__0x10011EFD0 0x00000010 [ 7] -[RCTAlertManager alertWithArgs:callback:].__rct_export_entry__...

可以看到可執行文件數據段多了個RCTExport段,內容就是各個要暴露給JS的方法。這些內容是可以在運行時獲取到的。在運行時提取每個方法的類名和方法名,然后用前綴過濾,就完成了提取模塊里暴露給JS方法的工作。

調用流程

接下來看看JS調用OC模塊方法的詳細流程,包括callback回調。

1.JS端調用某個OC模塊暴露出來的方法。

2.把上一步的調用分解為ModuleName,MethodName,arguments,再扔給MessageQueue處理。

在初始化時模塊配置表上的每一個模塊都生成了對應的remoteModule對象,對象里也生成了跟模塊配置表里一一對應的方法,這些方法里可以拿到自身的模塊名,方法名,并對callback進行一些處理,再移交給MessageQueue。具體實現在BatchedBridgeFactory.js的_createBridgedModule里,整個實現區區24行代碼,感受下JS的魔力吧。

3.在這一步把JS的callback函數緩存在MessageQueue的一個成員變量里,用CallbackID代表callback。在通過保存在MessageQueue的模塊配置表把上一步傳進來的ModuleName和MethodName轉為ModuleID和MethodID。

4.把上述步驟得到的ModuleID,MethodId,CallbackID和其他參數argus傳給OC。至于具體是怎么傳的,后面再說。

5.OC接收到消息,通過模塊配置表拿到對應的模塊和方法。

實際上模塊配置表已經經過處理了,跟JS一樣,在初始化時OC也對模塊配置表上的每一個模塊生成了對應的實例并緩存起來,模塊上的每一個方法也都生成了對應的RCTModuleMethod對象,這里通過ModuleID和MethodID取到對應的Module實例和RCTModuleMethod實例進行調用。具體實現在_handleRequestNumber:moduleID:methodID:params:。

6.RCTModuleMethod對JS傳過來的每一個參數進行處理。

RCTModuleMethod可以拿到OC要調用的目標方法的每個參數類型,處理JS類型到目標類型的轉換,所有JS傳過來的數字都是NSNumber,這里會轉成對應的int/long/double等類型,更重要的是會為block類型參數的生成一個block。

例如-(void)select:(int)index response:(RCTResponseSenderBlock)callback 這個方法,拿到兩個參數的類型為int,block,JS傳過來的兩個參數類型是NSNumber,NSString(CallbackID),這時會把NSNumber轉為int,NSString(CallbackID)轉為一個block,block的內容是把回調的值和CallbackID傳回給JS。

這些參數組裝完畢后,通過NSInvocation動態調用相應的OC模塊方法。

7.OC模塊方法調用完,執行block回調。

8.調用到第6步說明的RCTModuleMethod生成的block。

9.block里帶著CallbackID和block傳過來的參數去調JS里MessageQueue的方法invokeCallbackAndReturnFlushedQueue。

10.MessageQueue通過CallbackID找到相應的JS callback方法。

11.調用callback方法,并把OC帶過來的參數一起傳過去,完成回調。

整個流程就是這樣,簡單概括下,差不多就是:JS函數調用轉ModuleID/MethodID -> callback轉CallbackID -> OC根據ID拿到方法 -> 處理參數 -> 調用OC方法 -> 回調CallbackID -> JS通過CallbackID拿到callback執行

事件響應

上述第4步留下一個問題,JS是怎樣把數據傳給OC,讓OC去調相應方法的?

答案是通過返回值。JS不會主動傳遞數據給OC,在調OC方法時,會在上述第4步把ModuleID,MethodID等數據加到一個隊列里,等OC過來調JS的任意方法時,再把這個隊列返回給OC,此時OC再執行這個隊列里要調用的方法。

一開始不明白,設計成JS無法直接調用OC,需要在OC去調JS時才通過返回值觸發調用,整個程序還能跑得通嗎。后來想想純native開發里的事件響應機制,就有點理解了。native開發里,什么時候會執行代碼?只在有事件觸發的時候,這個事件可以是啟動事件,觸摸事件,timer事件,系統事件,回調事件。而在React Native里,這些事件發生時OC都會調用JS相應的模塊方法去處理,處理完這些事件后再執行JS想讓OC執行的方法,而沒有事件發生的時候,是不會執行任何代碼的,這跟native開發里事件響應機制是一致的。

說到OC調用JS,再補充一下,實際上模塊配置表除了有上述OC的模塊remoteModules外,還保存了JS模塊localModules,OC調JS某些模塊的方法時,也是通過傳遞ModuleID和MethodID去調用的,都會走到-enqueueJSCall:args:方法把兩個ID和參數傳給JS的BatchedBridge.callFunctionReturnFlushedQueue,跟JS調OC原理差不多,就不再贅述了。

總結

整個React Native的JS-OC通信機制大致就是這樣了,關鍵點在于:模塊化,模塊配置表,傳遞ID,封裝調用,事件響應,其設計思想和實現方法很值得學習借鑒。

轉自:http://www.cocoachina.com/ios/20150401/11458.html,部分內容有修改。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
精品美女永久免费视频| www.日韩av.com| 狠狠躁天天躁日日躁欧美| 亚洲国产欧美精品| 欧美日韩高清在线观看| 91免费在线视频网站| 国产狼人综合免费视频| 91亚洲国产成人久久精品网站| 超碰日本道色综合久久综合| 亚洲欧美一区二区三区在线| 亚洲国产精品99久久| 欧美国产视频日韩| 色狠狠av一区二区三区香蕉蜜桃| 欧美一区二区色| 亚洲午夜色婷婷在线| 国产精品第七十二页| 亚洲毛片在线免费观看| 影音先锋日韩有码| 国产精品草莓在线免费观看| 午夜精品久久久久久久久久久久久| 亚洲欧美一区二区激情| 国产精品综合久久久| 国产精品自拍偷拍| 欧美国产日本在线| 欧美小视频在线| 浅井舞香一区二区| 色悠悠国产精品| 97人人爽人人喊人人模波多| 日韩精品视频免费专区在线播放| 久久精品在线视频| 精品国产一区二区三区在线观看| 国外成人在线播放| 日韩天堂在线视频| 欧美综合一区第一页| 欧美一级在线亚洲天堂| 岛国av一区二区| 国产精品av电影| 国产欧美精品一区二区三区介绍| 97在线观看视频国产| 成人黄色av网| 欧美精品一二区| 最近中文字幕日韩精品| 国产999视频| 亚洲国产精品va在线观看黑人| 国产91ⅴ在线精品免费观看| 亚洲国产精品网站| 欧美老女人xx| 欧美一区二区大胆人体摄影专业网站| 不卡av电影院| 中文字幕无线精品亚洲乱码一区| 日本在线精品视频| 日韩欧美极品在线观看| 91夜夜揉人人捏人人添红杏| 精品国模在线视频| 亚洲一区美女视频在线观看免费| 欧美中文字幕精品| 欧美成年人网站| 亚洲国产精品网站| 亚洲欧美在线播放| 亚洲一区二区三区久久| 精品国产乱码久久久久酒店| 欧美日在线观看| 国产精品丝袜久久久久久不卡| 97视频在线观看免费| 久久久国产精品一区| 亚洲国产精品久久久久秋霞蜜臀| 久久亚洲一区二区三区四区五区高| 日韩色av导航| 中文字幕国产精品| 成人黄色免费网站在线观看| 亚洲欧美日韩精品久久亚洲区| 欧美精品激情在线| 亚洲3p在线观看| 2019中文字幕在线观看| 亚洲天堂av在线免费| 欧美专区福利在线| 岛国视频午夜一区免费在线观看| 欧美日本高清一区| 91牛牛免费视频| 午夜剧场成人观在线视频免费观看| 欧美性猛交xxxx乱大交蜜桃| 亚洲一级黄色av| 久久免费少妇高潮久久精品99| 亚洲电影在线看| 亚洲高清在线观看| 欧洲日本亚洲国产区| 久久精品成人一区二区三区| 日韩av在线网页| 欧美国产亚洲精品久久久8v| 欧美午夜激情在线| 国产在线一区二区三区| 国产在线播放91| 精品少妇一区二区30p| 欧美孕妇孕交黑巨大网站| 国产精品久久久久久久久久久久久久| 午夜精品99久久免费| 国内成人精品视频| 亚洲小视频在线观看| 91av视频在线免费观看| 久久国产色av| 九九热视频这里只有精品| 亚洲福利视频网| 欧美性猛交xxxx富婆弯腰| 日韩精品久久久久| 欧美日韩在线免费| 伊人伊人伊人久久| 欧美日韩在线视频观看| 亚洲国产精久久久久久| 亚洲福利在线观看| 日韩av手机在线观看| 亚洲天堂av电影| 欧美激情性做爰免费视频| 亚洲黄色av网站| 久久精品国产精品亚洲| 亚洲国产精久久久久久久| 狠狠操狠狠色综合网| 97视频在线观看成人| 亚洲**2019国产| 日韩在线观看电影| 亚洲天堂第一页| 九九视频这里只有精品| 国产日韩亚洲欧美| 久久久91精品国产一区不卡| 亚洲自拍偷拍视频| 色综合久久88| 在线色欧美三级视频| 亚洲免费小视频| 中文字幕亚洲综合久久筱田步美| 国产成人久久久| 欧美精品久久久久a| 欧美性猛交xxxx乱大交极品| 69久久夜色精品国产69乱青草| 亚洲成人xxx| 亚洲一区二区三区香蕉| 性色av香蕉一区二区| 亚洲成人精品av| 国产精品久久久久77777| 亚洲另类欧美自拍| 2019中文字幕在线免费观看| 亚洲成人亚洲激情| 九九久久精品一区| 中文字幕av一区中文字幕天堂| 中文字幕精品在线| 神马久久桃色视频| 国产一区二区三区久久精品| 色老头一区二区三区在线观看| 久久精品视频99| 国产综合福利在线| 色综合男人天堂| 欧美专区第一页| 国产精品三级美女白浆呻吟| 亚洲综合小说区| 精品久久久久久国产| 精品久久久中文| 精品一区二区三区电影| 国产精品欧美激情在线播放| 欧美在线视频一二三| 91在线视频成人| 国产一区二区三区在线播放免费观看| 中文字幕亚洲欧美一区二区三区| 亚洲裸体xxxx| 欧美精品生活片| 狠狠综合久久av一区二区小说| 国产欧美日韩精品在线观看|