From 9a2eb9089f0854502b4b03cf4f74426c23b3f4e8 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 16 Aug 2022 07:55:40 -0700 Subject: [PATCH] Provide defaults for TurboModuleManagerDelegate and JSIModulePackage (#34418) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/34418 This is an attempt to relax the need of specifying a custom `TurboModuleManagerDelegate` and a `JSIModulePackage` in new apps for New Architecture. Users can just specify the name of the dynamic library to load and they'll default to use the `DefaultTurboModuleManagerDelegate` and `DefaultJSIModulePackage`. Users will still have to provide a C++ implementation for it for the time being, but this at least removes one extra file that we requested them to create and maintain. If we're fine with this approach, I'll replicate it inside the default template. Changelog: [Android] [Added] - Provide defaults for TurboModuleManagerDelegate and JSIModulePackage Reviewed By: cipolleschi Differential Revision: D38701180 fbshipit-source-id: eec302c5789990700eb75353d97751358ca6799f --- .../defaults/DefaultComponentsRegistry.kt | 36 ++++++++++ .../react/defaults/DefaultJSIModulePackage.kt | 58 ++++++++++++++++ .../react/defaults/DefaultReactNativeHost.kt | 45 +++++++++++++ .../DefaultTurboModuleManagerDelegate.kt | 57 ++++++++++++++++ packages/rn-tester/android/app/build.gradle | 11 ++- .../react/uiapp/RNTesterApplication.java | 67 ++----------------- .../uiapp/RNTesterComponentsRegistry.java | 35 ---------- .../RNTesterTurboModuleManagerDelegate.java | 47 ------------- .../android/app/src/main/jni/CMakeLists.txt | 2 +- .../src/main/jni/RNTesterComponentsRegistry.h | 2 +- .../RNTesterTurboModuleManagerDelegate.cpp | 9 --- .../jni/RNTesterTurboModuleManagerDelegate.h | 8 +-- 12 files changed, 213 insertions(+), 164 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultComponentsRegistry.kt create mode 100644 ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultJSIModulePackage.kt create mode 100644 ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt create mode 100644 ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultTurboModuleManagerDelegate.kt delete mode 100644 packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterComponentsRegistry.java delete mode 100644 packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterTurboModuleManagerDelegate.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultComponentsRegistry.kt b/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultComponentsRegistry.kt new file mode 100644 index 00000000000..23e65c2d4a9 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultComponentsRegistry.kt @@ -0,0 +1,36 @@ +/* + * 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.defaults + +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.fabric.ComponentFactory + +/** + * A utility class that provides users a ComponentRegistry they can customize with a C++ + * implementation of its native methods. + * + * Please note that you need to provide a native implementation for the method initHybrid for this + * class, making sure the Java Descriptor is: + * Lcom/facebook/react/defaults/DefaultComponentsRegistry; + */ +@DoNotStrip +class DefaultComponentsRegistry +@DoNotStrip +private constructor(componentFactory: ComponentFactory) { + + @DoNotStrip private val hybridData: HybridData = initHybrid(componentFactory) + + @DoNotStrip private external fun initHybrid(componentFactory: ComponentFactory): HybridData + + companion object { + @JvmStatic + @DoNotStrip + fun register(componentFactory: ComponentFactory) = DefaultComponentsRegistry(componentFactory) + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultJSIModulePackage.kt b/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultJSIModulePackage.kt new file mode 100644 index 00000000000..71b01f5edef --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultJSIModulePackage.kt @@ -0,0 +1,58 @@ +/* + * 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.defaults + +import com.facebook.react.ReactNativeHost +import com.facebook.react.bridge.JSIModulePackage +import com.facebook.react.bridge.JSIModuleProvider +import com.facebook.react.bridge.JSIModuleSpec +import com.facebook.react.bridge.JSIModuleType +import com.facebook.react.bridge.JavaScriptContextHolder +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.UIManager +import com.facebook.react.fabric.ComponentFactory +import com.facebook.react.fabric.FabricJSIModuleProvider +import com.facebook.react.fabric.ReactNativeConfig +import com.facebook.react.uimanager.ViewManagerRegistry + +/** + * A utility class that allows users to create a JSIModulePackage to use Fabric. This essentially + * allows users to just provide C++ implementation for the methods of `DefaultComponentsRegistry` + * without providing all the extra machinery for the New Architecture. + * + * `ReactNativeHost` is required to create Fabric's ViewManagers. + */ +class DefaultJSIModulePackage(private val reactNativeHost: ReactNativeHost) : JSIModulePackage { + + override fun getJSIModules( + reactApplicationContext: ReactApplicationContext, + jsContext: JavaScriptContextHolder + ): List> = + listOf>(JSIModuleForFabric(reactApplicationContext, reactNativeHost)) + + private inner class JSIModuleForFabric( + private val reactApplicationContext: ReactApplicationContext, + private val reactNativeHost: ReactNativeHost + ) : JSIModuleSpec { + override fun getJSIModuleType(): JSIModuleType = JSIModuleType.UIManager + override fun getJSIModuleProvider(): JSIModuleProvider { + val componentFactory = ComponentFactory() + + DefaultComponentsRegistry.register(componentFactory) + + val viewManagers = + reactNativeHost.getReactInstanceManager().getOrCreateViewManagers(reactApplicationContext) + val viewManagerRegistry = ViewManagerRegistry(viewManagers) + return FabricJSIModuleProvider( + reactApplicationContext, + componentFactory, + ReactNativeConfig.DEFAULT_CONFIG, + viewManagerRegistry) + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt b/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt new file mode 100644 index 00000000000..841dea31549 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt @@ -0,0 +1,45 @@ +/* + * 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.defaults + +import android.app.Application +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackageTurboModuleManagerDelegate +import com.facebook.react.bridge.JSIModulePackage + +abstract class DefaultReactNativeHost protected constructor(application: Application) : + ReactNativeHost(application) { + + protected override fun getReactPackageTurboModuleManagerDelegateBuilder(): + ReactPackageTurboModuleManagerDelegate.Builder? = + dynamicLibraryName?.let { + // If the user provided a dynamic library name, we assume they want to load + // the default ReactPackageTurboModuleManagerDelegate + DefaultTurboModuleManagerDelegate.Builder(it) + } + + protected override fun getJSIModulePackage(): JSIModulePackage? = + dynamicLibraryName?.let { + // If the user provided a dynamic library name, we assume they want to load + // the default JSIModulePackage + DefaultJSIModulePackage(this) + } + + /** + * Returns the name of the dynamic library used by app on the New Architecture. This is generally + * "_appmodules" + * + * If null, we will assume you're not using the New Architecture and will not attempt to load any + * dynamic library at runtime. + * + * If set, we'll take care of create a TurboModuleManagerDelegate that will load the library you + * specified. + */ + protected open val dynamicLibraryName: String? + get() = null +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultTurboModuleManagerDelegate.kt b/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultTurboModuleManagerDelegate.kt new file mode 100644 index 00000000000..314a01ca91c --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultTurboModuleManagerDelegate.kt @@ -0,0 +1,57 @@ +/* + * 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.defaults + +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.ReactPackage +import com.facebook.react.ReactPackageTurboModuleManagerDelegate +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.soloader.SoLoader + +/** + * A utility class that allows you to provide a TurboModuleManagerDelegate by just specifying the + * name of the dynamic library. This class will take care of loading the dynamic library for you on + * your behalf. + * + * Please note that you need to provide a native implementation for the method initHybrid for this + * class, making sure the Java Descriptor is: + * Lcom/facebook/react/defaults/DefaultTurboModuleManagerDelegate; + */ +class DefaultTurboModuleManagerDelegate +private constructor( + dynamicLibraryName: String, + context: ReactApplicationContext, + packages: List +) : ReactPackageTurboModuleManagerDelegate(context, packages) { + + @DoNotStrip protected override external fun initHybrid(): HybridData? + + init { + maybeLoadOtherSoLibraries(dynamicLibraryName) + } + + @Synchronized + private fun maybeLoadOtherSoLibraries(dynamicLibraryName: String) { + // Prevents issues with initializer interruptions. + if (!isSoLibraryLoaded) { + SoLoader.loadLibrary(dynamicLibraryName) + isSoLibraryLoaded = true + } + } + + class Builder(private val dynamicLibraryName: String) : + ReactPackageTurboModuleManagerDelegate.Builder() { + protected override fun build(context: ReactApplicationContext, packages: List) = + DefaultTurboModuleManagerDelegate(dynamicLibraryName, context, packages) + } + + companion object { + @Volatile private var isSoLibraryLoaded = false + } +} diff --git a/packages/rn-tester/android/app/build.gradle b/packages/rn-tester/android/app/build.gradle index 29ed0714a44..9a358595e84 100644 --- a/packages/rn-tester/android/app/build.gradle +++ b/packages/rn-tester/android/app/build.gradle @@ -123,6 +123,13 @@ def reactNativeArchitectures() { return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] } +/** + * The name of the dynamic library for this application. This will contain all the + * compiled C++ code and will be loaded at runtime. + * For RN tester is "rntester_appmodules" so that we'll have a `librntester_appmodules.so` to load. + */ +def dynamicLibraryName = "rntester_appmodules" + android { buildToolsVersion = "31.0.0" compileSdkVersion 31 @@ -154,6 +161,7 @@ android { versionName "1.0" testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + buildConfigField("String", "DYNAMIC_LIBRARY_NAME", "\"$dynamicLibraryName\"") } signingConfigs { release { @@ -241,9 +249,8 @@ android { "-DPROJECT_BUILD_DIR=$buildDir", "-DREACT_ANDROID_DIR=$reactAndroidProjectDir", "-DREACT_ANDROID_BUILD_DIR=$reactAndroidBuildDir", + "-DTARGET_NAME=$dynamicLibraryName", "-DANDROID_STL=c++_shared" - - targets "rntester_appmodules" } } } diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java index 6f631b1a165..cf5abe45495 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java @@ -10,37 +10,24 @@ package com.facebook.react.uiapp; import android.app.Application; import android.content.Context; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.facebook.fbreact.specs.SampleTurboModule; import com.facebook.react.ReactApplication; import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; -import com.facebook.react.ReactPackageTurboModuleManagerDelegate; import com.facebook.react.TurboReactPackage; -import com.facebook.react.bridge.JSIModulePackage; -import com.facebook.react.bridge.JSIModuleProvider; -import com.facebook.react.bridge.JSIModuleSpec; -import com.facebook.react.bridge.JSIModuleType; -import com.facebook.react.bridge.JavaScriptContextHolder; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.UIManager; import com.facebook.react.config.ReactFeatureFlags; -import com.facebook.react.fabric.ComponentFactory; -import com.facebook.react.fabric.CoreComponentsRegistry; -import com.facebook.react.fabric.FabricJSIModuleProvider; -import com.facebook.react.fabric.ReactNativeConfig; +import com.facebook.react.defaults.DefaultReactNativeHost; import com.facebook.react.module.model.ReactModuleInfo; import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.shell.MainReactPackage; import com.facebook.react.uiapp.component.MyNativeViewManager; import com.facebook.react.uimanager.ViewManager; -import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.react.views.text.ReactFontManager; import com.facebook.soloader.SoLoader; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -50,7 +37,7 @@ import java.util.Map; public class RNTesterApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = - new ReactNativeHost(this) { + new DefaultReactNativeHost(this) { @Override public String getJSMainModuleName() { return "packages/rn-tester/js/RNTesterApp.android"; @@ -126,54 +113,9 @@ public class RNTesterApplication extends Application implements ReactApplication }); } - @Nullable @Override - protected ReactPackageTurboModuleManagerDelegate.Builder - getReactPackageTurboModuleManagerDelegateBuilder() { - return new RNTesterTurboModuleManagerDelegate.Builder(); - } - - @Nullable - @Override - protected JSIModulePackage getJSIModulePackage() { - return new JSIModulePackage() { - @Override - public List getJSIModules( - final ReactApplicationContext reactApplicationContext, - final JavaScriptContextHolder jsContext) { - final List specs = new ArrayList<>(); - - // Install the new renderer. - specs.add( - new JSIModuleSpec() { - @Override - public JSIModuleType getJSIModuleType() { - return JSIModuleType.UIManager; - } - - @Override - public JSIModuleProvider getJSIModuleProvider() { - final ComponentFactory componentFactory = new ComponentFactory(); - CoreComponentsRegistry.register(componentFactory); - RNTesterComponentsRegistry.register(componentFactory); - final ReactInstanceManager reactInstanceManager = getReactInstanceManager(); - - ViewManagerRegistry viewManagerRegistry = - new ViewManagerRegistry( - reactInstanceManager.getOrCreateViewManagers( - reactApplicationContext)); - - return new FabricJSIModuleProvider( - reactApplicationContext, - componentFactory, - ReactNativeConfig.DEFAULT_CONFIG, - viewManagerRegistry); - } - }); - - return specs; - } - }; + public String getDynamicLibraryName() { + return BuildConfig.DYNAMIC_LIBRARY_NAME; } }; @@ -183,6 +125,7 @@ public class RNTesterApplication extends Application implements ReactApplication ReactFontManager.getInstance().addCustomFont(this, "Rubik", R.font.rubik); super.onCreate(); SoLoader.init(this, /* native exopackage */ false); + SoLoader.loadLibrary(BuildConfig.DYNAMIC_LIBRARY_NAME); initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); } diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterComponentsRegistry.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterComponentsRegistry.java deleted file mode 100644 index 4c0582ba6f5..00000000000 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterComponentsRegistry.java +++ /dev/null @@ -1,35 +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.uiapp; - -import com.facebook.jni.HybridData; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.fabric.ComponentFactory; -import com.facebook.soloader.SoLoader; - -@DoNotStrip -public class RNTesterComponentsRegistry { - static { - SoLoader.loadLibrary("fabricjni"); - } - - @DoNotStrip private final HybridData mHybridData; - - @DoNotStrip - private native HybridData initHybrid(ComponentFactory componentFactory); - - @DoNotStrip - private RNTesterComponentsRegistry(ComponentFactory componentFactory) { - mHybridData = initHybrid(componentFactory); - } - - @DoNotStrip - public static RNTesterComponentsRegistry register(ComponentFactory componentFactory) { - return new RNTesterComponentsRegistry(componentFactory); - } -} diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterTurboModuleManagerDelegate.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterTurboModuleManagerDelegate.java deleted file mode 100644 index bb046c4b37b..00000000000 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterTurboModuleManagerDelegate.java +++ /dev/null @@ -1,47 +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.uiapp; - -import androidx.annotation.VisibleForTesting; -import com.facebook.jni.HybridData; -import com.facebook.react.ReactPackage; -import com.facebook.react.ReactPackageTurboModuleManagerDelegate; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.soloader.SoLoader; -import java.util.List; - -/** This class is responsible for creating all the TurboModules for the RNTester app. */ -public class RNTesterTurboModuleManagerDelegate extends ReactPackageTurboModuleManagerDelegate { - private static volatile boolean sIsSoLibraryLoaded; - - protected native HybridData initHybrid(); - - @VisibleForTesting - native boolean canCreateTurboModule(String moduleName); - - private RNTesterTurboModuleManagerDelegate( - ReactApplicationContext context, List packages) { - super(context, packages); - } - - public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder { - protected RNTesterTurboModuleManagerDelegate build( - ReactApplicationContext context, List packages) { - return new RNTesterTurboModuleManagerDelegate(context, packages); - } - } - - @Override - protected synchronized void maybeLoadOtherSoLibraries() { - // Prevents issues with initializer interruptions. - if (!sIsSoLibraryLoaded) { - SoLoader.loadLibrary("rntester_appmodules"); - sIsSoLibraryLoaded = true; - } - } -} diff --git a/packages/rn-tester/android/app/src/main/jni/CMakeLists.txt b/packages/rn-tester/android/app/src/main/jni/CMakeLists.txt index 8458616c6a1..496b839d767 100644 --- a/packages/rn-tester/android/app/src/main/jni/CMakeLists.txt +++ b/packages/rn-tester/android/app/src/main/jni/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.13) # Define the library name here. -project(rntester_appmodules) +project(${TARGET_NAME}) include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) diff --git a/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.h b/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.h index 121dff5cb44..5069583c7c2 100644 --- a/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.h +++ b/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.h @@ -19,7 +19,7 @@ class RNTesterComponentsRegistry : public facebook::jni::HybridClass { public: constexpr static auto kJavaDescriptor = - "Lcom/facebook/react/uiapp/RNTesterComponentsRegistry;"; + "Lcom/facebook/react/defaults/DefaultComponentsRegistry;"; static void registerNatives(); diff --git a/packages/rn-tester/android/app/src/main/jni/RNTesterTurboModuleManagerDelegate.cpp b/packages/rn-tester/android/app/src/main/jni/RNTesterTurboModuleManagerDelegate.cpp index 6bf5c8e8afa..c12c1cbdb43 100644 --- a/packages/rn-tester/android/app/src/main/jni/RNTesterTurboModuleManagerDelegate.cpp +++ b/packages/rn-tester/android/app/src/main/jni/RNTesterTurboModuleManagerDelegate.cpp @@ -21,9 +21,6 @@ void RNTesterTurboModuleManagerDelegate::registerNatives() { registerHybrid({ makeNativeMethod( "initHybrid", RNTesterTurboModuleManagerDelegate::initHybrid), - makeNativeMethod( - "canCreateTurboModule", - RNTesterTurboModuleManagerDelegate::canCreateTurboModule), }); } @@ -40,11 +37,5 @@ std::shared_ptr RNTesterTurboModuleManagerDelegate::getTurboModule( return RNTesterAppModuleProvider(name, params); } -bool RNTesterTurboModuleManagerDelegate::canCreateTurboModule( - const std::string &name) { - return getTurboModule(name, nullptr) != nullptr || - getTurboModule(name, {.moduleName = name}) != nullptr; -} - } // namespace react } // namespace facebook diff --git a/packages/rn-tester/android/app/src/main/jni/RNTesterTurboModuleManagerDelegate.h b/packages/rn-tester/android/app/src/main/jni/RNTesterTurboModuleManagerDelegate.h index d735d4dc521..d7330c252d1 100644 --- a/packages/rn-tester/android/app/src/main/jni/RNTesterTurboModuleManagerDelegate.h +++ b/packages/rn-tester/android/app/src/main/jni/RNTesterTurboModuleManagerDelegate.h @@ -20,7 +20,7 @@ class RNTesterTurboModuleManagerDelegate TurboModuleManagerDelegate> { public: static constexpr auto kJavaDescriptor = - "Lcom/facebook/react/uiapp/RNTesterTurboModuleManagerDelegate;"; + "Lcom/facebook/react/defaults/DefaultTurboModuleManagerDelegate;"; static jni::local_ref initHybrid(jni::alias_ref); @@ -33,12 +33,6 @@ class RNTesterTurboModuleManagerDelegate const std::string &name, const JavaTurboModule::InitParams ¶ms) override; - /** - * Test-only method. Allows user to verify whether a TurboModule can be - * created by instances of this class. - */ - bool canCreateTurboModule(const std::string &name); - private: friend HybridBase; using HybridBase::HybridBase;