From c9086c10bb1e3c32ce7d4bfdde4883cc1e2b4045 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Fri, 18 Jul 2025 04:54:11 -0700 Subject: [PATCH 1/3] Migrate RNTester to use `{usesCleartextTraffic}` Manifest Placeholder (#52620) Summary: This creates a `debugOptimized` build type for React Native Android, meaning that we can run C++ optimization on the debug build, while still having the debugger enabled. This is aimed at improving the developer experience for folks developing on low-end devices or emulators. Users that intend to debug can still use the `debug` variant where the full debug symbols are shipped. ## Changelog: [ANDROID] [ADDED] - Create a debugOptimized buildType for Android Pull Request resolved: https://github.com/facebook/react-native/pull/52620 Test Plan: Tested locally with RNTester by doing: ``` ./gradlew installDebugOptimized ``` This is the output of the 3 generated .aar. The size difference is a proof that we're correctly stripping out the C++ debug symbols: Screenshot 2025-07-15 at 17 49 50 Screenshot 2025-07-15 at 17 49 39 Screenshot 2025-07-15 at 17 49 32 Differential Revision: D78351347 Reviewed By: cipolleschi Pulled By: cipolleschi --- .../kotlin/com/facebook/react/ReactPlugin.kt | 2 ++ .../react/utils/AgpConfiguratorUtils.kt | 21 +++++++++++++++++++ .../android/app/src/debug/AndroidManifest.xml | 8 ------- .../android/app/src/main/AndroidManifest.xml | 1 + 4 files changed, 24 insertions(+), 8 deletions(-) delete mode 100644 packages/rn-tester/android/app/src/debug/AndroidManifest.xml diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt index 85f8ca32aaf142..3d40455a43a366 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt @@ -18,6 +18,7 @@ import com.facebook.react.tasks.GenerateEntryPointTask import com.facebook.react.tasks.GeneratePackageListTask import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForApp import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForLibraries +import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildTypesForApp import com.facebook.react.utils.AgpConfiguratorUtils.configureDevServerLocation import com.facebook.react.utils.AgpConfiguratorUtils.configureNamespaceForLibraries import com.facebook.react.utils.BackwardCompatUtils.configureBackwardCompatibilityReactMap @@ -84,6 +85,7 @@ class ReactPlugin : Plugin { configureAutolinking(project, extension) configureCodegen(project, extension, rootExtension, isLibrary = false) configureResources(project, extension) + configureBuildTypesForApp(project) } // Library Only Configuration diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt index f8bee6923f901c..f33353349b2c85 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt @@ -19,6 +19,7 @@ import java.net.Inet4Address import java.net.NetworkInterface import javax.xml.parsers.DocumentBuilder import javax.xml.parsers.DocumentBuilderFactory +import kotlin.plus import org.gradle.api.Action import org.gradle.api.Project import org.gradle.api.plugins.AppliedPlugin @@ -27,6 +28,26 @@ import org.w3c.dom.Element @Suppress("UnstableApiUsage") internal object AgpConfiguratorUtils { + fun configureBuildTypesForApp(project: Project) { + val action = + Action { + project.extensions + .getByType(ApplicationAndroidComponentsExtension::class.java) + .finalizeDsl { ext -> + ext.buildTypes { + val debug = + getByName("debug").apply { + manifestPlaceholders["usesCleartextTraffic"] = "true" + } + getByName("release").apply { + manifestPlaceholders["usesCleartextTraffic"] = "false" + } + } + } + } + project.pluginManager.withPlugin("com.android.application", action) + } + fun configureBuildConfigFieldsForApp(project: Project, extension: ReactExtension) { val action = Action { diff --git a/packages/rn-tester/android/app/src/debug/AndroidManifest.xml b/packages/rn-tester/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index fa26aa56e1c144..00000000000000 --- a/packages/rn-tester/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - diff --git a/packages/rn-tester/android/app/src/main/AndroidManifest.xml b/packages/rn-tester/android/app/src/main/AndroidManifest.xml index bd35388167baa1..a842f3a0d29136 100644 --- a/packages/rn-tester/android/app/src/main/AndroidManifest.xml +++ b/packages/rn-tester/android/app/src/main/AndroidManifest.xml @@ -50,6 +50,7 @@ Date: Fri, 18 Jul 2025 04:54:11 -0700 Subject: [PATCH 2/3] Migrate helloworld to use `{usesCleartextTraffic}` manifest placeholder Summary: This removes the need to specify 2 Manifests for apps and we can just use the `main` manifes to toggle if `usesCleartextTraffic` should be enabled or not. This will have to be replicated in the template repository. Changelog: [Android] [Added] - Add support to specify a single Manifest rather than 2 (main/debug) by using the `usesCleartextTraffic` manifest placeholder which is autoconfigured by RNGP. Differential Revision: D78425139 --- .../helloworld/android/app/src/debug/AndroidManifest.xml | 9 --------- .../helloworld/android/app/src/main/AndroidManifest.xml | 1 + 2 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 private/helloworld/android/app/src/debug/AndroidManifest.xml diff --git a/private/helloworld/android/app/src/debug/AndroidManifest.xml b/private/helloworld/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index eb98c01afd79a6..00000000000000 --- a/private/helloworld/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/private/helloworld/android/app/src/main/AndroidManifest.xml b/private/helloworld/android/app/src/main/AndroidManifest.xml index 4122f36a590a44..fe3dfae11627d8 100644 --- a/private/helloworld/android/app/src/main/AndroidManifest.xml +++ b/private/helloworld/android/app/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" + android:usesCleartextTraffic="${usesCleartextTraffic}" android:theme="@style/AppTheme"> Date: Fri, 18 Jul 2025 07:47:17 -0700 Subject: [PATCH 3/3] Create a debugOptimized buildType for Android (#52648) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52648 This creates a `debugOptimized` build type for React Native Android, meaning that we can run C++ optimization on the debug build, while still having the debugger enabled. This is aimed at improving the developer experience for folks developing on low-end devices or emulators. Users that intend to debug can still use the `debug` variant where the full debug symbols are shipped. Changelog: [ANDROID] [ADDED] - Create a debugOptimized buildType for Android Reviewed By: cipolleschi Differential Revision: D78425138 --- .../main/kotlin/com/facebook/react/ReactExtension.kt | 4 ++-- .../com/facebook/react/utils/AgpConfiguratorUtils.kt | 10 ++++++++++ packages/react-native/ReactAndroid/build.gradle.kts | 11 ++++++++++- .../ReactAndroid/hermes-engine/build.gradle.kts | 6 ++++++ .../jni/react/hermes/reactexecutor/CMakeLists.txt | 4 +++- .../main/jni/react/runtime/hermes/jni/CMakeLists.txt | 4 +++- .../src/main/jni/react/runtime/jni/CMakeLists.txt | 4 +++- .../ReactCommon/hermes/executor/CMakeLists.txt | 2 +- .../hermes/inspector-modern/CMakeLists.txt | 2 +- .../ReactCommon/jsinspector-modern/CMakeLists.txt | 10 ++++++---- .../ReactCommon/react/debug/CMakeLists.txt | 2 +- .../ReactCommon/react/runtime/CMakeLists.txt | 4 +++- .../ReactCommon/react/runtime/hermes/CMakeLists.txt | 2 +- 13 files changed, 50 insertions(+), 15 deletions(-) diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt index fa9c937361156b..2e89b8c281dd9c 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt @@ -100,10 +100,10 @@ abstract class ReactExtension @Inject constructor(val project: Project) { * Allows to specify the debuggable variants (by default just 'debug'). Variants in this list will * not be bundled (the bundle file will not be created and won't be copied over). * - * Default: ['debug'] + * Default: ['debug', 'debugOptimized'] */ val debuggableVariants: ListProperty = - objects.listProperty(String::class.java).convention(listOf("debug")) + objects.listProperty(String::class.java).convention(listOf("debug", "debugOptimized")) /** Hermes Config */ diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt index f33353349b2c85..c11d0ccf163224 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt @@ -42,6 +42,16 @@ internal object AgpConfiguratorUtils { getByName("release").apply { manifestPlaceholders["usesCleartextTraffic"] = "false" } + maybeCreate("debugOptimized").apply { + manifestPlaceholders["usesCleartextTraffic"] = "true" + initWith(debug) + externalNativeBuild { + cmake { + arguments("-DCMAKE_BUILD_TYPE=Release") + matchingFallbacks += listOf("release") + } + } + } } } } diff --git a/packages/react-native/ReactAndroid/build.gradle.kts b/packages/react-native/ReactAndroid/build.gradle.kts index 50d2d57927e8c7..ff2b486c4b98c3 100644 --- a/packages/react-native/ReactAndroid/build.gradle.kts +++ b/packages/react-native/ReactAndroid/build.gradle.kts @@ -599,7 +599,7 @@ android { publishing { multipleVariants { withSourcesJar() - includeBuildTypeValues("debug", "release") + includeBuildTypeValues("debug", "release", "debugOptimized") } } @@ -607,6 +607,15 @@ android { unitTests { isIncludeAndroidResources = true } targetSdk = libs.versions.targetSdk.get().toInt() } + + buildTypes { + create("debugOptimized") { + initWith(getByName("debug")) + externalNativeBuild { + cmake { arguments("-DCMAKE_BUILD_TYPE=Release", "-DREACT_NATIVE_DEBUG_OPTIMIZED=True") } + } + } + } } tasks.withType().configureEach { diff --git a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts index d0228e0d4d910c..69814d86625727 100644 --- a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts +++ b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts @@ -306,6 +306,12 @@ android { } } } + buildTypes { + create("debugOptimized") { + initWith(getByName("debug")) + externalNativeBuild { cmake { arguments("-DCMAKE_BUILD_TYPE=Release") } } + } + } } sourceSets.getByName("main") { diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/hermes/reactexecutor/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/react/hermes/reactexecutor/CMakeLists.txt index d0d015ccc55d4c..aa973151b94921 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/hermes/reactexecutor/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/react/hermes/reactexecutor/CMakeLists.txt @@ -25,4 +25,6 @@ target_link_libraries( reactnative ) target_compile_reactnative_options(hermes_executor PRIVATE) -target_compile_options(hermes_executor PRIVATE $<$:-DHERMES_ENABLE_DEBUGGER=1>) +if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED) + target_compile_options(hermes_executor PRIVATE -DHERMES_ENABLE_DEBUGGER=1) +endif() diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/CMakeLists.txt index 6b182daa3acb65..63c1a937341b3f 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/CMakeLists.txt @@ -27,4 +27,6 @@ target_link_libraries(hermesinstancejni ) target_compile_reactnative_options(hermesinstancejni PRIVATE) -target_compile_options(hermesinstancejni PRIVATE $<$:-DHERMES_ENABLE_DEBUGGER=1>) +if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED) + target_compile_options(hermesinstancejni PRIVATE -DHERMES_ENABLE_DEBUGGER=1) +endif () diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/CMakeLists.txt index 0633be11254ec2..8987aed037633a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/CMakeLists.txt @@ -17,7 +17,9 @@ add_library(rninstance ) target_compile_reactnative_options(rninstance PRIVATE) -target_compile_options(rninstance PRIVATE $<$:-DHERMES_ENABLE_DEBUGGER=1>) +if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED) + target_compile_options(rninstance PRIVATE -DHERMES_ENABLE_DEBUGGER=1) +endif () target_merge_so(rninstance) target_include_directories(rninstance PUBLIC .) diff --git a/packages/react-native/ReactCommon/hermes/executor/CMakeLists.txt b/packages/react-native/ReactCommon/hermes/executor/CMakeLists.txt index b512daeafd8fcf..4c1d72be560bc2 100644 --- a/packages/react-native/ReactCommon/hermes/executor/CMakeLists.txt +++ b/packages/react-native/ReactCommon/hermes/executor/CMakeLists.txt @@ -26,7 +26,7 @@ target_link_libraries(hermes_executor_common ) target_compile_reactnative_options(hermes_executor_common PRIVATE) -if(${CMAKE_BUILD_TYPE} MATCHES Debug) +if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED) target_compile_options( hermes_executor_common PRIVATE diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/CMakeLists.txt b/packages/react-native/ReactCommon/hermes/inspector-modern/CMakeLists.txt index 37dbf64c1876d9..3344bf7c4d8c1d 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/CMakeLists.txt +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/CMakeLists.txt @@ -17,7 +17,7 @@ add_library(hermes_inspector_modern target_compile_reactnative_options(hermes_inspector_modern PRIVATE) -if(${CMAKE_BUILD_TYPE} MATCHES Debug) +if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED) target_compile_options( hermes_inspector_modern PRIVATE diff --git a/packages/react-native/ReactCommon/jsinspector-modern/CMakeLists.txt b/packages/react-native/ReactCommon/jsinspector-modern/CMakeLists.txt index 437f8c303cb92e..e06c951fd91fb1 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/CMakeLists.txt +++ b/packages/react-native/ReactCommon/jsinspector-modern/CMakeLists.txt @@ -28,7 +28,9 @@ target_link_libraries(jsinspector reactperflogger ) target_compile_reactnative_options(jsinspector PRIVATE) -target_compile_options(jsinspector PRIVATE - $<$:-DREACT_NATIVE_DEBUGGER_ENABLED=1> - $<$:-DREACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1> -) +if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED) + target_compile_options(jsinspector PRIVATE + -DREACT_NATIVE_DEBUGGER_ENABLED=1 + -DREACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1 + ) +endif () diff --git a/packages/react-native/ReactCommon/react/debug/CMakeLists.txt b/packages/react-native/ReactCommon/react/debug/CMakeLists.txt index 35e81ec635034b..448f163308c616 100644 --- a/packages/react-native/ReactCommon/react/debug/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/debug/CMakeLists.txt @@ -21,6 +21,6 @@ endif() target_compile_reactnative_options(react_debug PRIVATE) target_compile_options(react_debug PRIVATE -Wpedantic) -if(NOT ${CMAKE_BUILD_TYPE} MATCHES Debug) +if(NOT ${CMAKE_BUILD_TYPE} MATCHES Debug AND NOT REACT_NATIVE_DEBUG_OPTIMIZED) target_compile_options(react_debug PUBLIC -DNDEBUG) endif() diff --git a/packages/react-native/ReactCommon/react/runtime/CMakeLists.txt b/packages/react-native/ReactCommon/react/runtime/CMakeLists.txt index 51ffc864b16fe2..0cf910be5bfda1 100644 --- a/packages/react-native/ReactCommon/react/runtime/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/runtime/CMakeLists.txt @@ -16,7 +16,9 @@ add_library(bridgeless ${bridgeless_SRC} ) target_compile_reactnative_options(bridgeless PRIVATE) -target_compile_options(bridgeless PRIVATE $<$:-DHERMES_ENABLE_DEBUGGER=1>) +if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED) + target_compile_options(bridgeless PRIVATE -DHERMES_ENABLE_DEBUGGER=1) +endif () target_include_directories(bridgeless PUBLIC .) react_native_android_selector(fabricjni fabricjni "") diff --git a/packages/react-native/ReactCommon/react/runtime/hermes/CMakeLists.txt b/packages/react-native/ReactCommon/react/runtime/hermes/CMakeLists.txt index d531e870b851b1..dc1a5dd9cab836 100644 --- a/packages/react-native/ReactCommon/react/runtime/hermes/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/runtime/hermes/CMakeLists.txt @@ -29,7 +29,7 @@ target_link_libraries(bridgelesshermes ) target_compile_reactnative_options(bridgelesshermes PRIVATE) -if(${CMAKE_BUILD_TYPE} MATCHES Debug) +if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED) target_compile_options( bridgelesshermes PRIVATE