From 7bb5d882995a8a0bd9553bdea8ff2ca4c26ac2d9 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Fri, 16 Sep 2022 12:00:23 +0300 Subject: [PATCH] [0.71.0] Update the New Architecture guide with the changes for the New Template on Android (#3324) Co-authored-by: Riccardo --- docs/build-speed.md | 2 +- docs/new-architecture-app-intro.md | 492 +++++++++++---- docs/new-architecture-app-modules-android.md | 572 ------------------ docs/new-architecture-app-renderer-android.md | 453 -------------- docs/new-architecture-intro.md | 3 - docs/the-new-architecture/use-app-template.md | 11 +- website/sidebars.json | 12 +- website/static/_redirects | 2 + .../version-0.69/build-speed.md | 2 +- .../version-0.70/build-speed.md | 2 +- 10 files changed, 377 insertions(+), 1174 deletions(-) delete mode 100644 docs/new-architecture-app-modules-android.md delete mode 100644 docs/new-architecture-app-renderer-android.md diff --git a/docs/build-speed.md b/docs/build-speed.md index 7cbcacb390c..11f3b46f666 100644 --- a/docs/build-speed.md +++ b/docs/build-speed.md @@ -6,7 +6,7 @@ title: Speeding up your Build phase Building your React Native app could be **expensive** and take several minutes of developers time. This can be problematic as your project grows and generally in bigger organizations with multiple React Native developers. -With [the New React Native Architecture](/docs/next/new-architecture-app-modules-android), this problem is becoming more critical +With [the New React Native Architecture](new-architecture-app-intro), this problem is becoming more critical as you might have to compile some native C++ code in your project with the Android NDK in addition to the native code already necessary for the iOS and Android platforms. To mitigate this performance hit, this page shares some suggestions on how to **improve your build time**. diff --git a/docs/new-architecture-app-intro.md b/docs/new-architecture-app-intro.md index c0d56f91a71..14bf8772a3b 100644 --- a/docs/new-architecture-app-intro.md +++ b/docs/new-architecture-app-intro.md @@ -4,6 +4,8 @@ title: Prerequisites for Applications --- import NewArchitectureWarning from './\_markdown-new-architecture-warning.mdx'; +import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; +import constants from '@site/core/TabsConstants'; @@ -35,128 +37,6 @@ Please [follow the instructions on the React Native website](hermes) to learn ho ::: -## Android - Update Build System - -Using the New Architecture on Android has some prerequisites that you need to meet: - -1. Using Gradle 7.x and Android Gradle Plugin 7.x -2. Using the **new React Gradle Plugin** -3. Building `react-native` **from Source** - -You can update Gradle by running: - -```bash -cd android && ./gradlew wrapper --gradle-version 7.3.3 --distribution-type=all -``` - -While the AGP version should be updated inside the **top-level** `build.gradle` file at the `com.android.tools.build:gradle` dependency line. - -Now, you can edit your **top-level** `settings.gradle` file to include the following line at the end of the file: - -```groovy -includeBuild('../node_modules/react-native-gradle-plugin') - -include(":ReactAndroid") -project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') -include(":ReactAndroid:hermes-engine") -project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') -``` - -Then, open the `android/app/src/main/AndroidManifest.xml` file and add this line: - -```diff -android:windowSoftInputMode="adjustResize" -+ android:exported="true"> - -``` - -Then, edit your **top-level Gradle file** to include the highlighted lines: - -```groovy -buildscript { - ext { - buildToolsVersion = "31.0.0" - minSdkVersion = 21 - compileSdkVersion = 31 - targetSdkVersion = 31 - if (System.properties['os.arch'] == "aarch64") { - // For M1 Users we need to use the NDK 24 which added support for aarch64 - ndkVersion = "24.0.8215888" - } else { - // Otherwise we default to the side-by-side NDK version from AGP. - ndkVersion = "21.4.7075529" - } - } - - // ... - dependencies { - // Make sure that AGP is at least at version 7.x - classpath("com.android.tools.build:gradle:7.2.0") - - // Add those lines - classpath("com.facebook.react:react-native-gradle-plugin") - classpath("de.undercouch:gradle-download-task:4.1.2") - } -} -``` - -Edit your **module-level** **Gradle file** (usually `app/build.gradle[.kts]`) to include the following: - -```diff -// ... - -apply plugin: "com.android.application" - -// ... - -if (enableHermes) { -- def hermesPath = "../../node_modules/hermes-engine/android/"; -- debugImplementation files(hermesPath + "hermes-debug.aar") -- releaseImplementation files(hermesPath + "hermes-release.aar") -+ //noinspection GradleDynamicVersion -+ implementation("com.facebook.react:hermes-engine:+") { // From node_modules -+ exclude group:'com.facebook.fbjni' -+ } -} else { - -// ... - -+ configurations.all { -+ resolutionStrategy.dependencySubstitution { -+ substitute(module("com.facebook.react:react-native")) -+ .using(project(":ReactAndroid")) -+ .because("On New Architecture we're building React Native from source") -+ substitute(module("com.facebook.react:hermes-engine")) -+ .using(project(":ReactAndroid:hermes-engine")) -+ .because("On New Architecture we're building Hermes from source") -+ } -+ } - -// Run this once to be able to run the application with BUCK -// puts all compile dependencies into folder libs for BUCK to use -task copyDownloadableDepsToLibs(type: Copy) { - -// ... - -+ 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" -+ } -``` - -Finally, it’s time to update your project to use the `react-native` dependency from the source rather than using a precompiled artifact from the NPM package. This is needed as the later setup will rely on building the native code from the source. - -Let’s edit your **module-level** `build.gradle` (the one inside the `app/` folder) and change the following line: - -```diff -dependencies { -- implementation "com.facebook.react:react-native:+" // From node_modules -+ implementation project(":ReactAndroid") // From node_modules -``` - ## iOS - Build the Project After upgrading the project, there are a few changes you need to apply: @@ -257,3 +137,371 @@ The `moduleName` has to be the same string used in the `[RCTRootView initWithBri // Run pod install with the flags RCT_NEW_ARCH_ENABLED=1 pod install ``` + +## Android - Prerequisites + +Using the New Architecture on Android has some prerequisites that you need to meet: + +1. Using Gradle version >= 7.x +2. Using Android Gradle Plugin >= 7.x (i.e. the `com.android.tools.build:gradle` dependency) + +If you updated to React Native 0.68+, you already meet those prerequisites. If you don't meet them, consider updating those dependencies first. + +## Android - React Native Gradle Plugin & Build from Source + +The New Architecture relies on the React Native Gradle Plugin (from the `react-native-gradle-plugin` NPM package) to build and run your project. + +Moreover, in this iteration of the guide you will build React Native from source. + +If you updated your project to React Native 0.68+, you probably already have this configuration set up correctly. + +If not make sure you edit the `android/settings.gradle` file as follows: + +```diff + 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') + ++include(":ReactAndroid") ++project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') ++include(":ReactAndroid:hermes-engine") ++project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/+ReactAndroid/hermes-engine') +``` + +Update the `android/build.gradle` file as follows: + +```diff +buildscript { + // ... + dependencies { + + // Add those lines ++ classpath("com.facebook.react:react-native-gradle-plugin") ++ classpath("de.undercouch:gradle-download-task:4.1.2") + } +} +``` + +And update the `android/app/build.gradle` file (please note that this file is different than the top level `build.gradle`) as follows: + +```diff +dependencies { + // ... + if (enableHermes) { +- def hermesPath = "../../node_modules/hermes-engine/android/"; +- debugImplementation files(hermesPath + "hermes-debug.aar") +- releaseImplementation files(hermesPath + "hermes-release.aar") ++ //noinspection GradleDynamicVersion ++ implementation("com.facebook.react:hermes-engine:+") { // From node_modules ++ exclude group:'com.facebook.fbjni' ++ } + } +} + ++ configurations.all { ++ resolutionStrategy.dependencySubstitution { ++ substitute(module("com.facebook.react:react-native")) ++ .using(project(":ReactAndroid")) ++ .because("On New Architecture we're building React Native from source") ++ substitute(module("com.facebook.react:hermes-engine")) ++ .using(project(":ReactAndroid:hermes-engine")) ++ .because("On New Architecture we're building Hermes from source") ++ } ++ } +``` + +## Android - Configure the NDK + +:::caution + +In this iteration of the guide you’re setting up the project to build from source. You might notice an increase in your build time because of this. +You can mitigate this by following the approach described in [Speeding up your Build phase](/docs/next/build-speed) guide. + +::: + +As Codegen will output some Java and some C++ code that needs to build, you need to configure the Android NDK to do so. + +Edit your `android/app/build.gradle` file to include the **two** `externalNativeBuild` blocks detailed below inside the `android{}` block: + +```groovy +android { + defaultConfig { + applicationId "com.awesomeproject" + // ... + + // Add this block + externalNativeBuild { + cmake { + arguments "-DPROJECT_BUILD_DIR=$buildDir", + "-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", + "-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build", + "-DANDROID_STL=c++_shared" + } + } + } + + // Add this block + externalNativeBuild { + cmake { + path "$projectDir/src/main/jni/CMakeLists.txt" + } + } +} +``` + +In the same `build.gradle` file, inside the same `android{}` also add the following section: + +```groovy +android { + // ... + + def reactAndroidProjectDir = project(':ReactAndroid').projectDir + def packageReactNdkLibs = tasks.register("packageReactNdkLibs", Copy) { + dependsOn(":ReactAndroid:packageReactNdkLibsForBuck") + dependsOn("generateCodegenArtifactsFromSchema") + from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") + into("$buildDir/react-ndk/exported") + } + + afterEvaluate { + preBuild.dependsOn(packageReactNdkLibs) + configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild) + configureCMakeDebug.dependsOn(preDebugBuild) + } + + packagingOptions { + pickFirst '**/libhermes.so' + pickFirst '**/libjsc.so' + } +} +``` + +Finally, you need to create two files that are required to build the native code correctly: + +- A CMake file with the compilation instructions (similar to a `build.gradle` for Android/Java) +- An `OnLoad.cpp` file which, as the name says, will be loaded when your app starts. + +Create a file inside the `android/app/src/main/jni` folder called `CMakeLists.txt` with the following content: + +```cmake title="CMakeLists.txt" +cmake_minimum_required(VERSION 3.13) + +# Define the library name here. +project(appmodules) + +# This file includes all the necessary to let you build your application with the New Architecture. +include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) +``` + +And create the `android/app/src/main/jni/OnLoad.cpp` file with the following content: + +```cpp title="OnLoad.cpp" +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +void registerComponents( + std::shared_ptr registry) { + // Custom Fabric Components go here. You can register custom + // components coming from your App or from 3rd party libraries here. + // + // providerRegistry->add(concreteComponentDescriptorProvider< + // AocViewerComponentDescriptor>()); + + // By default we just use the components autolinked by RN CLI + rncli_registerProviders(registry); +} + +std::shared_ptr provideModules( + const std::string &name, + 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); + + // By default we just use the module providers autolinked by RN CLI + return rncli_ModuleProvider(name, params); +} + +} // namespace react +} // namespace facebook + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return facebook::jni::initialize(vm, [] { + facebook::react::DefaultTurboModuleManagerDelegate:: + moduleProvidersFromEntryPoint = &facebook::react::provideModules; + facebook::react::DefaultComponentsRegistry:: + registerComponentDescriptorsFromEntryPoint = + &facebook::react::registerComponents; + }); +} +``` + +When the app loads, this file will take care of registering the Native Components and Modules which provide native sources. By default we only provide the autolinked libraries as this allows you to use those libraries. + +This is the only C++ file you'll have to add to your project, and the infrastructure will take care of the rest. + +## Android - Update your Java classes + +To simplify how to enable the New Architecture on Android, you can use some utility classes that will take care of all the setup without you having to worry about it. + +Those classes are all located inside the `com.facebook.react.defaults` package and are all named `Defaults*`. + +### Update the React Native Host + +First, update your `ReactNativeHost` as follows (usually located in your `MainApplication.java` file): + + + + +```diff title="MainApplication.java" ++import com.facebook.react.defaults.DefaultReactNativeHost; + + private final ReactNativeHost mReactNativeHost = +- new ReactNativeHost(this) { ++ new DefaultReactNativeHost(this) { + + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + ++ @Override ++ public boolean isNewArchEnabled() { ++ return true; ++ } +``` + + + + +```diff title="MainApplication.kt" ++import com.facebook.react.defaults.DefaultReactNativeHost + + val reactNativeHost = +- ReactNativeHost(this) { ++ DefaultReactNativeHost(this) { + + override fun getUseDeveloperSupport() = BuildConfig.DEBUG ++ override fun isNewArchEnabled() = true + + } +``` + + + + +### Update the your application OnCreate + +Still inside your `MainApplication` method `onCreate`, make sure that the New Architecture infrastructure is loaded correctly: + + + + +```diff title="MainApplication.java" ++import com.facebook.react.defaults.DefaultNativeEntryPoint; + + @Override + public void onCreate() { + super.onCreate(); + SoLoader.init(this, /* native exopackage */ false); + // Make sure it's called after SoLoader.init ++ ReactFeatureFlags.useTurboModules = true; ++ DefaultNativeEntryPoint.load(); + ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); + } +``` + + + + +```diff title="MainApplication.kt" ++import com.facebook.react.defaults.DefaultNativeEntryPoint + + override fun onCreate() { + super.onCreate() + SoLoader.init(this, /* native exopackage */ false) + // Make sure it's called after SoLoader.init ++ ReactFeatureFlags.useTurboModules = true ++ DefaultNativeEntryPoint.load() + ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); + } +``` + + + + +### Update your Activity Delegate + +Finally, update your `MainActivity.java` file by providing a React Activity Delegate: + + + + +```diff title="MainActivity.java" ++import com.facebook.react.defaults.DefaultReactActivityDelegate; + +public class MainActivity extends ReactActivity { + ++ @Override ++ protected ReactActivityDelegate createReactActivityDelegate() { ++ return new DefaultReactActivityDelegate( ++ this, ++ getMainComponentName(), ++ true, // Here we enable Fabric ++ true, // Here we enable Concurrent React Features ++ ); ++ } + +} +``` + + + + +```diff title="MainApplication.kt" ++import com.facebook.react.defaults.DefaultReactActivityDelegate; + +public class MainActivity : ReactActivity { + ++ @Override ++ override protected fun createReactActivityDelegate() = ++ DefaultReactActivityDelegate( ++ this, ++ mainComponentName, ++ true, // Here we enable Fabric ++ true, // Here we enable Concurrent React Features ++ ) + +} +``` + + + + +That's it! + +It’s now time to run your Android app to verify that everything works correctly: + +```bash +yarn react-native run-android +``` + +In your Metro terminal log, you will now see the following log to confirm that Fabric is running correctly: + +``` +BUNDLE ./App.js +LOG Running "App" with {"fabric":true,"initialProps":{"concurrentRoot": "true"},"rootTag":1} +``` diff --git a/docs/new-architecture-app-modules-android.md b/docs/new-architecture-app-modules-android.md deleted file mode 100644 index 02069ffac51..00000000000 --- a/docs/new-architecture-app-modules-android.md +++ /dev/null @@ -1,572 +0,0 @@ ---- -id: new-architecture-app-modules-android -title: Enabling TurboModule on Android ---- - -import NewArchitectureWarning from './\_markdown-new-architecture-warning.mdx'; -import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -import constants from '@site/core/TabsConstants'; - - - -Make sure your application meets all the [prerequisites](new-architecture-app-intro). - -## 1. Enable NDK and the native build - -:::caution - -In this iteration of the guide we’re setting up the project to let you build from source. You might notice an increase in your build time because of this. -You can mitigate this by following the approach described in [Speeding up your Build phase](/docs/next/build-speed) guide. - -::: - -The Codegen will output some Java and some C++ code that now we need to build. - -Let’s edit your **module-level** `build.gradle` to include the **two** `externalNativeBuild` blocks detailed below inside the `android{}` block: - -```groovy -android { - defaultConfig { - applicationId "com.awesomeproject" - // ... - - // Add this block - externalNativeBuild { - cmake { - arguments "-DPROJECT_BUILD_DIR=$buildDir", - "-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", - "-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build", - "-DNODE_MODULES_DIR=$rootDir/../node_modules", - "-DANDROID_STL=c++_shared" - } - } - } - - // Add this block - externalNativeBuild { - cmake { - path "$projectDir/src/main/jni/CMakeLists.txt" - } - } -} -``` - -In the same `build.gradle` file, inside the same `android{}` let’s add also the following section: - -```groovy -android { - // ... - - def reactAndroidProjectDir = project(':ReactAndroid').projectDir - def packageReactNdkLibs = tasks.register("packageReactNdkLibs", Copy) { - dependsOn(":ReactAndroid:packageReactNdkLibsForBuck") - dependsOn("generateCodegenArtifactsFromSchema") - from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") - into("$buildDir/react-ndk/exported") - } - - afterEvaluate { - preBuild.dependsOn(packageReactNdkLibs) - configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild) - configureCMakeDebug.dependsOn(preDebugBuild) - } - - packagingOptions { - pickFirst '**/libhermes.so' - pickFirst '**/libjsc.so' - } -} -``` - -Finally, we need to create a CMake file inside the `src/main/jni` folder called `CMakeLists.txt` with the following content: - -```cmake -cmake_minimum_required(VERSION 3.13) - -# Define the library name here. -project(myapplication_appmodules) - -# This file includes all the necessary to let you build your application with the New Architecture. -include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) -``` - -This setup will run a native build on your project and will compile the C++ files that have been generated by the codegen. You will see the native build running with the Gradle task `:app:externalNativeBuildDebug` - -You can now verify that everything works correctly by running your android app: - -```bash -yarn react-native run-android -``` - -## 2. Java/Kotlin - Provide a `ReactPackageTurboModuleManagerDelegate` - -Now is time to actually use the Turbo Native Module. -First, we will need to create a `ReactPackageTurboModuleManagerDelegate` subclass, like the following: - - - - -```java -package com.awesomeproject; - -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; - -public class MyApplicationTurboModuleManagerDelegate extends ReactPackageTurboModuleManagerDelegate { - - private static volatile boolean sIsSoLibraryLoaded; - - protected MyApplicationTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext, List packages) { - super(reactApplicationContext, packages); - } - - protected native HybridData initHybrid(); - - public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder { - protected MyApplicationTurboModuleManagerDelegate build( - ReactApplicationContext context, List packages) { - return new MyApplicationTurboModuleManagerDelegate(context, packages); - } - } - - @Override - protected synchronized void maybeLoadOtherSoLibraries() { - // Prevents issues with initializer interruptions. - if (!sIsSoLibraryLoaded) { - SoLoader.loadLibrary("myapplication_appmodules"); - sIsSoLibraryLoaded = true; - } - } -} -``` - - - - - -```kotlin -package com.awesomeproject - -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 - -class MyApplicationTurboModuleManagerDelegate -protected constructor( - reactApplicationContext: ReactApplicationContext, - packages: List -) : ReactPackageTurboModuleManagerDelegate(reactApplicationContext, packages) { - - override protected external fun initHybrid(): HybridData? - class Builder : ReactPackageTurboModuleManagerDelegate.Builder() { - override protected fun build( - context: ReactApplicationContext, - packages: List - ): MyApplicationTurboModuleManagerDelegate = - MyApplicationTurboModuleManagerDelegate(context, packages) - } - - @Synchronized - override protected fun maybeLoadOtherSoLibraries() { - // Prevents issues with initializer interruptions. - if (!isSoLibraryLoaded) { - SoLoader.loadLibrary("myapplication_appmodules") - isSoLibraryLoaded = true - } - } - - companion object { - @Volatile private var isSoLibraryLoaded = false - } -} -``` - - - - -Please note that the `SoLoader.loadLibrary` parameter (in this case `"myapplication_appmodules")` should be the same as the one specified for `project()` inside the `CMakeLists.txt` file you created before. - -This class will then be responsible of loading the Turbo Native Modules and will take care of loading the native library build with the NDK at runtime. - -## 3. Adapt your `ReactNativeHost` to use the `ReactPackageTurboModuleManagerDelegate` - -Then, you can provide the class you created to your `ReactNativeHost`. You can locate your `ReactNativeHost` by searching for the `getReactNativeHost()`. The `ReactNativeHost` is usually located inside your `Application` class. - -Once you located it, you need to add the `getReactPackageTurboModuleManagerDelegateBuilder` method as from the snippet below: - - - - -```java -public class MyApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = - new ReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { /* ... */ } - - @Override - protected List getPackages() { /* ... */ } - - @Override - protected String getJSMainModuleName() {/* ... */ } - - @NonNull - @Override - protected ReactPackageTurboModuleManagerDelegate.Builder getReactPackageTurboModuleManagerDelegateBuilder() { - return new MyApplicationTurboModuleManagerDelegate.Builder(); - } - }; -} -``` - - - - -```kotlin -class MyApplication : Application(), ReactApplication { - private val reactNativeHost: ReactNativeHost = - object : ReactNativeHost(this) { - - override fun getUseDeveloperSupport(): Boolean { - /* ... */ - } - - override fun getPackages(): List? { - /* ... */ - } - - override fun getJSMainModuleName(): String? { - /* ... */ - } - - @NonNull - override fun getReactPackageTurboModuleManagerDelegateBuilder() = - ReactPackageTurboModuleManagerDelegate.Builder() - } -} -``` - - - - -## 4. Extend the `getPackages()` from your `ReactNativeHost` to use the TurboModule - -Still on the `ReactNativeHost` , we need to extend the the `getPackages()` method to include the newly created Turbo Native Module. Update the method to include the following: - - - - -```java -public class MyApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = - new ReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { /* ... */ } - - @Override - protected List getPackages() { - List packages = new PackageList(this).getPackages(); - - // Add those lines - packages.add(new TurboReactPackage() { - @Nullable - @Override - public NativeModule getModule(String name, ReactApplicationContext reactContext) { - if (name.equals(NativeAwesomeManager.NAME)) { - return new NativeAwesomeManager(reactContext); - } else { - return null; - } - } - - @Override - public ReactModuleInfoProvider getReactModuleInfoProvider() { - return () -> { - final Map moduleInfos = new HashMap<>(); - moduleInfos.put( - NativeAwesomeManager.NAME, - new ReactModuleInfo( - NativeAwesomeManager.NAME, - "NativeAwesomeManager", - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - true // isTurboModule - ) - ); - return moduleInfos; - }; - } - }); - return packages; - } - - @Override - protected String getJSMainModuleName() {/* ... */ } - - @NonNull - @Override - protected ReactPackageTurboModuleManagerDelegate.Builder getReactPackageTurboModuleManagerDelegateBuilder() { - return new MyApplicationTurboModuleManagerDelegate.Builder(); - } - }; -} -``` - - - - -```kotlin -class MyApplication() : Application(), ReactApplication { - - private val reactNativeHost: ReactNativeHost = - object : ReactNativeHost(this) { - override fun getUseDeveloperSupport(): Boolean { - /* ... */ - } - - override protected fun getPackages(): List? { - val packages: MutableList = PackageList(this).getPackages() - - // Add those lines - packages.add( - object : TurboReactPackage() { - @Nullable - override fun getModule( - name: String, - reactContext: ReactApplicationContext? - ): NativeModule? = - if ((name == NativeAwesomeManager.NAME)) { - NativeAwesomeManager(reactContext) - } else { - null - } - - override fun getReactModuleInfoProvider() = - mutableMapOf( - NativeAwesomeManager.NAME, - ReactModuleInfo( - NativeAwesomeManager.NAME, - "NativeAwesomeManager", - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - true // isTurboModule - ) - ) - } - ) - return packages - } - - override protected fun getJSMainModuleName(): String? { - /* ... */ - } - - @NonNull - override protected fun getReactPackageTurboModuleManagerDelegateBuilder(): - ReactPackageTurboModuleManagerDelegate.Builder? { - return Builder() - } - } -} -``` - - - - -## 5. C++ Provide a native implementation for the methods in your `*TurboModuleDelegate` class - -If you take a closer look at the class `MyApplicationTurboModuleManagerDelegate` that you created before, you will notice how some of the methods are `native`. - -Therefore, you need to provide some C++ classes to implement those methods. Specifically you will need those files, to be added inside the `src/main/jni` folder: - -- `MyApplicationTurboModuleManagerDelegate.h` An header file for the TurboModule Delegate. -- `MyApplicationTurboModuleManagerDelegate.cpp` The implementation of the aforementioned header file. -- `MyApplicationModuleProvider.h` A header file for the TurboModule provider, where you can specify which TurboModules you want to load. -- `MyApplicationModuleProvider.cpp` The implementation for the aforementioned header file. -- `OnLoad.cpp` Where the initialisation code will be placed. Specifically TurboModule uses FBJNI so the initialisation for such library lives there. - -The content of those files should be the following: - -#### MyApplicationTurboModuleManagerDelegate.h - -Please note that the `kJavaDescriptor` should be adapted to follow the package name you picked for your project. - -```cpp -#include -#include - -#include -#include - -namespace facebook { -namespace react { - -class MyApplicationTurboModuleManagerDelegate : public jni::HybridClass { -public: - // Adapt it to the package you used for your Java class. - static constexpr auto kJavaDescriptor = - "Lcom/awesomeproject/MyApplicationTurboModuleManagerDelegate;"; - - 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; - -private: - friend HybridBase; - using HybridBase::HybridBase; - -}; - -} // namespace react -} // namespace facebook -``` - -#### MyApplicationTurboModuleManagerDelegate.cpp - -```cpp -#include "MyApplicationTurboModuleManagerDelegate.h" -#include "MyApplicationModuleProvider.h" - -namespace facebook { -namespace react { - -jni::local_ref MyApplicationTurboModuleManagerDelegate::initHybrid(jni::alias_ref) { - return makeCxxInstance(); -} - -void MyApplicationTurboModuleManagerDelegate::registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", MyApplicationTurboModuleManagerDelegate::initHybrid), - }); -} - -std::shared_ptr MyApplicationTurboModuleManagerDelegate::getTurboModule(const std::string name, const std::shared_ptr jsInvoker) { - // Not implemented yet: provide pure-C++ NativeModules here. - return nullptr; -} - -std::shared_ptr MyApplicationTurboModuleManagerDelegate::getTurboModule(const std::string name, const JavaTurboModule::InitParams ¶ms) { - return MyApplicationModuleProvider(name, params); -} - -} // namespace react -} // namespace facebook -``` - -#### MyApplicationModuleProvider.h - -```cpp -#pragma once - -#include -#include - -#include - -namespace facebook { -namespace react { - -std::shared_ptr MyApplicationModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams ¶ms); - -} // namespace react -} // namespace facebook -``` - -#### MyApplicationModuleProvider.cpp - -Please adapt the `samplelibrary.h` import to match the same library name you provided when building the apps. -This is the C++ generated file that is created by the codegen. - -Here you can also specify more than one provider, should you have more than one Turbo Native Module. Specifically in this example we look for a Turbo Native Module from `samplelibrary` (the one we specified) and we fallback to the `rncore` Module Provider (containing all the Core modules). - -```cpp -#include "MyApplicationModuleProvider.h" - -#include -#include - -namespace facebook { -namespace react { - -std::shared_ptr MyApplicationModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams ¶ms) { - auto module = samplelibrary_ModuleProvider(moduleName, params); - if (module != nullptr) { - return module; - } - - return rncore_ModuleProvider(moduleName, params); -} - -} // namespace react -} // namespace facebook -``` - -#### OnLoad.cpp - -```cpp -#include -#include "MyApplicationTurboModuleManagerDelegate.h" - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - return facebook::jni::initialize(vm, [] { - facebook::react::MyApplicationTurboModuleManagerDelegate::registerNatives(); - }); -} -``` - -## 6. Enable the `useTurboModules` flag in your Application `onCreate` - -Now you can finally enable the `Turbo Native Module` support in your Application. To do so, you need to turn on the `useTurboModule` flag inside your Application `onCreate` method. - - - - -```java -public class MyApplication extends Application implements ReactApplication { - - @Override - public void onCreate() { - ReactFeatureFlags.useTurboModules = true; - //... - } -} -``` - - - - - -```kotlin -class MyApplication : Application(), ReactApplication { - - override fun onCreate() { - ReactFeatureFlags.useTurboModules = true - // ... - } -} -``` - - - - -It’s now time to run again your Android app to verify that everything works correctly: - -```bash -yarn react-native run-android -``` diff --git a/docs/new-architecture-app-renderer-android.md b/docs/new-architecture-app-renderer-android.md deleted file mode 100644 index 39bb732efbf..00000000000 --- a/docs/new-architecture-app-renderer-android.md +++ /dev/null @@ -1,453 +0,0 @@ ---- -id: new-architecture-app-renderer-android -title: Enabling Fabric on Android ---- - -import NewArchitectureWarning from './\_markdown-new-architecture-warning.mdx'; - - - -Make sure your application meets all the [prerequisites](new-architecture-app-intro). - -## 1. Provide a `JSIModulePackage` inside your `ReactNativeHost` - -In order to enable Fabric in your app, you would need to add a `JSIModulePackage` inside your `ReactNativeHost`. If you followed the TurboModule section of this guide, you probably already know where to find your `ReactNativeHost`. If not, you can locate your `ReactNativeHost` by searching for the `getReactNativeHost()`. The `ReactNativeHost` is usually located inside your `Application` class. - -Once you located it, you need to add the `getJSIModulePackage` method as from the snippet below: - -```java title='MyApplication.java' -public class MyApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = - new ReactNativeHost(this) { - - // Add those lines: - @Nullable - @Override - protected JSIModulePackage getJSIModulePackage() { - return new JSIModulePackage() { - @Override - public List getJSIModules( - final ReactApplicationContext reactApplicationContext, - final JavaScriptContextHolder jsContext) { - final List specs = new ArrayList<>(); - specs.add(new JSIModuleSpec() { - @Override - public JSIModuleType getJSIModuleType() { - return JSIModuleType.UIManager; - } - - @Override - public JSIModuleProvider getJSIModuleProvider() { - final ComponentFactory componentFactory = new ComponentFactory(); - CoreComponentsRegistry.register(componentFactory); - final ReactInstanceManager reactInstanceManager = getReactInstanceManager(); - - ViewManagerRegistry viewManagerRegistry = - new ViewManagerRegistry( - reactInstanceManager.getOrCreateViewManagers( - reactApplicationContext)); - - return new FabricJSIModuleProvider( - reactApplicationContext, - componentFactory, - new EmptyReactNativeConfig(), - viewManagerRegistry); - } - }); - return specs; - } - }; - } - }; -} -``` - -## 2. Make sure your call `setIsFabric` on your Activity’s `ReactRootView` - -Inside your `Activity` class, you need to make sure you’re calling `setIsFabric` on the `ReactRootView`. -If you don’t have a `ReactActivityDelegate` you might need to create one. - -```java -public class MainActivity extends ReactActivity { - - // Add the Activity Delegate, if you don't have one already. - public static class MainActivityDelegate extends ReactActivityDelegate { - - public MainActivityDelegate(ReactActivity activity, String mainComponentName) { - super(activity, mainComponentName); - } - - @Override - protected ReactRootView createRootView() { - ReactRootView reactRootView = new ReactRootView(getContext()); - - // Make sure to call setIsFabric(true) on your ReactRootView - reactRootView.setIsFabric(true); - return reactRootView; - } - } - - // Make sure to override the `createReactActivityDelegate()` method. - @Override - protected ReactActivityDelegate createReactActivityDelegate() { - return new MainActivityDelegate(this, getMainComponentName()); - } -} -``` - -The crucial part in this code is the `reactRootView.setIsFabric(true)` which will enable the new renderer for this Activity. - -You can now verify that everything works correctly by running your android app: - -```bash -yarn react-native run-android -``` - -In your Metro terminal log, you will now see the following log to confirm that Fabric is running correctly: - -``` -BUNDLE ./App.js -LOG Running "App" with {"fabric":true,"initialProps":{},"rootTag":1} -``` - -## Migrating Android ViewManagers - -First, make sure you followed the instructions to [Enabling the New Renderer (Fabric) in Your Android Application](#enabling-the-new-renderer-fabric-in-your-android-application). Plus we will also assume that you followed the instructions from [Enabling the New NativeModule System (Turbo Module) in Your Android Application](#enabling-the-new-nativemodule-system-turbomodule-in-your-android-application) as the native builds setup steps are presented over there and won’t be repeated here. - -### JavaScript changes - -1. Make sure your other JS changes are ready to go by following Preparing your JavaScript codebase for the new React Native Renderer (Fabric) -2. Replace the call to `requireNativeComponent` with `codegenNativeComponent`. This tells the JS codegen to start generating the native implementation of the component, consisting of C++ and Java classes. This is how it looks for the WebView component: - -```ts -import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; - -// babel-plugin-codegen will replace the function call to use NativeComponentRegistry -// 'RCTWebView' is interopped by RCTFabricComponentsPlugins - -export default (codegenNativeComponent( - 'RCTWebView', -): HostComponent); -``` - -4. **[Flow users]** Make sure your native component has Flow types for its props, since the JS codegen uses these types to generate the type-safe native implementation of the component. The codegen generates C++ classes during the build time, which guarantees that the native implementation is always up-to-date with its JS interface. Use [these c++ compatible types](https://github.com/facebook/react-native/blob/main/Libraries/Types/CodegenTypes.js#L28-L30). - -```ts title="RNTMyNativeViewNativeComponent.js" -import type {Int32} from 'react-native/Libraries/Types/CodegenTypes'; -import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; -import type {HostComponent} from 'react-native'; -import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; - -type NativeProps = $ReadOnly<{| - ...ViewProps, // This is required. - someNumber: Int32, -|}>; - -[...] - -export default (codegenNativeComponent( - 'RNTMyNativeView', -): HostComponent); -``` - -5. **[TypeScript users]** We are currently investigating a support for TypeScript. - -### Native/Java Changes - -1. **Update (or Create) your ViewManager to use the generated classes from the Codegen.** - -Specifically you will have to implement the generated **ViewManagerInterface** and to pass events to the generated **ViewManagerDelegate.** -Your ViewManager could follow this structure. The MyNativeView class in this example is an Android View implementation (like a subclass of LinearLayout, Button, TextView, etc.) - -```java title='MyNativeViewManager.java' -// View manager for MyNativeView components. -@ReactModule(name = MyNativeViewManager.REACT_CLASS) -public class MyNativeViewManager extends SimpleViewManager - implements RNTMyNativeViewManagerInterface { - - public static final String REACT_CLASS = "RNTMyNativeView"; - - private final ViewManagerDelegate mDelegate; - - public MyNativeViewManager() { - mDelegate = new RNTMyNativeViewManagerDelegate<>(this); - } - - @Nullable - @Override - protected ViewManagerDelegate getDelegate() { - return mDelegate; - } - - @NonNull - @Override - public String getName() { - return REACT_CLASS; - } - - @NonNull - @Override - protected MyNativeView createViewInstance(@NonNull ThemedReactContext reactContext) { - return new MyNativeView(reactContext); - } -} -``` - -1. **Add your ViewManager to one of the Packages loaded by your Application.** - -Specifically inside the `ReactNativeHost` , update `getPackages` method to include the following: - -```java -public class MyApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { /* ... */ } - - @Override - protected List getPackages() { - List packages = new PackageList(this).getPackages(); - - // ... other packages or `TurboReactPackage added` here... - - // Add those lines. - packages.add(new ReactPackage() { - @NonNull - @Override - public List createNativeModules( - @NonNull ReactApplicationContext reactContext) { - return Collections.emptyList(); - } - - @NonNull - @Override - public List createViewManagers( - @NonNull ReactApplicationContext reactContext) { - // Your ViewManager is returned here. - return Collections.singletonList(new MyNativeViewManager()); - } - }); - return packages; - } - }; -} -``` - -3. **Add a Fabric Component Registry** - -You need to create a new component Registry that will allow you to **register** your components to be discovered by Fabric. Let’s create the `MyComponentsRegistry` file with the following content. - -As you can see, some methods are `native()` which we will implement in C++ in the following paragraph. - -```java -package com.awesomeproject; - -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 MyComponentsRegistry { - static { - SoLoader.loadLibrary("fabricjni"); - } - - @DoNotStrip private final HybridData mHybridData; - - @DoNotStrip - private native HybridData initHybrid(ComponentFactory componentFactory); - - @DoNotStrip - private MyComponentsRegistry(ComponentFactory componentFactory) { - mHybridData = initHybrid(componentFactory); - } - - @DoNotStrip - public static MyComponentsRegistry register(ComponentFactory componentFactory) { - return new MyComponentsRegistry(componentFactory); - } -} -``` - -4. **Register your custom Fabric Component Registry** - -Finally, let’s edit the `getJSIModulePackage` from the `ReactNativeHost` to also register your Component Registry alongside the Core one: - -```java -public class MyApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { - @Nullable - @Override - protected JSIModulePackage getJSIModulePackage() { - return new JSIModulePackage() { - @Override - public List getJSIModules( - final ReactApplicationContext reactApplicationContext, - final JavaScriptContextHolder jsContext) { - final List specs = new ArrayList<>(); - specs.add(new JSIModuleSpec() { - // ... - - @Override - public JSIModuleProvider getJSIModuleProvider() { - final ComponentFactory componentFactory = new ComponentFactory(); - CoreComponentsRegistry.register(componentFactory); - - // Add this line just below CoreComponentsRegistry.register - MyComponentsRegistry.register(componentFactory); - - // ... - } - }); - return specs; - } - }; - } - }; -} -``` - -### Native/C++ Changes - -It’s now time to provide an implementation for your `MyComponentsRegistry` in C++: - -1. **Create a header file: `MyComponentsRegistry.h`** - -The file should be placed inside the `src/main/jni` folder. -Please note that the `kJavaDescriptor` should be adapted to follow the package name you picked for your project. - -```cpp title="MyComponentsRegistry.h" -#pragma once - -#include -#include -#include -#include - -namespace facebook { -namespace react { - -class MyComponentsRegistry - : public facebook::jni::HybridClass { - public: - constexpr static auto kJavaDescriptor = - "Lcom/awesomeproject/MyComponentsRegistry;"; - - static void registerNatives(); - - MyComponentsRegistry(ComponentFactory *delegate); - - private: - friend HybridBase; - - static std::shared_ptr - sharedProviderRegistry(); - - const ComponentFactory *delegate_; - - static jni::local_ref initHybrid( - jni::alias_ref, - ComponentFactory *delegate); -}; - -} // namespace react -} // namespace facebook -``` - -2. **Create an implementation file: `MyComponentsRegistry.cpp`** - -The file should be placed inside the `src/main/jni` folder alongside `MyComponentsRegistry.h - -```cpp title="MyComponentsRegistry.cpp" -#include "MyComponentsRegistry.h" - -#include -#include -#include -#include -#include - -namespace facebook { -namespace react { - -MyComponentsRegistry::MyComponentsRegistry( - ComponentFactory *delegate) - : delegate_(delegate) {} - -std::shared_ptr -MyComponentsRegistry::sharedProviderRegistry() { - auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); - - providerRegistry->add(concreteComponentDescriptorProvider< - RNTMyNativeViewComponentDescriptor>()); - - return providerRegistry; -} - -jni::local_ref -MyComponentsRegistry::initHybrid( - jni::alias_ref, - ComponentFactory *delegate) { - auto instance = makeCxxInstance(delegate); - - auto buildRegistryFunction = - [](EventDispatcher::Weak const &eventDispatcher, - ContextContainer::Shared const &contextContainer) - -> ComponentDescriptorRegistry::Shared { - auto registry = MyComponentsRegistry::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 MyComponentsRegistry::registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", MyComponentsRegistry::initHybrid), - }); -} - -} // namespace react -} // namespace facebook -``` - -4. **Load your file in the OnLoad.cpp** - -If you followed the TurboModule instructions, you should have a `OnLoad.cpp` file inside the `src/main/jni` folder. There you should add a line to load the `MyComponentsRegistry` class: - -```cpp title="OnLoad.cpp" -#include -#include "MyApplicationTurboModuleManagerDelegate.h" -// Add this import -#include "MyComponentsRegistry.h" - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - return facebook::jni::initialize(vm, [] { - facebook::react::MyApplicationTurboModuleManagerDelegate::registerNatives(); - - // Add this line - facebook::react::MyComponentsRegistry::registerNatives(); - }); -} -``` - -You can now verify that everything works correctly by running your android app: - -```bash -yarn react-native run-android -``` diff --git a/docs/new-architecture-intro.md b/docs/new-architecture-intro.md index e5b224a1649..277e9d2e81e 100644 --- a/docs/new-architecture-intro.md +++ b/docs/new-architecture-intro.md @@ -22,9 +22,6 @@ The guide is divided into five sections: - [iOS](new-architecture-library-ios) - **Supporting the New Architecture in your App** - [Prerequisites for Supporting the New Architecture in your App](new-architecture-app-intro) - - Android - - [Enabling the New Native Module System (Turbo Module) in your App](new-architecture-app-modules-android) - - [Enabling the New Renderer (Fabric) in your App](new-architecture-app-renderer-android) - [**React 18 & React Native**](react-18-and-react-native) - [**Troubleshooting**](new-architecture-troubleshooting) - [**Appendix**](new-architecture-appendix) diff --git a/docs/the-new-architecture/use-app-template.md b/docs/the-new-architecture/use-app-template.md index 53f96acc3f6..2fdfdf55fee 100644 --- a/docs/the-new-architecture/use-app-template.md +++ b/docs/the-new-architecture/use-app-template.md @@ -119,13 +119,4 @@ After you build and run the app when Metro serves the JavaScript bundle, you sho If you'd like to view the code changes relevant to the New Architecture, take a look at the [upgrade helper from version 0.67.4 to 0.68.0](https://react-native-community.github.io/upgrade-helper/?from=0.67.4&to=0.68.0). Files that were added for the New Architecture are marked with a yellow banner. -For further explanations of what each file is doing, check out these guides to walk through the changes step-by-step: - -#### Android - -- [Enabling the New Native Module System (Turbo Module) on Android](new-architecture-app-modules-android.md) -- [Enabling the New Renderer (Fabric) on Android](new-architecture-app-renderer-android.md) - -#### iOS - -- [Enabling The New Architecture in Your App](new-architecture-app-intro.md) +For further explanations of what each file is doing, check out these guides to walk through the changes step-by-step: [Enabling The New Architecture in Your App](new-architecture-app-intro.md) diff --git a/website/sidebars.json b/website/sidebars.json index 504f2d8947a..3bf2d97e9f0 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -122,17 +122,7 @@ "new-architecture-library-ios" ] }, - { - "type": "category", - "label": "Supporting in your App", - "collapsible": false, - "collapsed": false, - "items": [ - "new-architecture-app-intro", - "new-architecture-app-modules-android", - "new-architecture-app-renderer-android" - ] - }, + "new-architecture-app-intro", "react-18-and-react-native", "new-architecture-troubleshooting", "new-architecture-appendix" diff --git a/website/static/_redirects b/website/static/_redirects index d5fa4b353c5..1d7ba174410 100644 --- a/website/static/_redirects +++ b/website/static/_redirects @@ -16,6 +16,8 @@ /blog/2021/03/11/version-0.64 /blog/2021/03/12/version-0.64 # Removed pages +/docs/new-architecture-app-modules-android /docs/new-architecture-intro +/docs/new-architecture-app-renderer-android /docs/new-architecture-intro /docs/new-architecture-app-modules-ios /docs/new-architecture-intro /docs/new-architecture-app-renderer-ios /docs/new-architecture-intro diff --git a/website/versioned_docs/version-0.69/build-speed.md b/website/versioned_docs/version-0.69/build-speed.md index 4eebf969d66..7cb71e375ab 100644 --- a/website/versioned_docs/version-0.69/build-speed.md +++ b/website/versioned_docs/version-0.69/build-speed.md @@ -6,7 +6,7 @@ title: Speeding up your Build phase Building your React Native app could be **expensive** and take several minutes of developers time. This can be problematic as your project grows and generally in bigger organizations with multiple React Native developers. -With [the New React Native Architecture](/docs/next/new-architecture-app-modules-android), this problem is becoming more critical +With [the New React Native Architecture](new-architecture-app-modules-android), this problem is becoming more critical as you might have to compile some native C++ code in your project with the Android NDK in addition to the native code already necessary for the iOS and Android platforms. To mitigate this performance hit, this page shares some suggestions on how to **improve your build time**. diff --git a/website/versioned_docs/version-0.70/build-speed.md b/website/versioned_docs/version-0.70/build-speed.md index 7cbcacb390c..129423924d4 100644 --- a/website/versioned_docs/version-0.70/build-speed.md +++ b/website/versioned_docs/version-0.70/build-speed.md @@ -6,7 +6,7 @@ title: Speeding up your Build phase Building your React Native app could be **expensive** and take several minutes of developers time. This can be problematic as your project grows and generally in bigger organizations with multiple React Native developers. -With [the New React Native Architecture](/docs/next/new-architecture-app-modules-android), this problem is becoming more critical +With [the New React Native Architecture](new-architecture-app-modules-android), this problem is becoming more critical as you might have to compile some native C++ code in your project with the Android NDK in addition to the native code already necessary for the iOS and Android platforms. To mitigate this performance hit, this page shares some suggestions on how to **improve your build time**.