From 8d652fba4ce07256784a1b7e86713c810336856d Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 21 Dec 2021 11:18:29 -0800 Subject: [PATCH] Setup a `newArchEnabled` property to Opt-in the New Architecture in the template (#32790) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/32790 As the name says, I've added a `newArchEnabled` property that can be used to toggle the New Architecture in the new app template. Users can use this to try the New Architecture in their project by either: * Set `newArchEnabled` to true inside the `gradle.properties` file * Invoke gradle with `-PnewArchEnabled=true` * Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` The Project property will also control if: * ReactNative dependency should be built from source or not. * The NDK should be enabled or not. Please note that this requires RN 0.68.x to run properly (it won't work with 0.67 RCs) or a Nightly version of React Native. Changelog: [Android] [Added] - Setup a `newArchEnabled` property to Opt-in the New Architecture in the template Reviewed By: ShikaSD Differential Revision: D33065373 fbshipit-source-id: 32085f5b071d6243936bafd91425b5b43e5b5101 --- settings.gradle.kts | 6 - template/android/app/build.gradle | 68 +++++++++- .../java/com/helloworld/MainActivity.java | 25 ++++ .../java/com/helloworld/MainApplication.java | 13 +- .../MainApplicationReactNativeHost.java | 116 ++++++++++++++++++ .../components/MainComponentsRegistry.java | 36 ++++++ ...ApplicationTurboModuleManagerDelegate.java | 48 ++++++++ template/android/app/src/main/jni/Android.mk | 49 ++++++++ .../jni/MainApplicationModuleProvider.cpp | 24 ++++ .../main/jni/MainApplicationModuleProvider.h | 16 +++ ...nApplicationTurboModuleManagerDelegate.cpp | 45 +++++++ ...ainApplicationTurboModuleManagerDelegate.h | 38 ++++++ .../src/main/jni/MainComponentsRegistry.cpp | 61 +++++++++ .../app/src/main/jni/MainComponentsRegistry.h | 32 +++++ template/android/app/src/main/jni/OnLoad.cpp | 11 ++ template/android/build.gradle | 2 + template/android/gradle.properties | 7 ++ template/android/settings.gradle | 10 ++ template/package.json | 1 + 19 files changed, 599 insertions(+), 9 deletions(-) create mode 100644 template/android/app/src/main/java/com/helloworld/newarchitecture/MainApplicationReactNativeHost.java create mode 100644 template/android/app/src/main/java/com/helloworld/newarchitecture/components/MainComponentsRegistry.java create mode 100644 template/android/app/src/main/java/com/helloworld/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java create mode 100644 template/android/app/src/main/jni/Android.mk create mode 100644 template/android/app/src/main/jni/MainApplicationModuleProvider.cpp create mode 100644 template/android/app/src/main/jni/MainApplicationModuleProvider.h create mode 100644 template/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp create mode 100644 template/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h create mode 100644 template/android/app/src/main/jni/MainComponentsRegistry.cpp create mode 100644 template/android/app/src/main/jni/MainComponentsRegistry.h create mode 100644 template/android/app/src/main/jni/OnLoad.cpp diff --git a/settings.gradle.kts b/settings.gradle.kts index 045b88e9ac0a3f..37da6262662687 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,9 +21,3 @@ include( // Include this to enable codegen Gradle plugin. includeBuild("packages/react-native-gradle-plugin/") -// Include this to build the Android template as well and make sure is not broken. -if (File("template/node_modules/").exists()) { - includeBuild("template/android/") { - name = "template-android" - } -} diff --git a/template/android/app/build.gradle b/template/android/app/build.gradle index e1c91549c43251..850578b51d8ab4 100644 --- a/template/android/app/build.gradle +++ b/template/android/app/build.gradle @@ -139,7 +139,56 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + + if (isNewArchitectureEnabled()) { + // We configure the NDK build only if you decide to opt-in for the New Architecture. + externalNativeBuild { + ndkBuild { + arguments "APP_PLATFORM=android-21", + "APP_STL=c++_shared", + "NDK_TOOLCHAIN_VERSION=clang", + "GENERATED_SRC_DIR=$buildDir/generated/source", + "PROJECT_BUILD_DIR=$buildDir", + "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", + "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build" + cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1" + cppFlags "-std=c++17" + // Make sure this target name is the same you specify inside the + // src/main/jni/Android.mk file for the `LOCAL_MODULE` variable. + targets "helloworld_appmodules" + } + } + } + } + + if (isNewArchitectureEnabled()) { + // We configure the NDK build only if you decide to opt-in for the New Architecture. + externalNativeBuild { + ndkBuild { + path "$projectDir/src/main/jni/Android.mk" + } + } + def reactAndroidProjectDir = project(':ReactAndroid').projectDir + def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) { + dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck") + from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") + into("$buildDir/react-ndk/exported") + } + def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) { + dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck") + from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") + into("$buildDir/react-ndk/exported") + } + afterEvaluate { + // If you wish to add a custom TurboModule or component locally, + // you should uncomment this line. + // preBuild.dependsOn("generateCodegenArtifactsFromSchema") + preDebugBuild.dependsOn(packageReactNdkDebugLibs) + preReleaseBuild.dependsOn(packageReactNdkReleaseLibs) + } } + splits { abi { reset() @@ -193,8 +242,15 @@ android { dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) - //noinspection GradleDynamicVersion - implementation "com.facebook.react:react-native:+" // From node_modules + + // If new architecture is enabled, we let you build RN from source + // Otherwise we fallback to a prebuilt .aar bundled in the NPM package. + if (isNewArchitectureEnabled()) { + implementation project(":ReactAndroid") + } else { + //noinspection GradleDynamicVersion + implementation "com.facebook.react:react-native:+" // From node_modules + } implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" @@ -228,3 +284,11 @@ task copyDownloadableDepsToLibs(type: Copy) { } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) + +def isNewArchitectureEnabled() { + // To opt-in for the New Architecture, you can either: + // - Set `newArchEnabled` to true inside the `gradle.properties` file + // - Invoke gradle with `-newArchEnabled=true` + // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} diff --git a/template/android/app/src/main/java/com/helloworld/MainActivity.java b/template/android/app/src/main/java/com/helloworld/MainActivity.java index c7106d573c5d56..24f412851ff6a7 100644 --- a/template/android/app/src/main/java/com/helloworld/MainActivity.java +++ b/template/android/app/src/main/java/com/helloworld/MainActivity.java @@ -1,6 +1,8 @@ package com.helloworld; import com.facebook.react.ReactActivity; +import com.facebook.react.ReactActivityDelegate; +import com.facebook.react.ReactRootView; public class MainActivity extends ReactActivity { @@ -12,4 +14,27 @@ public class MainActivity extends ReactActivity { protected String getMainComponentName() { return "HelloWorld"; } + + /** + * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and + * you can specify the rendered you wish to use (Fabric or the older renderer). + */ + @Override + protected ReactActivityDelegate createReactActivityDelegate() { + return new MainActivityDelegate(this, getMainComponentName()); + } + + public static class MainActivityDelegate extends ReactActivityDelegate { + public MainActivityDelegate(ReactActivity activity, String mainComponentName) { + super(activity, mainComponentName); + } + + @Override + protected ReactRootView createRootView() { + ReactRootView reactRootView = new ReactRootView(getContext()); + // If you opted-in for the New Architecture, we enable the Fabric Renderer. + reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); + return reactRootView; + } + } } diff --git a/template/android/app/src/main/java/com/helloworld/MainApplication.java b/template/android/app/src/main/java/com/helloworld/MainApplication.java index e55c37b9780140..eedd192958b993 100644 --- a/template/android/app/src/main/java/com/helloworld/MainApplication.java +++ b/template/android/app/src/main/java/com/helloworld/MainApplication.java @@ -7,7 +7,9 @@ import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; +import com.facebook.react.config.ReactFeatureFlags; import com.facebook.soloader.SoLoader; +import com.helloworld.newarchitecture.MainApplicationReactNativeHost; import java.lang.reflect.InvocationTargetException; import java.util.List; @@ -35,14 +37,23 @@ protected String getJSMainModuleName() { } }; + private final ReactNativeHost mNewArchitectureNativeHost = + new MainApplicationReactNativeHost(this); + @Override public ReactNativeHost getReactNativeHost() { - return mReactNativeHost; + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + return mNewArchitectureNativeHost; + } else { + return mReactNativeHost; + } } @Override public void onCreate() { super.onCreate(); + // If you opted-in for the New Architecture, we enable the TurboModule system + ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; SoLoader.init(this, /* native exopackage */ false); initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); } diff --git a/template/android/app/src/main/java/com/helloworld/newarchitecture/MainApplicationReactNativeHost.java b/template/android/app/src/main/java/com/helloworld/newarchitecture/MainApplicationReactNativeHost.java new file mode 100644 index 00000000000000..f555e36448c171 --- /dev/null +++ b/template/android/app/src/main/java/com/helloworld/newarchitecture/MainApplicationReactNativeHost.java @@ -0,0 +1,116 @@ +package com.helloworld.newarchitecture; + +import android.app.Application; +import androidx.annotation.NonNull; +import com.facebook.react.PackageList; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.ReactPackageTurboModuleManagerDelegate; +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.CoreComponentsRegistry; +import com.facebook.react.fabric.EmptyReactNativeConfig; +import com.facebook.react.fabric.FabricJSIModuleProvider; +import com.facebook.react.uimanager.ViewManagerRegistry; +import com.helloworld.BuildConfig; +import com.helloworld.newarchitecture.components.MainComponentsRegistry; +import com.helloworld.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate; +import java.util.ArrayList; +import java.util.List; + +/** + * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both + * TurboModule delegates and the Fabric Renderer. + * + *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the + * `newArchEnabled` property). Is ignored otherwise. + */ +public class MainApplicationReactNativeHost extends ReactNativeHost { + public MainApplicationReactNativeHost(Application application) { + super(application); + } + + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List getPackages() { + List packages = new PackageList(this).getPackages(); + // Packages that cannot be autolinked yet can be added manually here, for example: + // packages.add(new MyReactNativePackage()); + // TurboModules must also be loaded here providing a valid TurboReactPackage implementation: + // packages.add(new TurboReactPackage() { ... }); + // If you have custom Fabric Components, their ViewManagers should also be loaded here + // inside a ReactPackage. + return packages; + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + + @NonNull + @Override + protected ReactPackageTurboModuleManagerDelegate.Builder + getReactPackageTurboModuleManagerDelegateBuilder() { + // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary + // for the new architecture and to use TurboModules correctly. + return new MainApplicationTurboModuleManagerDelegate.Builder(); + } + + @Override + protected JSIModulePackage getJSIModulePackage() { + return new JSIModulePackage() { + @Override + public List getJSIModules( + final ReactApplicationContext reactApplicationContext, + final JavaScriptContextHolder jsContext) { + final List specs = new ArrayList<>(); + + // Here we provide a new JSIModuleSpec that will be responsible of providing the + // custom Fabric Components. + specs.add( + new JSIModuleSpec() { + @Override + public JSIModuleType getJSIModuleType() { + return JSIModuleType.UIManager; + } + + @Override + public JSIModuleProvider getJSIModuleProvider() { + final ComponentFactory componentFactory = new ComponentFactory(); + CoreComponentsRegistry.register(componentFactory); + + // Here we register a Components Registry. + // The one that is generated with the template contains no components + // and just provides you the one from React Native core. + MainComponentsRegistry.register(componentFactory); + + final ReactInstanceManager reactInstanceManager = getReactInstanceManager(); + + ViewManagerRegistry viewManagerRegistry = + new ViewManagerRegistry( + reactInstanceManager.getOrCreateViewManagers(reactApplicationContext)); + + return new FabricJSIModuleProvider( + reactApplicationContext, + componentFactory, + new EmptyReactNativeConfig(), + viewManagerRegistry); + } + }); + return specs; + } + }; + } +} diff --git a/template/android/app/src/main/java/com/helloworld/newarchitecture/components/MainComponentsRegistry.java b/template/android/app/src/main/java/com/helloworld/newarchitecture/components/MainComponentsRegistry.java new file mode 100644 index 00000000000000..c74d0ccadb6b8d --- /dev/null +++ b/template/android/app/src/main/java/com/helloworld/newarchitecture/components/MainComponentsRegistry.java @@ -0,0 +1,36 @@ +package com.helloworld.newarchitecture.components; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.fabric.ComponentFactory; +import com.facebook.soloader.SoLoader; + +/** + * Class responsible to load the custom Fabric Components. This class has native methods and needs a + * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ + * folder for you). + * + *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the + * `newArchEnabled` property). Is ignored otherwise. + */ +@DoNotStrip +public class MainComponentsRegistry { + static { + SoLoader.loadLibrary("fabricjni"); + } + + @DoNotStrip private final HybridData mHybridData; + + @DoNotStrip + private native HybridData initHybrid(ComponentFactory componentFactory); + + @DoNotStrip + private MainComponentsRegistry(ComponentFactory componentFactory) { + mHybridData = initHybrid(componentFactory); + } + + @DoNotStrip + public static MainComponentsRegistry register(ComponentFactory componentFactory) { + return new MainComponentsRegistry(componentFactory); + } +} diff --git a/template/android/app/src/main/java/com/helloworld/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java b/template/android/app/src/main/java/com/helloworld/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java new file mode 100644 index 00000000000000..8593b3bb850cd8 --- /dev/null +++ b/template/android/app/src/main/java/com/helloworld/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java @@ -0,0 +1,48 @@ +package com.helloworld.newarchitecture.modules; + +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; + +/** + * Class responsible to load the TurboModules. This class has native methods and needs a + * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ + * folder for you). + * + *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the + * `newArchEnabled` property). Is ignored otherwise. + */ +public class MainApplicationTurboModuleManagerDelegate + extends ReactPackageTurboModuleManagerDelegate { + + private static volatile boolean sIsSoLibraryLoaded; + + protected MainApplicationTurboModuleManagerDelegate( + ReactApplicationContext reactApplicationContext, List packages) { + super(reactApplicationContext, packages); + } + + protected native HybridData initHybrid(); + + native boolean canCreateTurboModule(String moduleName); + + public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder { + protected MainApplicationTurboModuleManagerDelegate build( + ReactApplicationContext context, List packages) { + return new MainApplicationTurboModuleManagerDelegate(context, packages); + } + } + + @Override + protected synchronized void maybeLoadOtherSoLibraries() { + if (!sIsSoLibraryLoaded) { + // If you change the name of your application .so file in the Android.mk file, + // make sure you update the name here as well. + SoLoader.loadLibrary("helloworld_appmodules"); + sIsSoLibraryLoaded = true; + } + } +} diff --git a/template/android/app/src/main/jni/Android.mk b/template/android/app/src/main/jni/Android.mk new file mode 100644 index 00000000000000..0ae63667564998 --- /dev/null +++ b/template/android/app/src/main/jni/Android.mk @@ -0,0 +1,49 @@ +THIS_DIR := $(call my-dir) + +include $(REACT_ANDROID_DIR)/Android-prebuilt.mk + +# If you wish to add a custom TurboModule or Fabric component in your app you +# will have to include the following autogenerated makefile. +# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk +include $(CLEAR_VARS) + +LOCAL_PATH := $(THIS_DIR) + +# You can customize the name of your application .so file here. +LOCAL_MODULE := helloworld_appmodules + +LOCAL_C_INCLUDES := $(LOCAL_PATH) +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) + +# If you wish to add a custom TurboModule or Fabric component in your app you +# will have to uncomment those lines to include the generated source +# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni) +# +# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni +# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp) +# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni + +# Here you should add any native library you wish to depend on. +LOCAL_SHARED_LIBRARIES := \ + libfabricjni \ + libfbjni \ + libfolly_futures \ + libfolly_json \ + libglog \ + libjsi \ + libreact_codegen_rncore \ + libreact_debug \ + libreact_nativemodule_core \ + libreact_render_componentregistry \ + libreact_render_core \ + libreact_render_debug \ + libreact_render_graphics \ + librrc_view \ + libruntimeexecutor \ + libturbomodulejsijni \ + libyoga + +LOCAL_CFLAGS := -DLOG_TAG=\"ReactNative\" -fexceptions -frtti -std=c++17 -Wall + +include $(BUILD_SHARED_LIBRARY) diff --git a/template/android/app/src/main/jni/MainApplicationModuleProvider.cpp b/template/android/app/src/main/jni/MainApplicationModuleProvider.cpp new file mode 100644 index 00000000000000..0ac23cc6263452 --- /dev/null +++ b/template/android/app/src/main/jni/MainApplicationModuleProvider.cpp @@ -0,0 +1,24 @@ +#include "MainApplicationModuleProvider.h" + +#include + +namespace facebook { +namespace react { + +std::shared_ptr MainApplicationModuleProvider( + const std::string moduleName, + const JavaTurboModule::InitParams ¶ms) { + // Here you can provide your own module provider for TurboModules coming from + // either your application or from external libraries. The approach to follow + // is similar to the following (for a library called `samplelibrary`: + // + // auto module = samplelibrary_ModuleProvider(moduleName, params); + // if (module != nullptr) { + // return module; + // } + // return rncore_ModuleProvider(moduleName, params); + return rncore_ModuleProvider(moduleName, params); +} + +} // namespace react +} // namespace facebook diff --git a/template/android/app/src/main/jni/MainApplicationModuleProvider.h b/template/android/app/src/main/jni/MainApplicationModuleProvider.h new file mode 100644 index 00000000000000..0fa43fa69ad4e5 --- /dev/null +++ b/template/android/app/src/main/jni/MainApplicationModuleProvider.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +namespace facebook { +namespace react { + +std::shared_ptr MainApplicationModuleProvider( + const std::string moduleName, + const JavaTurboModule::InitParams ¶ms); + +} // namespace react +} // namespace facebook diff --git a/template/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp b/template/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp new file mode 100644 index 00000000000000..dbbdc3d13205fe --- /dev/null +++ b/template/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp @@ -0,0 +1,45 @@ +#include "MainApplicationTurboModuleManagerDelegate.h" +#include "MainApplicationModuleProvider.h" + +namespace facebook { +namespace react { + +jni::local_ref +MainApplicationTurboModuleManagerDelegate::initHybrid( + jni::alias_ref) { + return makeCxxInstance(); +} + +void MainApplicationTurboModuleManagerDelegate::registerNatives() { + registerHybrid({ + makeNativeMethod( + "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), + makeNativeMethod( + "canCreateTurboModule", + MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), + }); +} + +std::shared_ptr +MainApplicationTurboModuleManagerDelegate::getTurboModule( + const std::string name, + const std::shared_ptr jsInvoker) { + // Not implemented yet: provide pure-C++ NativeModules here. + return nullptr; +} + +std::shared_ptr +MainApplicationTurboModuleManagerDelegate::getTurboModule( + const std::string name, + const JavaTurboModule::InitParams ¶ms) { + return MainApplicationModuleProvider(name, params); +} + +bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule( + std::string name) { + return getTurboModule(name, nullptr) != nullptr || + getTurboModule(name, {.moduleName = name}) != nullptr; +} + +} // namespace react +} // namespace facebook diff --git a/template/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h b/template/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h new file mode 100644 index 00000000000000..25f27722d0e4fa --- /dev/null +++ b/template/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h @@ -0,0 +1,38 @@ +#include +#include + +#include +#include + +namespace facebook { +namespace react { + +class MainApplicationTurboModuleManagerDelegate + : public jni::HybridClass< + MainApplicationTurboModuleManagerDelegate, + TurboModuleManagerDelegate> { + public: + // Adapt it to the package you used for your Java class. + static constexpr auto kJavaDescriptor = + "Lcom/helloworld/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; + + static jni::local_ref initHybrid(jni::alias_ref); + + static void registerNatives(); + + std::shared_ptr getTurboModule( + const std::string name, + const std::shared_ptr jsInvoker) override; + std::shared_ptr getTurboModule( + 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(std::string name); +}; + +} // namespace react +} // namespace facebook diff --git a/template/android/app/src/main/jni/MainComponentsRegistry.cpp b/template/android/app/src/main/jni/MainComponentsRegistry.cpp new file mode 100644 index 00000000000000..8f7edffd642342 --- /dev/null +++ b/template/android/app/src/main/jni/MainComponentsRegistry.cpp @@ -0,0 +1,61 @@ +#include "MainComponentsRegistry.h" + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {} + +std::shared_ptr +MainComponentsRegistry::sharedProviderRegistry() { + auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); + + // Custom Fabric Components go here. You can register custom + // components coming from your App or from 3rd party libraries here. + // + // providerRegistry->add(concreteComponentDescriptorProvider< + // AocViewerComponentDescriptor>()); + return providerRegistry; +} + +jni::local_ref +MainComponentsRegistry::initHybrid( + jni::alias_ref, + ComponentFactory *delegate) { + auto instance = makeCxxInstance(delegate); + + auto buildRegistryFunction = + [](EventDispatcher::Weak const &eventDispatcher, + ContextContainer::Shared const &contextContainer) + -> ComponentDescriptorRegistry::Shared { + auto registry = MainComponentsRegistry::sharedProviderRegistry() + ->createComponentDescriptorRegistry( + {eventDispatcher, contextContainer}); + + auto mutableRegistry = + std::const_pointer_cast(registry); + + mutableRegistry->setFallbackComponentDescriptor( + std::make_shared( + ComponentDescriptorParameters{ + eventDispatcher, contextContainer, nullptr})); + + return registry; + }; + + delegate->buildRegistryFunction = buildRegistryFunction; + return instance; +} + +void MainComponentsRegistry::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), + }); +} + +} // namespace react +} // namespace facebook diff --git a/template/android/app/src/main/jni/MainComponentsRegistry.h b/template/android/app/src/main/jni/MainComponentsRegistry.h new file mode 100644 index 00000000000000..d61cbffaae4a6c --- /dev/null +++ b/template/android/app/src/main/jni/MainComponentsRegistry.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class MainComponentsRegistry + : public facebook::jni::HybridClass { + public: + // Adapt it to the package you used for your Java class. + constexpr static auto kJavaDescriptor = + "Lcom/helloworld/newarchitecture/components/MainComponentsRegistry;"; + + static void registerNatives(); + + MainComponentsRegistry(ComponentFactory *delegate); + + private: + static std::shared_ptr + sharedProviderRegistry(); + + static jni::local_ref initHybrid( + jni::alias_ref, + ComponentFactory *delegate); +}; + +} // namespace react +} // namespace facebook diff --git a/template/android/app/src/main/jni/OnLoad.cpp b/template/android/app/src/main/jni/OnLoad.cpp new file mode 100644 index 00000000000000..c569b6e865dab5 --- /dev/null +++ b/template/android/app/src/main/jni/OnLoad.cpp @@ -0,0 +1,11 @@ +#include +#include "MainApplicationTurboModuleManagerDelegate.h" +#include "MainComponentsRegistry.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return facebook::jni::initialize(vm, [] { + facebook::react::MainApplicationTurboModuleManagerDelegate:: + registerNatives(); + facebook::react::MainComponentsRegistry::registerNatives(); + }); +} diff --git a/template/android/build.gradle b/template/android/build.gradle index 76cdf637f69d49..fada917abb9d3e 100644 --- a/template/android/build.gradle +++ b/template/android/build.gradle @@ -14,6 +14,8 @@ buildscript { } dependencies { classpath("com.android.tools.build:gradle:7.0.1") + classpath("com.facebook.react:react") + classpath("de.undercouch:gradle-download-task:4.1.1") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/template/android/gradle.properties b/template/android/gradle.properties index 389db0c188079c..0c800f37f869e8 100644 --- a/template/android/gradle.properties +++ b/template/android/gradle.properties @@ -31,3 +31,10 @@ FLIPPER_VERSION=0.99.0 # You can also override it from the CLI using # ./gradlew -PreactNativeArchitectures=x86_64 reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=false diff --git a/template/android/settings.gradle b/template/android/settings.gradle index e50c29d6298864..9f74bf9d5f3857 100644 --- a/template/android/settings.gradle +++ b/template/android/settings.gradle @@ -1,3 +1,13 @@ rootProject.name = 'HelloWorld' apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' +includeBuild('../node_modules/react-native-gradle-plugin') { + dependencySubstitution { + substitute(module("com.facebook.react:react")).using(project(":")) + } +} + +if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { + include(":ReactAndroid") + project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') +} diff --git a/template/package.json b/template/package.json index 40743891fac12c..f506391cd22bee 100644 --- a/template/package.json +++ b/template/package.json @@ -21,6 +21,7 @@ "eslint": "^7.32.0", "jest": "^26.6.3", "metro-react-native-babel-preset": "^0.66.2", + "react-native-gradle-plugin": "^0.0.3", "react-test-renderer": "17.0.2" }, "jest": {