Migrate ReactPackageTurboModuleManagerDelegate to Kotlin (#51855)

Summary:
Migrate com.facebook.react.ReactPackageTurboModuleManagerDelegate to Kotlin.

## Changelog:

[INTERNAL] - Migrate com.facebook.react.ReactPackageTurboModuleManagerDelegate to Kotlin

Pull Request resolved: https://github.com/facebook/react-native/pull/51855

Test Plan:
```bash
yarn test-android
yarn android
```

Reviewed By: fabriziocucci

Differential Revision: D76116517

Pulled By: cortinico

fbshipit-source-id: 76dc4f7e16736a54be2bbfc1e2fa2e64b1433739
This commit is contained in:
Mateo Guzmán
2025-06-09 09:13:20 -07:00
committed by Facebook GitHub Bot
parent f33fdca876
commit 8d76670cd5
5 changed files with 258 additions and 276 deletions
@@ -368,10 +368,10 @@ public abstract class com/facebook/react/ReactPackageTurboModuleManagerDelegate
public abstract class com/facebook/react/ReactPackageTurboModuleManagerDelegate$Builder {
public fun <init> ()V
public fun build ()Lcom/facebook/react/ReactPackageTurboModuleManagerDelegate;
public final fun build ()Lcom/facebook/react/ReactPackageTurboModuleManagerDelegate;
protected abstract fun build (Lcom/facebook/react/bridge/ReactApplicationContext;Ljava/util/List;)Lcom/facebook/react/ReactPackageTurboModuleManagerDelegate;
public fun setPackages (Ljava/util/List;)Lcom/facebook/react/ReactPackageTurboModuleManagerDelegate$Builder;
public fun setReactApplicationContext (Lcom/facebook/react/bridge/ReactApplicationContext;)Lcom/facebook/react/ReactPackageTurboModuleManagerDelegate$Builder;
public final fun setPackages (Ljava/util/List;)Lcom/facebook/react/ReactPackageTurboModuleManagerDelegate$Builder;
public final fun setReactApplicationContext (Lcom/facebook/react/bridge/ReactApplicationContext;)Lcom/facebook/react/ReactPackageTurboModuleManagerDelegate$Builder;
}
public class com/facebook/react/ReactRootView : android/widget/FrameLayout, com/facebook/react/uimanager/ReactRoot, com/facebook/react/uimanager/RootView {
@@ -79,6 +79,15 @@ public abstract class LazyReactPackage : ReactPackage {
*/
protected abstract fun getNativeModules(reactContext: ReactApplicationContext): List<ModuleSpec>
/**
* Internal accessor to [getNativeModules]. This is needed because [getNativeModules] was
* originally protected in Java (which had subclass + package visibility) and is now protected in
* Kotlin (which has only subclass visiblity). We add this accessor to prevent making
* [getNativeModules] public
*/
internal fun internal_getNativeModules(reactContext: ReactApplicationContext): List<ModuleSpec> =
getNativeModules(reactContext)
/**
* @param reactContext react application context that can be used to create modules
* @return A [List]<[NativeModule]> to register
@@ -1,269 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react;
import androidx.annotation.Nullable;
import com.facebook.infer.annotation.Assertions;
import com.facebook.jni.HybridData;
import com.facebook.react.bridge.CxxModuleWrapper;
import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags;
import com.facebook.react.internal.turbomodule.core.TurboModuleManagerDelegate;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Provider;
public abstract class ReactPackageTurboModuleManagerDelegate extends TurboModuleManagerDelegate {
interface ModuleProvider {
@Nullable
NativeModule getModule(String moduleName);
}
private final List<ModuleProvider> mModuleProviders = new ArrayList<>();
private final Map<ModuleProvider, Map<String, ReactModuleInfo>> mPackageModuleInfos =
new HashMap<>();
private final boolean mShouldEnableLegacyModuleInterop =
ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
&& ReactNativeNewArchitectureFeatureFlags.useTurboModuleInterop();
// Lazy Props
private List<ReactPackage> mPackages;
private ReactApplicationContext mReactContext;
protected ReactPackageTurboModuleManagerDelegate(
ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {
super();
initialize(reactApplicationContext, packages);
}
protected ReactPackageTurboModuleManagerDelegate(
ReactApplicationContext reactApplicationContext,
List<ReactPackage> packages,
HybridData hybridData) {
super(hybridData);
initialize(reactApplicationContext, packages);
}
private void initialize(
ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {
final ReactApplicationContext applicationContext = reactApplicationContext;
for (ReactPackage reactPackage : packages) {
if (reactPackage instanceof BaseReactPackage) {
final BaseReactPackage baseReactPackage = (BaseReactPackage) reactPackage;
final ModuleProvider moduleProvider =
moduleName -> baseReactPackage.getModule(moduleName, applicationContext);
mModuleProviders.add(moduleProvider);
mPackageModuleInfos.put(
moduleProvider, baseReactPackage.getReactModuleInfoProvider().getReactModuleInfos());
continue;
}
if (shouldSupportLegacyPackages() && reactPackage instanceof LazyReactPackage) {
// TODO(T145105887): Output warnings that LazyReactPackage was used
final LazyReactPackage lazyPkg = ((LazyReactPackage) reactPackage);
final List<ModuleSpec> moduleSpecs = lazyPkg.getNativeModules(reactApplicationContext);
final Map<String, Provider<? extends NativeModule>> moduleSpecProviderMap = new HashMap<>();
for (final ModuleSpec moduleSpec : moduleSpecs) {
moduleSpecProviderMap.put(moduleSpec.getName(), moduleSpec.getProvider());
}
final ModuleProvider moduleProvider =
moduleName -> {
Provider<? extends NativeModule> provider = moduleSpecProviderMap.get(moduleName);
return provider != null ? provider.get() : null;
};
mModuleProviders.add(moduleProvider);
mPackageModuleInfos.put(
moduleProvider, lazyPkg.getReactModuleInfoProvider().getReactModuleInfos());
continue;
}
if (shouldSupportLegacyPackages()) {
// TODO(T145105887): Output warnings that ReactPackage was used
final List<NativeModule> nativeModules =
reactPackage.createNativeModules(reactApplicationContext);
final Map<String, NativeModule> moduleMap = new HashMap<>();
final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
for (final NativeModule module : nativeModules) {
final Class<? extends NativeModule> moduleClass = module.getClass();
final @Nullable ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class);
final String moduleName = reactModule != null ? reactModule.name() : module.getName();
final ReactModuleInfo moduleInfo =
reactModule != null
? new ReactModuleInfo(
moduleName,
moduleClass.getName(),
reactModule.canOverrideExistingModule(),
true,
reactModule.isCxxModule(),
ReactModuleInfo.classIsTurboModule(moduleClass))
: new ReactModuleInfo(
moduleName,
moduleClass.getName(),
module.canOverrideExistingModule(),
true,
CxxModuleWrapper.class.isAssignableFrom(moduleClass),
ReactModuleInfo.classIsTurboModule(moduleClass));
reactModuleInfoMap.put(moduleName, moduleInfo);
moduleMap.put(moduleName, module);
}
final ModuleProvider moduleProvider = moduleMap::get;
mModuleProviders.add(moduleProvider);
mPackageModuleInfos.put(moduleProvider, reactModuleInfoMap);
}
}
}
@Override
public boolean unstable_shouldEnableLegacyModuleInterop() {
return mShouldEnableLegacyModuleInterop;
}
@Nullable
@Override
public TurboModule getModule(String moduleName) {
NativeModule resolvedModule = null;
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;
}
}
}
// Skip TurboModule-incompatible modules
boolean isLegacyModule = !(resolvedModule instanceof TurboModule);
if (isLegacyModule) {
return null;
}
return (TurboModule) resolvedModule;
}
@Override
public boolean unstable_isModuleRegistered(String moduleName) {
for (final ModuleProvider moduleProvider : mModuleProviders) {
final ReactModuleInfo moduleInfo = mPackageModuleInfos.get(moduleProvider).get(moduleName);
if (moduleInfo != null && moduleInfo.isTurboModule()) {
return true;
}
}
return false;
}
@Override
public boolean unstable_isLegacyModuleRegistered(String moduleName) {
for (final ModuleProvider moduleProvider : mModuleProviders) {
final ReactModuleInfo moduleInfo = mPackageModuleInfos.get(moduleProvider).get(moduleName);
if (moduleInfo != null && !moduleInfo.isTurboModule()) {
return true;
}
}
return false;
}
@Nullable
@Override
public NativeModule getLegacyModule(String moduleName) {
if (!unstable_shouldEnableLegacyModuleInterop()) {
return null;
}
NativeModule resolvedModule = null;
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;
}
}
}
// Skip TurboModule-compatible modules
boolean isLegacyModule = !(resolvedModule instanceof TurboModule);
if (!isLegacyModule) {
return null;
}
return resolvedModule;
}
@Override
public List<String> getEagerInitModuleNames() {
List<String> moduleNames = new ArrayList<>();
for (final ModuleProvider moduleProvider : mModuleProviders) {
for (final ReactModuleInfo moduleInfo : mPackageModuleInfos.get(moduleProvider).values()) {
if (moduleInfo.isTurboModule() && moduleInfo.needsEagerInit()) {
moduleNames.add(moduleInfo.name());
}
}
}
return moduleNames;
}
private boolean shouldSupportLegacyPackages() {
return unstable_shouldEnableLegacyModuleInterop();
}
public abstract static class Builder {
private @Nullable List<ReactPackage> mPackages;
private @Nullable ReactApplicationContext mContext;
public Builder setPackages(List<ReactPackage> packages) {
mPackages = new ArrayList<>(packages);
return this;
}
public Builder setReactApplicationContext(ReactApplicationContext context) {
mContext = context;
return this;
}
protected abstract ReactPackageTurboModuleManagerDelegate build(
ReactApplicationContext context, List<ReactPackage> packages);
public ReactPackageTurboModuleManagerDelegate build() {
Assertions.assertNotNull(
mContext,
"The ReactApplicationContext must be provided to create"
+ " ReactPackageTurboModuleManagerDelegate");
Assertions.assertNotNull(
mPackages,
"A set of ReactPackages must be provided to create"
+ " ReactPackageTurboModuleManagerDelegate");
return build(mContext, mPackages);
}
}
}
@@ -0,0 +1,242 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react
import com.facebook.jni.HybridData
import com.facebook.react.bridge.CxxModuleWrapper
import com.facebook.react.bridge.ModuleSpec
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
import com.facebook.react.internal.turbomodule.core.TurboModuleManagerDelegate
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.module.model.ReactModuleInfo
import com.facebook.react.turbomodule.core.interfaces.TurboModule
import javax.inject.Provider
public abstract class ReactPackageTurboModuleManagerDelegate : TurboModuleManagerDelegate {
internal fun interface ModuleProvider {
fun getModule(moduleName: String): NativeModule?
}
private val moduleProviders = mutableListOf<ModuleProvider>()
private val packageModuleInfos = mutableMapOf<ModuleProvider, Map<String, ReactModuleInfo>>()
private val shouldEnableLegacyModuleInterop =
ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
ReactNativeNewArchitectureFeatureFlags.useTurboModuleInterop()
protected constructor(
reactApplicationContext: ReactApplicationContext,
packages: List<ReactPackage>
) : super() {
initialize(reactApplicationContext, packages)
}
protected constructor(
reactApplicationContext: ReactApplicationContext,
packages: List<ReactPackage>,
hybridData: HybridData
) : super(hybridData) {
initialize(reactApplicationContext, packages)
}
private fun initialize(
reactApplicationContext: ReactApplicationContext,
packages: List<ReactPackage>
) {
val applicationContext: ReactApplicationContext = reactApplicationContext
for (reactPackage in packages) {
if (reactPackage is BaseReactPackage) {
val moduleProvider = ModuleProvider { moduleName: String ->
reactPackage.getModule(moduleName, applicationContext)
}
moduleProviders.add(moduleProvider)
packageModuleInfos[moduleProvider] =
reactPackage.getReactModuleInfoProvider().getReactModuleInfos()
continue
}
@Suppress("DEPRECATION")
if (shouldSupportLegacyPackages() && reactPackage is LazyReactPackage) {
// TODO(T145105887): Output warnings that LazyReactPackage was used
val lazyPkg = reactPackage
val moduleSpecs: List<ModuleSpec> =
lazyPkg.internal_getNativeModules(reactApplicationContext)
val moduleSpecProviderMap: MutableMap<String?, Provider<out NativeModule>> = mutableMapOf()
for (moduleSpec in moduleSpecs) {
moduleSpecProviderMap[moduleSpec.getName()] = moduleSpec.getProvider()
}
val moduleProvider = ModuleProvider { moduleName: String ->
moduleSpecProviderMap[moduleName]?.get()
}
moduleProviders.add(moduleProvider)
packageModuleInfos[moduleProvider] = lazyPkg.reactModuleInfoProvider.getReactModuleInfos()
continue
}
if (shouldSupportLegacyPackages()) {
// TODO(T145105887): Output warnings that ReactPackage was used
val nativeModules = reactPackage.createNativeModules(reactApplicationContext)
val moduleMap: MutableMap<String, NativeModule> = mutableMapOf()
val reactModuleInfoMap: MutableMap<String, ReactModuleInfo> = mutableMapOf()
for (module in nativeModules) {
val moduleClass: Class<out NativeModule> = module.javaClass
val reactModule = moduleClass.getAnnotation(ReactModule::class.java)
val moduleName = reactModule?.name ?: module.name
val moduleInfo: ReactModuleInfo =
if (reactModule != null)
ReactModuleInfo(
moduleName,
moduleClass.name,
reactModule.canOverrideExistingModule,
true,
reactModule.isCxxModule,
ReactModuleInfo.classIsTurboModule(moduleClass))
else
ReactModuleInfo(
moduleName,
moduleClass.name,
module.canOverrideExistingModule(),
true,
CxxModuleWrapper::class.java.isAssignableFrom(moduleClass),
ReactModuleInfo.classIsTurboModule(moduleClass))
reactModuleInfoMap[moduleName] = moduleInfo
moduleMap[moduleName] = module
}
val moduleProvider = ModuleProvider { module -> moduleMap[module] }
moduleProviders.add(moduleProvider)
packageModuleInfos[moduleProvider] = reactModuleInfoMap
}
}
}
override fun unstable_shouldEnableLegacyModuleInterop(): Boolean = shouldEnableLegacyModuleInterop
override fun getModule(moduleName: String): TurboModule? {
var resolvedModule: NativeModule? = null
for (moduleProvider in moduleProviders) {
val moduleInfo: ReactModuleInfo? = packageModuleInfos[moduleProvider]?.get(moduleName)
if (moduleInfo?.isTurboModule == true &&
(resolvedModule == null || moduleInfo.canOverrideExistingModule)) {
val module = moduleProvider.getModule(moduleName)
if (module != null) {
resolvedModule = module
}
}
}
// Skip TurboModule-incompatible modules
val isLegacyModule = resolvedModule !is TurboModule
if (isLegacyModule) {
return null
}
return resolvedModule as TurboModule
}
override fun unstable_isModuleRegistered(moduleName: String): Boolean {
for (moduleProvider in moduleProviders) {
val moduleInfo: ReactModuleInfo? = packageModuleInfos[moduleProvider]?.get(moduleName)
if (moduleInfo?.isTurboModule == true) {
return true
}
}
return false
}
override fun unstable_isLegacyModuleRegistered(moduleName: String): Boolean {
for (moduleProvider in moduleProviders) {
val moduleInfo: ReactModuleInfo? = packageModuleInfos[moduleProvider]?.get(moduleName)
if (moduleInfo?.isTurboModule == false) {
return true
}
}
return false
}
override fun getLegacyModule(moduleName: String): NativeModule? {
if (!unstable_shouldEnableLegacyModuleInterop()) {
return null
}
var resolvedModule: NativeModule? = null
for (moduleProvider in moduleProviders) {
val moduleInfo: ReactModuleInfo? = packageModuleInfos[moduleProvider]?.get(moduleName)
if (moduleInfo?.isTurboModule == false &&
(resolvedModule == null || moduleInfo.canOverrideExistingModule)) {
val module = moduleProvider.getModule(moduleName)
if (module != null) {
resolvedModule = module
}
}
}
// Skip TurboModule-compatible modules
val isLegacyModule = resolvedModule !is TurboModule
if (!isLegacyModule) {
return null
}
return resolvedModule
}
override fun getEagerInitModuleNames(): List<String> = buildList {
for (moduleProvider in moduleProviders) {
for (moduleInfo in packageModuleInfos[moduleProvider]?.values ?: emptyList()) {
if (moduleInfo.isTurboModule && moduleInfo.needsEagerInit) {
add(moduleInfo.name)
}
}
}
}
private fun shouldSupportLegacyPackages(): Boolean = unstable_shouldEnableLegacyModuleInterop()
public abstract class Builder {
private var packages: List<ReactPackage>? = null
private var context: ReactApplicationContext? = null
public fun setPackages(packages: List<ReactPackage>): Builder {
this.packages = packages.toList()
return this
}
public fun setReactApplicationContext(context: ReactApplicationContext?): Builder {
this.context = context
return this
}
protected abstract fun build(
context: ReactApplicationContext,
packages: List<ReactPackage>
): ReactPackageTurboModuleManagerDelegate
public fun build(): ReactPackageTurboModuleManagerDelegate {
val nonNullContext =
requireNotNull(context) {
"The ReactApplicationContext must be provided to create ReactPackageTurboModuleManagerDelegate"
}
val nonNullPackages =
requireNotNull(packages) {
"A set of ReactPackages must be provided to create ReactPackageTurboModuleManagerDelegate"
}
return build(nonNullContext, nonNullPackages)
}
}
}
@@ -34,17 +34,17 @@ public abstract class TurboModuleManagerDelegate {
* Create and return a TurboModule Java object with name `moduleName`. If `moduleName` isn't a
* TurboModule, return null.
*/
public abstract fun getModule(moduleName: String?): TurboModule?
public abstract fun getModule(moduleName: String): TurboModule?
public abstract fun unstable_isModuleRegistered(moduleName: String?): Boolean
public abstract fun unstable_isModuleRegistered(moduleName: String): Boolean
/**
* Create an return a legacy NativeModule with name `moduleName`. If `moduleName` is a
* TurboModule, return null.
*/
public open fun getLegacyModule(moduleName: String?): NativeModule? = null
public open fun getLegacyModule(moduleName: String): NativeModule? = null
public open fun unstable_isLegacyModuleRegistered(moduleName: String?): Boolean = false
public open fun unstable_isLegacyModuleRegistered(moduleName: String): Boolean = false
public open fun getEagerInitModuleNames(): List<String> = emptyList()