上篇文章说到RN调用原生方法,最终会调用被挂载global上的nativeFlushQueueImmediate函数,但是留下了一个疑问,就是这个函数是怎么具体分发到每个具体的函数中的,
先来看下这个函数的实现,去除异常处理外就调用了callNativeModules(args[0], false);方法。
args[0]是一个二维数组,里面的元素分别是:
第一个元素是moduleID的集合,在iOS里有一个数组,存放着导出的模块,这个moduleID就是这个数组的下标
第二个元素是methodID的集合,表示着导出方法的下标
第三个元素RN调用iOS参数的集合
如果参数中包含了onSucc或者OnFail的回调函数的话,把callID << 1的值加到参数里当做OnFail的标识,把(callID << 1) | 1的值加到参数里当做onSucc的标识。
这样onSucc和OnFail的标识就只有第一位不一样,OnFail第一位为0,onSucc第一位为1。
原生端进行回调的时候,把这个值带上,进行 callID >>> 1就能得到原来的callID, 把这个值与1相&,如果为1,则调用onSucc,否则调用OnFail。
第四个元素是callID,表示当前是第几次调用的原生方法,这里会把当前队列的最后的一次给传回来
上面用二维数组表示的意义是,为了不频繁与原生进行交互,在RN端有个判断逻辑是,如果当前的时间与上一次调用时间的时间差小于5毫秒,则把这次调用的信息存放到这个二维数组中,等到下一次调用的时候,把多次的调用信息传到iOS端
再回到callNativeModules函数中,首先会把二维数组args[0]转成MethodCall类型的数组,MethodCall结构如下
struct MethodCall {
int moduleId; /// 模块ID,对应的模块数组中的下标
int methodId;/// 方法ID,对应的方法数组中的下标
folly::dynamic arguments;/// 参数
int callId;
};
复制代码
接下来会通过moduleId得到对应的模块(RCTNativeModule),再通过methodId得到对应的方法(RCTModuleMethod),RCTModuleMethod获取到OC里的方法名字,如testPromise:(nullable NSString *)name resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject,会对这个名字进行处理,得到selector testPromise: resolve: rejecter:和所有的所有的参数类型,处理的逻辑见RCTModuleMethod的processMethodSignature方法。
得到selector之后,通过selector获取到NSMethodSignature,在通过NSMethodSignature生成NSInvocation。
再把RN端传过来的参数传承NSInvocation所对应类型的参数,然后执行NSInvocation,执行NSInvocation的target,是RCTNativeModule中所保存的对应模块的实例,该实例是在初始化的时候创建的,并且之会创建一次,调用new方法调用的。
如果调用了上面的resolve或者rejecter的回调,那么会调用RCTCxxBridge的- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args,最终又会调用MessageQueue.js中的invokeCallbackAndReturnFlushedQueue方法,进行处理回调,会有2个参数,一个是左移之后的callID,一个是回调带回去的结果。
invokeCallbackAndReturnFlushedQueue内部会通过callID找到对应的回调函数去执行,然后会把会把queue中未执行的消息给返回回来,这个时候,原生端就会再去调用这些方法,如此反复。
作者:李坤
链接:https://juejin.cn/post/6966168407146233863
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
共同学习,写下你的评论
评论加载中...
作者其他优质文章