这是rn最传统的通信方式,基于0.64代码梳理。
整体看,仍然是基于跨语言interop能力额外搭建了一套通信方式。
方法定义和绑定
信道建立
双端的接口定义是割裂的,并没有一个地方做唯一类型验证。
js侧
- 用了一个很奇怪(不熟悉js语法,别的语言没见过这个写法)的+method的方式定义方法,并传给TurboModuleRegistry
- TurboModuleRegistry#getEnforcing->requireModule->NativeModules.js->根方法,初始化NativeModules->genModule,这里面会消费native产生的__fbBatchedBridgeConfig
- 动态生成一个对象,根据上面定义的module,#genMethod->方法内容就是转调BatchedBridge#enqueueNativeCall
java侧
- 启动流程略过->这里起了个新线程,CatalystInstanceImpl#initializeBridge->CatalystInstanceImpl.cpp#initializeBridge->buildNativeModuleList->new JavaNativeModule->ModuleRegistry#registerModules,这里持有了一个name to index to arrayItem(module)的映射关系
- ProxyExecutor#initializeRuntime->ModuleRegistry#getConfig
- JavaNativeModule#getMethods->JavaModuleWrapper.java#getMethodDescriptors->findMethods->反射methods并构建JavaMethodWrapper,把映射存下来
- 接上文->把config存到js中的__fbBatchedBridgeConfig指针上
js call java
- BatchedBridge#enqueueNativeCall,加入到_queue,注意这里的_queue是object[4][],相同index代表了一个调用->如果队列中有等待超过5ms的调用则,global.nativeFlushQueueImmediate->JSIExecutor.cpp#callNativeModules,这里会把jsi(是的BatchedBridge也是jsi)对象转成folly::dynamic,有内存拷贝->JsToNativeBridge#callNativeModules->MethodCall#parseMethodCalls->ModuleRegistry#callNativeMethod->JavaNativeModule#invoke,切到shadowThread->JavaModuleWrapper.java#invoke->JavaMethodWrapper#invoke处理数据,然后反射调用到真正方法
java call js
有一个callFunction,比较简单,不赘述。
类型约束及传输
类型见官网。
传输主要两部分:jsi->folly::dynamic,folly::dynamic->ReadableNativeArray/Map。
js->c++
JSI的Value是个Union的封装,folly::dynamic也是个Union封装。
JSIDynamic.cpp#dynamicFromValue->dynamicFromValueShallow,这里会把需要深拷贝的类型加到一个栈里->依次把栈里的数据dynamicFromValueShallow。
c+±>java
主要是folly::hybrid,也是一个跨语言通信的小框架。以ReadableNativeArray为例。
方法定义和绑定
JNIEnv#registerNatives关联java和native方法。
数据传输
在传递数据的时候,把dynamic转成对应的jobject/jprimitive(addDynamicToJArray)。
gc
也是PhantomReference方案。为每个HybridData创建了一个PhantomReference(叫Destructor),然后加到了全局唯一的ReferenceQueue里。启动一个daemon线程,死循环清理这个queue里的reference。
不明就里,但是会有个全局变量持有所有的Destructor。逻辑上有一个很有意思的多线程优化:
- Destructor会在构造线程先加入到一个treiber stack中,这个stack使用compareAndSwap做到了无锁。
- 仅在DestructorThread,会把stack dump到一个无锁双向队列中。
由此做到了无锁、线程安全的把所有的Destructor都集中到了队列中。