上篇文章說(shuō)到RN調(diào)用原生方法医窿,最終會(huì)調(diào)用被掛載global上的nativeFlushQueueImmediate
函數(shù),但是留下了一個(gè)疑問(wèn)姥卢,就是這個(gè)函數(shù)是怎么具體分發(fā)到每個(gè)具體的函數(shù)中的。
先來(lái)看下這個(gè)函數(shù)的實(shí)現(xiàn)僧叉,去除異常處理外就調(diào)用了callNativeModules(args[0], false);
方法棺榔。
args[0]
是一個(gè)二維數(shù)組,里面的元素分別是:
第一個(gè)元素是moduleID的集合症歇,在iOS里有一個(gè)數(shù)組,存放著導(dǎo)出的模塊宛蚓,這個(gè)moduleID就是這個(gè)數(shù)組的下標(biāo)
第二個(gè)元素是methodID的集合设塔,表示著導(dǎo)出方法的下標(biāo)
-
第三個(gè)元素RN調(diào)用iOS參數(shù)的集合
如果參數(shù)中包含了onSucc或者OnFail的回調(diào)函數(shù)的話,把callID << 1
的值加到參數(shù)里當(dāng)做OnFail的標(biāo)識(shí),把(callID << 1) | 1
的值加到參數(shù)里當(dāng)做onSucc的標(biāo)識(shí)表谊。這樣onSucc和OnFail的標(biāo)識(shí)就只有第一位不一樣盖喷,OnFail第一位為0难咕,onSucc第一位為1。
原生端進(jìn)行回調(diào)的時(shí)候余佃,把這個(gè)值帶上,進(jìn)行
callID >>> 1
就能得到原來(lái)的callID
爆土, 把這個(gè)值與1相&,如果為1氧猬,則調(diào)用onSucc坏瘩,否則調(diào)用OnFail。 第四個(gè)元素是callID,表示當(dāng)前是第幾次調(diào)用的原生方法倔矾,這里會(huì)把當(dāng)前隊(duì)列的最后的一次給傳回來(lái)
上面用二維數(shù)組表示的意義是,為了不頻繁與原生進(jìn)行交互丰包,在RN端有個(gè)判斷邏輯是壤巷,如果當(dāng)前的時(shí)間與上一次調(diào)用時(shí)間的時(shí)間差小于5毫秒,則把這次調(diào)用的信息存放到這個(gè)二維數(shù)組中胧华,等到下一次調(diào)用的時(shí)候,把多次的調(diào)用信息傳到iOS端
再回到callNativeModules
函數(shù)中瘸爽,首先會(huì)把二維數(shù)組args[0]轉(zhuǎn)成MethodCall
類型的數(shù)組铅忿,MethodCall
結(jié)構(gòu)如下
struct MethodCall {
int moduleId; /// 模塊ID,對(duì)應(yīng)的模塊數(shù)組中的下標(biāo)
int methodId;/// 方法ID,對(duì)應(yīng)的方法數(shù)組中的下標(biāo)
folly::dynamic arguments;/// 參數(shù)
int callId;
};
接下來(lái)會(huì)通過(guò)moduleId得到對(duì)應(yīng)的模塊(RCTNativeModule)享言,再通過(guò)methodId得到對(duì)應(yīng)的方法(RCTModuleMethod),RCTModuleMethod獲取到OC里的方法名字渗鬼,如testPromise:(nullable NSString *)name resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject
,會(huì)對(duì)這個(gè)名字進(jìn)行處理,得到selector testPromise: resolve: rejecter:
和所有的所有的參數(shù)類型,處理的邏輯見(jiàn)RCTModuleMethod
的processMethodSignature
方法差牛。
得到selector之后,通過(guò)selector獲取到NSMethodSignature
偏化,在通過(guò)NSMethodSignature
生成NSInvocation
镐侯。
再把RN端傳過(guò)來(lái)的參數(shù)傳承NSInvocation
所對(duì)應(yīng)類型的參數(shù),然后執(zhí)行NSInvocation
苟翻,執(zhí)行NSInvocation
的target,是RCTNativeModule
中所保存的對(duì)應(yīng)模塊的實(shí)例怜俐,該實(shí)例是在初始化的時(shí)候創(chuàng)建的邓尤,并且之會(huì)創(chuàng)建一次,調(diào)用new
方法調(diào)用的汞扎。
如果調(diào)用了上面的resolve
或者rejecter
的回調(diào),那么會(huì)調(diào)用RCTCxxBridge
的- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args
,最終又會(huì)調(diào)用MessageQueue.js
中的invokeCallbackAndReturnFlushedQueue
方法景鼠,進(jìn)行處理回調(diào)痹扇,會(huì)有2個(gè)參數(shù),一個(gè)是左移之后的callID鲫构,一個(gè)是回調(diào)帶回去的結(jié)果。
invokeCallbackAndReturnFlushedQueue
內(nèi)部會(huì)通過(guò)callID找到對(duì)應(yīng)的回調(diào)函數(shù)去執(zhí)行包晰,然后會(huì)把會(huì)把queue中未執(zhí)行的消息給返回回來(lái),這個(gè)時(shí)候伐憾,原生端就會(huì)再去調(diào)用這些方法,如此反復(fù)蒸矛。