ReactNative TurboModule(3)

news/2024/10/28 16:14:49/

ReactNative TurboModule

简述

ReactNative新架构的两个核心支柱是TurboModule和Fabric渲染器,前者的功能是提供一个Native的模块,比如蓝牙之类的,后者则是提供一个自定义Native UI组件的能力,ReactNative本身虽然提供了非常多的组件,但是如果想要实现像Android自定义View一些复杂的组件UI效果,就需要自己定义Fabric组件,其实他们的核心都是通过jsi实现js和Native通信,然后在Android上则是通过jni实现Java和C++通信,最终达到js和Java层通信的效果,TurboModule和Fabric只是提供的接口不同,流程不同。
我们这一节先来了解一下TurboModule,TurboModule的逻辑相较于Fabric更加简单一些,所以先从TurboModule开始学习。

关于TurboModule的使用ReactNative官网上有详细的流程,我们就不过多介绍了,主要来介绍一下TurboModule的组件做了什么,怎么样实现JS和Java通信的。

Demo

我们自己定义一个TurboModule,然后基于这个TurboModule来介绍它的原理。
我们定义一个js文件,输出一个TurboModule,然后使用Codegen来生产脚手架。
Codegen的作用类似于aidl,帮助我们生成一些固定格式的代码,只是格式上和aidl不一样。

// @flow
import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport';
import { TurboModuleRegistry } from 'react-native';export interface Spec extends TurboModule {
add(a: number, b: number): Promise<number>;
}
export default (TurboModuleRegistry.get<Spec>(
'RTNTurboTest'
): ?Spec);

我们来看看生成的文件,其中这里大多数文件都是没有用到的,如EventEmitters,Props,ShadowNode,State都没有用到,这些都是给Fabric使用的,映射JS层UI属性之类的,所以才说TurboModule的框架比Fabric更加简单,这些后续我们在介绍Fabric时会再介绍一下。
在这里插入图片描述

这里我们先来看NativeTurboTestSpec,我们最终的实现就是需要通过继承这个类,然后实现add方法,然后脚手架以及TurboModule框架帮助我们做的事情就是后续我们可以直接在JS中调用add方法,最终就会调用到我们实现的NativeTurboTestSpec子类的add方法中。
所以接下来我们要分析的就是ReactNative是怎么做到这个JS调用add最终调用到Java层的add中去的。

public abstract class NativeTurboTestSpec extends ReactContextBaseJavaModule implements TurboModule {public static final String NAME = "RTNTurboTest";public NativeTurboTestSpec(ReactApplicationContext reactContext) {super(reactContext);}@Overridepublic @Nonnull String getName() {return NAME;}// 需要业务实现@ReactMethod@DoNotStrippublic abstract void add(double a, double b, Promise promise);
}

加载流程

在上一章介绍应用启动的流程中我们提到过,ReactInstance是React在Java侧最重要的管理类,加载TurboModule的包其实也由ReactInstance在构造函数中处理的。

我们接着上一章2.9,来看ReactInstance的构造函数。

1.1 ReactInstance
我们省略其他代码,只看TurboModule相关的逻辑。

/* package */ ReactInstance(BridgelessReactContext bridgelessReactContext,ReactHostDelegate delegate,ComponentFactory componentFactory,DevSupportManager devSupportManager,QueueThreadExceptionHandler exceptionHandler,boolean useDevSupport,@Nullable ReactHostInspectorTarget reactHostInspectorTarget) {// ...mReactPackages = new ArrayList<>();// 添加React的核心package,这些事ReactNative自己的TurboModulemReactPackages.add(new CoreReactPackage(bridgelessReactContext.getDevSupportManager(),bridgelessReactContext.getDefaultHardwareBackBtnHandler()));if (useDevSupport) {// 如果是debug模式mReactPackages.add(new DebugCorePackage());}// 调用ReactHostDelegate的getReactPackages获取其他的ReactPackages// 这个方法最终会调用Applcation里面定义的reactNativeHost匿名内部类的getReactPackages,详见1.1.1  mReactPackages.addAll(mDelegate.getReactPackages());TurboModuleManagerDelegate turboModuleManagerDelegate =mDelegate// 这里获取的build是DefaultTurboModuleManagerDelegate.Builder().getTurboModuleManagerDelegateBuilder().setPackages(mReactPackages).setReactApplicationContext(mBridgelessReactContext)// 详见1.2.build();RuntimeExecutor unbufferedRuntimeExecutor = getUnbufferedRuntimeExecutor();// 构造TurboModuleManager,TurboModuleManager持有turboModuleManagerDelegate,就可以通过turboModuleManagerDelegate来管理所有的Package。 // 详见1.6 mTurboModuleManager =new TurboModuleManager(// Use unbuffered RuntimeExecutor to install bindingunbufferedRuntimeExecutor,turboModuleManagerDelegate,getJSCallInvokerHolder(),getNativeMethodCallInvokerHolder());Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);// ...
}

1.1.1 ReactHostDelegate.getReactPackages
调用PackageList.getPackages 获取需要添加的包。

override val reactNativeHost: ReactNativeHost =object : DefaultReactNativeHost(this) {override fun getPackages(): List<ReactPackage> =// 调用PackageList获取packages,详见1.1.2PackageList(this).packages.apply {// Packages that cannot be autolinked yet can be added manually here, for example:// add(MyReactNativePackage())}override fun getJSMainModuleName(): String = "index"override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUGoverride val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLEDoverride val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED}

1.1.2 PackageList.getPackages
TurboTestPackage是我们自己定义的Package,所有自己定义的包。不只是TurboMoudle,Fabric也是在这里添加的。
这里的代码是我们通过Codegen生成模块的时候自动添加的。

public ArrayList<ReactPackage> getPackages() {return new ArrayList<>(Arrays.<ReactPackage>asList(new MainReactPackage(mConfig),new TurboTestPackage()));
}

1.2 DefaultTurboModuleManagerDelegate.Builder.build
构造DefaultTurboModuleManagerDelegate

override fun build(context: ReactApplicationContext,packages: List<ReactPackage>
): DefaultTurboModuleManagerDelegate {val cxxReactPackages = mutableListOf<CxxReactPackage>()for (cxxReactPackageProvider in cxxReactPackageProviders) {cxxReactPackages.add(cxxReactPackageProvider(context))}// 详见1.3return DefaultTurboModuleManagerDelegate(context, packages, cxxReactPackages)
}

1.3 DefaultTurboModuleManagerDelegate
DefaultTurboModuleManagerDelegate是ReactPackageTurboModuleManagerDelegate的子类。
调用了initialize方法。

protected ReactPackageTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext,List<ReactPackage> packages,HybridData hybridData) {super(hybridData);// 调用了initialize,详见1.4initialize(reactApplicationContext, packages);
}

1.4 ReactPackageTurboModuleManagerDelegate.initialize
这里的逻辑主要是通过收集的ReactPackage的getReactModuleInfoProvider提供的Provider,来获取每个Package包函的Module的ModuleInfo,我们自定义TurboModule时,这个getReactModuleInfoProvider是需要我们自己来实现的。
这里还存储了moduleProvider,它会调用package的getModule,这个getModule也是我们自己定义的,是new Module对象的地方。

private void initialize(ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {final ReactApplicationContext applicationContext = reactApplicationContext;// 遍历所有的ReactPackagefor (ReactPackage reactPackage : packages) {if (reactPackage instanceof BaseReactPackage) {// 如果是BaseReactPackage,需要加载Provider,获取ModuleInfo// TurboReactPackage是BaseReactPackage的子类,所以也会走这里final BaseReactPackage baseReactPackage = (BaseReactPackage) reactPackage;// 这里构建的Provider会调用package的getModule,这个getModule也是我们自己定义的,是new Module对象的地方。  final ModuleProvider moduleProvider =moduleName -> baseReactPackage.getModule(moduleName, applicationContext);mModuleProviders.add(moduleProvider);// 这里会获取对应的Package的ModuleInfos,如果是自定义的TurboModule,这个getReactModuleInfos是需要我们实现的。// 这里我们以我们自定义的TurboTestModule为例来看看,详见1.5mPackageModuleInfos.put(moduleProvider, baseReactPackage.getReactModuleInfoProvider().getReactModuleInfos());continue;}// ...}
}

1.5 TurboTestPackage
这个是我们自己定义的TurboModule,这里的逻辑就是照着官网的指引文档写的,主要是提供了两个方法,getReactModuleInfoProvider和getModule。
到这里,ReactPackageTurboModuleManagerDelegate就已经持有了所有的TurboModule的Info,后续只需要通过ReactPackageTurboModuleManagerDelegate我们就可以根据ModuleName来调用getModule构造对应的Module,后面构造了TurboModuleManager,TurboModuleManager持有ReactPackageTurboModuleManagerDelegate,后续就可以通过TurboModuleManager来获取或者构造对应的Module。

public class TurboTestPackage extends TurboReactPackage {@Nullable@Overridepublic NativeModule getModule(String name, ReactApplicationContext reactContext) {if (name.equals(TurboTestModule.NAME)) {return new TurboTestModule(reactContext);} else {return null;}}@Overridepublic ReactModuleInfoProvider getReactModuleInfoProvider() {return () -> {final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();moduleInfos.put(TurboTestModule.NAME,new ReactModuleInfo(TurboTestModule.NAME,TurboTestModule.NAME,false, // canOverrideExistingModulefalse, // needsEagerInittrue, // hasConstantsfalse, // isCxxModuletrue // isTurboModule));return moduleInfos;};}
}

接下来我们来看一下TurboModuleManager,这里有比较关键的和C++绑定的逻辑,因为ReactNative有非常多的java和C++通信的逻辑都是通过这样的Binding来实现的,所以这里我们来看一下这个流程。

1.6 TurboModuleManager
调用installJSIBindings来构建JSI的绑定,绑定后就可以实现从JS层-〉C++ -〉Java的调用。

public TurboModuleManager(RuntimeExecutor runtimeExecutor,@Nullable final TurboModuleManagerDelegate delegate,CallInvokerHolder jsCallInvokerHolder,NativeMethodCallInvokerHolder nativeMethodCallInvokerHolder) {mDelegate = delegate;mHybridData =initHybrid(runtimeExecutor,(CallInvokerHolderImpl) jsCallInvokerHolder,(NativeMethodCallInvokerHolderImpl) nativeMethodCallInvokerHolder,delegate);// 关联JSI,构建C++,Java和JS层通信,详见1.7installJSIBindings(shouldEnableLegacyModuleInterop(), enableSyncVoidMethods());mEagerInitModuleNames =delegate == null ? new ArrayList<>() : delegate.getEagerInitModuleNames();ModuleProvider nullProvider = moduleName -> null;// 封装delegate,后续可以通过这个provider根据moduleName获取对应/构建的ModulemTurboModuleProvider =delegate == null? nullProvider: moduleName -> (NativeModule) delegate.getModule(moduleName);mLegacyModuleProvider =delegate == null || !shouldEnableLegacyModuleInterop()? nullProvider: moduleName -> {NativeModule nativeModule = delegate.getLegacyModule(moduleName);if (nativeModule != null) {// TurboModuleManagerDelegate.getLegacyModule must never return a TurboModuleAssertions.assertCondition(!(nativeModule instanceof TurboModule),"NativeModule \"" + moduleName + "\" is a TurboModule");return nativeModule;}return null;};
}

1.7 TurboModuleManager.installJSIBindings
这是一个native方法,调用到TurboModuleManager::installJSIBindings

void TurboModuleManager::installJSIBindings(jni::alias_ref<jhybridobject> javaPart,bool shouldCreateLegacyModules,bool enableSyncVoidMethods) {
auto cxxPart = javaPart->cthis();
if (cxxPart == nullptr || !cxxPart->jsCallInvoker_) {return; // Runtime doesn't exist when attached to Chrome debugger.
}cxxPart->runtimeExecutor_([cxxPart,javaPart = jni::make_global(javaPart),shouldCreateLegacyModules,enableSyncVoidMethods](jsi::Runtime& runtime) {// 调用了TurboModuleBinding::installTurboModuleBinding::install(runtime,// 这里构造的moduleProvider,后续通过moduleProvider来构造ModulecxxPart->createTurboModuleProvider(javaPart, &runtime, enableSyncVoidMethods),shouldCreateLegacyModules? cxxPart->createLegacyModuleProvider(javaPart): nullptr);
});
}

1.8 TurboModuleBinding::install
通过JSI绑定了JS的一些全局变量。比如global.__turboModuleProxy。

void TurboModuleBinding::install(jsi::Runtime& runtime,TurboModuleProviderFunctionType&& moduleProvider,TurboModuleProviderFunctionType&& legacyModuleProvider,std::shared_ptr<LongLivedObjectCollection> longLivedObjectCollection) {// 绑定global.__turboModuleProxy,后续可以通过JS global.__turboModuleProxy调用到这里构建的方法。  runtime.global().setProperty(runtime,"__turboModuleProxy",jsi::Function::createFromHostFunction(runtime,jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),1,[binding = TurboModuleBinding(runtime, std::move(moduleProvider), longLivedObjectCollection)](jsi::Runtime& rt,const jsi::Value& thisVal,const jsi::Value* args,size_t count) {if (count < 1) {throw std::invalid_argument("__turboModuleProxy must be called with at least 1 argument");}std::string moduleName = args[0].getString(rt).utf8(rt);return binding.getModule(rt, moduleName);}));// 根据JS属性RN$Bridgeless  来判断是否需要绑定后续的属性。if (runtime.global().hasProperty(runtime, "RN$Bridgeless")) {bool rnTurboInterop = legacyModuleProvider != nullptr;auto turboModuleBinding = legacyModuleProvider? std::make_unique<TurboModuleBinding>(runtime,std::move(legacyModuleProvider),longLivedObjectCollection): nullptr;auto nativeModuleProxy = std::make_shared<BridgelessNativeModuleProxy>(std::move(turboModuleBinding));defineReadOnlyGlobal(runtime, "RN$TurboInterop", jsi::Value(rnTurboInterop));defineReadOnlyGlobal(runtime,"nativeModuleProxy",jsi::Object::createFromHostObject(runtime, nativeModuleProxy));}
}

调用和创建TurboModule流程

我们从我们定义的js文件开始。
2.1 NativeTurboTest.js
这个文件是我们自己定义的,也是根据官方文档指引写的。
调用了TurboModuleRegistry.get来构造export的Spec。

// @flow
import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport';
import { TurboModuleRegistry } from 'react-native';export interface Spec extends TurboModule {
add(a: number, b: number): Promise<number>;
}// 通过TurboModuleRegistry.get获取,详见1.2
export default (TurboModuleRegistry.get<Spec>(
'RTNTurboTest'
): ?Spec);

2.2 TurboModuleRegistry.get

export function get<T: TurboModule>(name: string): ?T {// 详见2.3return requireModule<T>(name);
}

2.3 requireModule

function requireModule<T: TurboModule>(name: string): ?T {if (!isBridgeless() || isTurboModuleInteropEnabled()) {// ... 旧的架构逻辑}// 新架构,通过turboModuleProxy来获取目标Moduleif (turboModuleProxy != null) {const module: ?T = turboModuleProxy(name);if (module != null) {if (shouldReportDebugInfo()) {moduleLoadHistory.TurboModules.push(name);}return module;}}// ...
}

2.4 turboModuleProxy
turboModuleProxy就是global.__turboModuleProxy,我们在1.8提到过,已经通过JSI将global.__turboModuleProxy和C++的方法绑定了。

const turboModuleProxy = global.__turboModuleProxy;

2.5 global.__turboModuleProxy
这里到C++层了,这里调用了TurboModuleBinding.getModule来获取Module。

void TurboModuleBinding::install(jsi::Runtime& runtime,TurboModuleProviderFunctionType&& moduleProvider,TurboModuleProviderFunctionType&& legacyModuleProvider,std::shared_ptr<LongLivedObjectCollection> longLivedObjectCollection) {runtime.global().setProperty(runtime,"__turboModuleProxy",jsi::Function::createFromHostFunction(runtime,jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),1,[binding = TurboModuleBinding(// global.__turboModuleProxy方法会通过JSI到这里。runtime, std::move(moduleProvider), longLivedObjectCollection)](jsi::Runtime& rt,const jsi::Value& thisVal,const jsi::Value* args,size_t count) {if (count < 1) {throw std::invalid_argument("__turboModuleProxy must be called with at least 1 argument");}std::string moduleName = args[0].getString(rt).utf8(rt);// 调用了getModule来获取Module,详见2.6return binding.getModule(rt, moduleName);}));// ...
}

2.6 TurboModuleBinding::getModule
这里通过moduleProvider_来构造Module,这里的moduleProvider_是1.7通过cxxPart->createTurboModuleProvider构造的。
获取到Module后,Module里面有一个jsRepresentation_,这个jsRepresentation_是一个类似于句柄的东西,给JS层使用的,如果用过jni的话一般Java层会持有一个C++层的地址作为句柄,这里也是类似。

jsi::Value TurboModuleBinding::getModule(jsi::Runtime& runtime,const std::string& moduleName) const {std::shared_ptr<TurboModule> module;{SystraceSection s("TurboModuleBinding::moduleProvider", "module", moduleName);// 这里moduleProvider_是1.7通过cxxPart->createTurboModuleProvider构造的,详见2.7module = moduleProvider_(moduleName);}if (module) {// 这里获取Module的jsRepresentation_,这个类似于句柄,给JS层使用的,如果用过jni的话一般Java层会持有一个C++层的地址作为句柄,这里也是类似。  auto& weakJsRepresentation = module->jsRepresentation_;if (weakJsRepresentation) {auto jsRepresentation = weakJsRepresentation->lock(runtime);if (!jsRepresentation.isUndefined()) {return jsRepresentation;}}jsi::Object jsRepresentation(runtime);weakJsRepresentation =std::make_unique<jsi::WeakObject>(runtime, jsRepresentation);auto hostObject =jsi::Object::createFromHostObject(runtime, std::move(module));jsRepresentation.setProperty(runtime, "__proto__", std::move(hostObject));return jsRepresentation;} else {return jsi::Value::null();}
}

2.7 TurboModuleManager::createTurboModuleProvider
TurboModule分非常多种类,JavaModule,CxxModule,然后由于要兼容旧架构,还有leacyModule,会根据module不同的类型使用不同的方法来创建不同的Module,但是其实最终调用的方法是一样的。
这里我们就跟JavaModule的逻辑,构建了Java层的getTurboJavaModule方法并调用,ReactNative中java和C++的交互和jni看起来不太一样,其实是他们对jni又做了一次封装。(不得不说写前端的人非常喜欢框架)
delegate->cthis()->getTurboModule是绑定C++逻辑的,就是在这里和我们Codegen生成的脚手架关联,我们到第三小节来介绍这个。

TurboModuleProviderFunctionType TurboModuleManager::createTurboModuleProvider(jni::alias_ref<jhybridobject> javaPart,jsi::Runtime* runtime,bool enableSyncVoidMethods) {
return [turboModuleCache_ = std::weak_ptr<ModuleCache>(turboModuleCache_),runtime,jsCallInvoker_ = std::weak_ptr<CallInvoker>(jsCallInvoker_),nativeMethodCallInvoker_ =std::weak_ptr<NativeMethodCallInvoker>(nativeMethodCallInvoker_),weakDelegate = jni::make_weak(delegate_),weakJavaPart = jni::make_weak(javaPart),enableSyncVoidMethods](const std::string& name) -> std::shared_ptr<TurboModule> {// ...// 先从缓存里查找是否存在对应name的Moduleauto turboModuleLookup = turboModuleCache->find(name);if (turboModuleLookup != turboModuleCache->end()) {TurboModulePerfLogger::moduleJSRequireBeginningCacheHit(moduleName);TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName);return turboModuleLookup->second;}TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName);// 通过delegate的getTurboModule构建对应Moduleauto cxxModule = delegate->cthis()->getTurboModule(name, jsCallInvoker);if (cxxModule) {turboModuleCache->insert({name, cxxModule});return cxxModule;}// 从GlobalModuleMap中查找是否存在对应的Moduleauto& cxxTurboModuleMapProvider = globalExportedCxxTurboModuleMap();auto it = cxxTurboModuleMapProvider.find(name);if (it != cxxTurboModuleMapProvider.end()) {auto turboModule = it->second(jsCallInvoker);turboModuleCache->insert({name, turboModule});return turboModule;}// 如果是legacyCxxModule,则通过getTurboLegacyCxxModule来获取// legacyCxxModule是适配旧架构用的。  static auto getTurboLegacyCxxModule =javaPart->getClass()->getMethod<jni::alias_ref<CxxModuleWrapper::javaobject>(const std::string&)>("getTurboLegacyCxxModule");auto legacyCxxModule = getTurboLegacyCxxModule(javaPart.get(), name);if (legacyCxxModule) {TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName);auto turboModule = std::make_shared<react::TurboCxxModule>(legacyCxxModule->cthis()->getModule(), jsCallInvoker);turboModuleCache->insert({name, turboModule});TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName);return turboModule;}// 正常的JavaTruboModule,通过getTurboJavaModule来构建,这里getTurboJavaModule就是Java层的getTurboJavaModule方法了,详见2.8static auto getTurboJavaModule =javaPart->getClass()->getMethod<jni::alias_ref<JTurboModule>(const std::string&)>("getTurboJavaModule");auto moduleInstance = getTurboJavaModule(javaPart.get(), name);if (moduleInstance) {TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName);JavaTurboModule::InitParams params = {.moduleName = name,.instance = moduleInstance,.jsInvoker = jsCallInvoker,.nativeMethodCallInvoker = nativeMethodCallInvoker,.shouldVoidMethodsExecuteSync = enableSyncVoidMethods};// 详见3.1auto turboModule = delegate->cthis()->getTurboModule(name, params);if (moduleInstance->isInstanceOf(JTurboModuleWithJSIBindings::javaClassStatic())) {static auto getBindingsInstaller =JTurboModuleWithJSIBindings::javaClassStatic()->getMethod<BindingsInstallerHolder::javaobject()>("getBindingsInstaller");auto installer = getBindingsInstaller(moduleInstance);if (installer) {// 详见installer->cthis()->installBindings(*runtime);}}// 将新构造的turboModule插入缓存turboModuleCache->insert({name, turboModule});TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName);return turboModule;}return nullptr;};
}

2.8 TurboModuleManager.getTurboJavaModule
调用了getModule来获取Module。

private TurboModule getTurboJavaModule(String moduleName) {if (shouldRouteTurboModulesThroughLegacyModuleInterop()) {return null;}if (!isTurboModule(moduleName)) {return null;}// 调用了getModule,其实其他什么CxxModule最终也是调用这个方法来获取Module的,只是在返回值判断有效性的时候有所差异。 // 详见2.9 final NativeModule module = getModule(moduleName);return !(module instanceof CxxModuleWrapper) && module instanceof TurboModule? (TurboModule) module: null;
}

2.9 TurboModuleManager.getModule
主要就是调用了getOrCreateModule来获取/创建Module,其他的就是一个缓存逻辑,只创建一次,后续使用之前创建的。

public NativeModule getModule(String moduleName) {ModuleHolder moduleHolder;synchronized (mModuleCleanupLock) {if (mModuleCleanupStarted) {// ...return null;}// 这里是一个缓存逻辑if (!mModuleHolders.containsKey(moduleName)) {mModuleHolders.put(moduleName, new ModuleHolder());}moduleHolder = mModuleHolders.get(moduleName);}TurboModulePerfLogger.moduleCreateStart(moduleName, moduleHolder.getModuleId());NativeModule module = getOrCreateModule(moduleName, moduleHolder, true);if (module != null) {TurboModulePerfLogger.moduleCreateEnd(moduleName, moduleHolder.getModuleId());} else {TurboModulePerfLogger.moduleCreateFail(moduleName, moduleHolder.getModuleId());}return module;
}

2.10 TurboModuleManager.getOrCreateModule

@Nullable
private NativeModule getOrCreateModule(String moduleName, @NonNull ModuleHolder moduleHolder, boolean shouldPerfLog) {boolean shouldCreateModule = false;synchronized (moduleHolder) {// 如果有缓存,就直接返回if (moduleHolder.isDoneCreatingModule()) {if (shouldPerfLog) {TurboModulePerfLogger.moduleCreateCacheHit(moduleName, moduleHolder.getModuleId());}return moduleHolder.getModule();}if (!moduleHolder.isCreatingModule()) {// Only one thread gets hereshouldCreateModule = true;moduleHolder.startCreatingModule();}}// 需要新建Moduleif (shouldCreateModule) {TurboModulePerfLogger.moduleCreateConstructStart(moduleName, moduleHolder.getModuleId());// 这个mTurboModuleProvider是1.6构造函数时候创建的// 最终是调用delegate.getModule(moduleName),详见2.11NativeModule nativeModule = mTurboModuleProvider.getModule(moduleName);if (nativeModule == null) {nativeModule = mLegacyModuleProvider.getModule(moduleName);}TurboModulePerfLogger.moduleCreateConstructEnd(moduleName, moduleHolder.getModuleId());TurboModulePerfLogger.moduleCreateSetUpStart(moduleName, moduleHolder.getModuleId());if (nativeModule != null) {synchronized (moduleHolder) {moduleHolder.setModule(nativeModule);}nativeModule.initialize();} else {// ...}TurboModulePerfLogger.moduleCreateSetUpEnd(moduleName, moduleHolder.getModuleId());synchronized (moduleHolder) {moduleHolder.endCreatingModule();moduleHolder.notifyAll();}return nativeModule;}synchronized (moduleHolder) {boolean wasInterrupted = false;while (moduleHolder.isCreatingModule()) {try {// Wait until TurboModule is created and initializedmoduleHolder.wait();} catch (InterruptedException e) {wasInterrupted = true;}}if (wasInterrupted) {/** TurboModules should ideally be quick to create and initialize. Therefore,* we wait until the TurboModule is done initializing before re-interrupting the* current thread.*/Thread.currentThread().interrupt();}return moduleHolder.getModule();}
}

2.11 ReactPackageTurboModuleManagerDelegate.getModule
这里会遍历mModuleProviders,mModuleProviders里的ModuleProvider是我们1.4构建的,调用package的getModule。
package的getModule见1.5,我们自定义的TurboTestPackage会返回一个TurboTestModule。
到这加载流程就完成了。

public TurboModule getModule(String moduleName) {NativeModule resolvedModule = null;// 这里的mModuleProviders是1.4构建的,会调用每个package的getModule方法,而package的getMoudle是我们自己实现的// 见1.5 TurboTestModule,我们会在getModule返回一个TurboTestModule实例。  for (final ModuleProvider moduleProvider : mModuleProviders) {final ReactModuleInfo moduleInfo = mPackageModuleInfos.get(moduleProvider).get(moduleName);if (moduleInfo != null&& moduleInfo.isTurboModule()&& (resolvedModule == null || moduleInfo.canOverrideExistingModule())) {final NativeModule module = moduleProvider.getModule(moduleName);if (module != null) {resolvedModule = module;}}}boolean isLegacyModule = !(resolvedModule instanceof TurboModule);if (isLegacyModule) {return null;}return (TurboModule) resolvedModule;
}

调用流程

接下来我们看一下在JS层获取对应的Module后怎么通过JS方法调用到对应Module的Java层。

在2.7小节的时候提到了,如果是JavaModule还会调用delegate->cthis()->getTurboModule来和脚手架进行关联,我们从这里开始。

3.1 DefaultTurboModuleManagerDelegate::getTurboModule
这里调用了javaModuleProvider来处理底层的逻辑。

std::shared_ptr<TurboModule> DefaultTurboModuleManagerDelegate::getTurboModule(const std::string& name,const JavaTurboModule::InitParams& params) {// 详见3.2auto moduleProvider = DefaultTurboModuleManagerDelegate::javaModuleProvider;if (moduleProvider) {if (auto resolvedModule = moduleProvider(name, params)) {return resolvedModule;}}return nullptr;}

3.2 javaModuleProvider
调用rncore_ModuleProvider加载rn和核心模块,调用了autolinking_ModuleProvider来加载我们自己定义的Module。

std::shared_ptr<TurboModule> javaModuleProvider(const std::string& name,const JavaTurboModule::InitParams& params) {#ifdef REACT_NATIVE_APP_MODULE_PROVIDERauto module = REACT_NATIVE_APP_MODULE_PROVIDER(name, params);if (module != nullptr) {return module;}#endif// 这个是reactnative的core moduleif (auto module = rncore_ModuleProvider(name, params)) {return module;}// 我们自己定义的在这里,详见3.3if (auto module = autolinking_ModuleProvider(name, params)) {return module;}return nullptr;
}

3.3 autolinking_ModuleProvider
这个代码也是自动生成的,我们可以看到构建了一个RTNTurboTestSpec_ModuleProvider,这个是Codegen生成的脚手架,我们来看看。

std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params) {// 详见3.4 auto module_RTNTurboTestSpec = RTNTurboTestSpec_ModuleProvider(moduleName, params);if (module_RTNTurboTestSpec != nullptr) {return module_RTNTurboTestSpec;}return nullptr;
}

3.4 RTNTurboTestSpec_ModuleProvider
构建了一个NativeTurboTestSpecJSI类,这个类也是由Codegen生成的。

std::shared_ptr<TurboModule> RTNTurboTestSpec_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params) {if (moduleName == "RTNTurboTest") {return std::make_shared<NativeTurboTestSpecJSI>(params);}return nullptr;
}

3.5 NativeTurboTestSpecJSI
这个类继承自JavaTurboModule,这里构造函数只是将方法名称和方法本身做一个映射,后续就可以通过methodMap_以及方法名找到对应的方法,__hostFunction_NativeTurboTestSpecJSI_add则是回调到java层最终的实现。
我们接着看一下父类JavaTurboModule的构造数(见3.6)。

NativeTurboTestSpecJSI::NativeTurboTestSpecJSI(const JavaTurboModule::InitParams &params): JavaTurboModule(params) {// __hostFunction_NativeTurboTestSpecJSI_add详见3.5.1methodMap_["add"] = MethodMetadata {2, __hostFunction_NativeTurboTestSpecJSI_add};}

3.5.1 __hostFunction_NativeTurboTestSpecJSI_add

static facebook::jsi::Value __hostFunction_NativeTurboTestSpecJSI_add(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {static jmethodID cachedMethodId = nullptr;// 回调到java层的实现return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "add", "(DDLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
}

3.6 JavaTurboModule
JavaTurboModule继承自TurboModule,TurboModule继承自facebook::jsi::HostObject,HostObject是JSI中的object,可以通过JSI将这个对象暴露给JS层。
从JS层比如调用turboModule.add,则会通过JSI调用到我们当前NativeTurboTestSpecJSI的get方法,这个get是HostObject的接口,由TurboModule实现,会遍历methodMap_找到对应的native方法来执行,这个在下一节我们来介绍JSI的时候会详细介绍。

JavaTurboModule::JavaTurboModule(const InitParams& params): TurboModule(params.moduleName, params.jsInvoker),instance_(jni::make_global(params.instance)),nativeMethodCallInvoker_(params.nativeMethodCallInvoker),shouldVoidMethodsExecuteSync_(params.shouldVoidMethodsExecuteSync) {}  

到这里我们就成功关联了JS层和java层的方法调用。

小结

本节我们介绍了TurboModule的加载流程,而且也介绍了Module中方法的绑定流程,讲述了如果从JS层调用方法最终调用到Java层,这个套逻辑是ReactNative最核心的逻辑,Fabric渲染器的核心也是通过JSI通信,只不过框架和接口的逻辑不太一样,且Fabric涉及更多的内容,Props,State等。
读完本节可能大家对JSI起到一个什么作用有了一些概念,下一节我们会深入的学习JSI。


http://www.ppmy.cn/news/1542629.html

相关文章

html和css实现页面

要使用HTML和CSS创建一个简单的网页&#xff0c;你可以遵循以下步骤&#xff1a; 1.创建HTML结构&#xff1a;定义页面的不同部分&#xff0c;如头部、主体、底部等。 2.添加CSS样式&#xff1a;为HTML元素添加样式&#xff0c;如颜色、字体、布局等。 下面是一个简单的HTML和…

gin入门教程(2):go安装以及初始目录构建

2.1 安装 Go 1. 下载 Go 访问 Go 语言的官方网站 golang.org。根据您的操作系统&#xff08;Windows、macOS 或 Linux&#xff09;选择合适的安装包下载。 2. 安装 Go Windows&#xff1a; 运行下载的 .msi 安装程序&#xff0c;按照提示完成安装。 macOS&#xff1a; 可以…

Docker | centos7上对docker进行安装和配置

安装docker docker配置条件安装地址安装步骤2. 卸载旧版本3. yum 安装gcc相关4. 安装需要的软件包5. 设置stable镜像仓库6. 更新yum软件包索引7. 安装docker引擎8. 启动测试9. 测试补充&#xff1a;设置国内docker仓库镜像 10. 卸载 centos7安装docker https://docs.docker.com…

谁说π难求?盘点圆周率的各种操作

谁说π难求&#xff1f;盘点圆周率的各种骚操作 引言&#xff1a;π的魅力与困惑 圆周率 π \pi π&#xff0c;一直以来是数学界的明星。从古代的阿基米德到现代计算机科学家&#xff0c;大家都想追求这位“神秘数”的真面目。可是&#xff0c;π 就像个顽皮的孩子&#xf…

谷歌仓库管理工具repo

Google 的仓库管理工具 Repo 是一个用于管理包含多个 Git 仓库的大型项目的命令行工具。它最初由 Google 为 Android 操作系统开发&#xff0c;以简化和协调众多子项目的版本控制和协作过程。以下是对 Repo 的详细解释&#xff1a; 主要功能与特点 多仓库管理&#xff1a; Rep…

Android Room(SQLite) too many SQL variables异常

SQLiteException 一、解决办法1. 修改数据库语句2. 分批执行 二、问题根源 转载请注明出处: https://blog.csdn.net/hx7013/article/details/143198862 在使用 Room 或其他基于 SQLite 的 ORM 框架时&#xff0c;批量操作如 IN 或 NOT IN 查询可能会触发 android.database.sqli…

绿意盎然:Spring Boot植物健康管理新纪元

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理植物健康系统的相关信息成为必然。开发合适…

Redis 持久化 总结

前言 相关系列 《Redis & 目录》&#xff08;持续更新&#xff09;《Redis & 持久化 & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Redis & 持久化 & 总结》&#xff08;学习总结/最新最准/持续更新&#xff09;《Redis & …