Skip to content

Commit 80ecd14

Browse files
j-piaseckimeta-codesync[bot]
authored andcommitted
Add Android opt-in for RN_STRICT_API (#58849)
Summary: Pull Request resolved: #58849 Adds a `strictCxxApiEnabled` (or `react.strictCxxApiEnabled`) Gradle property that defines `RN_STRICT_API` for an app's own native code: the app library, autolinked libraries and app codegen, through `common_flags` in `ReactNative-application.cmake`. React Native's own code is unaffected, since it defines `RN_BUILDING`. The shared precompiled header now includes React Native through module umbrellas, as its direct includes would otherwise fail under the flag. Codegen targets reuse that precompiled header, so a direct include of any header it already contains is skipped by `#pragma once` and the guards are effectively not enforced in those targets. Changelog: [Android][Added] - Add `strictCxxApiEnabled` Gradle property to enforce React Native's C++ stable API in app native code Differential Revision: D123399797
1 parent 8bdc1fc commit 80ecd14

6 files changed

Lines changed: 64 additions & 10 deletions

File tree

‎packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.android.build.api.variant.Variant
1212
import com.facebook.react.ReactExtension
1313
import com.facebook.react.internal.StubPchBuildService
1414
import com.facebook.react.utils.ProjectUtils.getReactNativeArchitectures
15+
import com.facebook.react.utils.ProjectUtils.isStrictCxxApiEnabled
1516
import java.io.File
1617
import org.gradle.api.Project
1718

@@ -58,6 +59,9 @@ internal object NdkConfiguratorUtils {
5859
if (cmakeArgs.none { it.startsWith("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES") }) {
5960
cmakeArgs.add("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON")
6061
}
62+
if (project.isStrictCxxApiEnabled && cmakeArgs.none { it.startsWith("-DRN_STRICT_API") }) {
63+
cmakeArgs.add("-DRN_STRICT_API=ON")
64+
}
6165

6266
val architectures = project.getReactNativeArchitectures()
6367
// abiFilters are split ABI are not compatible each other, so we set the abiFilters

‎packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/ProjectUtils.kt‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ import com.facebook.react.utils.PropertyUtils.REACT_NATIVE_ARCHITECTURES
1515
import com.facebook.react.utils.PropertyUtils.SCOPED_EDGE_TO_EDGE_ENABLED
1616
import com.facebook.react.utils.PropertyUtils.SCOPED_HERMES_ENABLED
1717
import com.facebook.react.utils.PropertyUtils.SCOPED_REACT_NATIVE_ARCHITECTURES
18+
import com.facebook.react.utils.PropertyUtils.SCOPED_STRICT_CXX_API_ENABLED
1819
import com.facebook.react.utils.PropertyUtils.SCOPED_USE_THIRD_PARTY_JSC
20+
import com.facebook.react.utils.PropertyUtils.STRICT_CXX_API_ENABLED
1921
import com.facebook.react.utils.PropertyUtils.USE_THIRD_PARTY_JSC
2022
import org.gradle.api.Project
2123
import org.gradle.api.file.DirectoryProperty
@@ -56,6 +58,13 @@ internal object ProjectUtils {
5658
(project.hasProperty(SCOPED_EDGE_TO_EDGE_ENABLED) &&
5759
project.property(SCOPED_EDGE_TO_EDGE_ENABLED).toString().toBoolean())
5860

61+
internal val Project.isStrictCxxApiEnabled: Boolean
62+
get() =
63+
(project.hasProperty(STRICT_CXX_API_ENABLED) &&
64+
project.property(STRICT_CXX_API_ENABLED).toString().toBoolean()) ||
65+
(project.hasProperty(SCOPED_STRICT_CXX_API_ENABLED) &&
66+
project.property(SCOPED_STRICT_CXX_API_ENABLED).toString().toBoolean())
67+
5968
internal val Project.useThirdPartyJSC: Boolean
6069
get() =
6170
(project.hasProperty(USE_THIRD_PARTY_JSC) &&

‎packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PropertyUtils.kt‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ object PropertyUtils {
2929
const val EDGE_TO_EDGE_ENABLED = "edgeToEdgeEnabled"
3030
const val SCOPED_EDGE_TO_EDGE_ENABLED = "react.edgeToEdgeEnabled"
3131

32+
/**
33+
* Public property that enforces the C++ stable API for the app's own native code by defining
34+
* RN_STRICT_API
35+
*/
36+
const val STRICT_CXX_API_ENABLED = "strictCxxApiEnabled"
37+
const val SCOPED_STRICT_CXX_API_ENABLED = "react.strictCxxApiEnabled"
38+
3239
/** Public property that excludes jsctooling from core */
3340
const val USE_THIRD_PARTY_JSC = "useThirdPartyJSC"
3441
const val SCOPED_USE_THIRD_PARTY_JSC = "react.useThirdPartyJSC"

‎packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/ProjectUtilsTest.kt‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.facebook.react.utils.ProjectUtils.getReactNativeArchitectures
1515
import com.facebook.react.utils.ProjectUtils.isEdgeToEdgeEnabled
1616
import com.facebook.react.utils.ProjectUtils.isHermesEnabled
1717
import com.facebook.react.utils.ProjectUtils.isNewArchEnabled
18+
import com.facebook.react.utils.ProjectUtils.isStrictCxxApiEnabled
1819
import com.facebook.react.utils.ProjectUtils.needsCodegenFromPackageJson
1920
import java.io.File
2021
import org.assertj.core.api.Assertions.assertThat
@@ -115,6 +116,39 @@ class ProjectUtilsTest {
115116
assertThat(project.isEdgeToEdgeEnabled).isFalse()
116117
}
117118

119+
@Test
120+
fun isStrictCxxApiEnabled_returnsFalseByDefault() {
121+
assertThat(createProject().isStrictCxxApiEnabled).isFalse()
122+
}
123+
124+
@Test
125+
fun isStrictCxxApiEnabled_withEnabledViaProperty_returnsTrue() {
126+
val project = createProject()
127+
project.extensions.extraProperties.set("strictCxxApiEnabled", "true")
128+
assertThat(project.isStrictCxxApiEnabled).isTrue()
129+
}
130+
131+
@Test
132+
fun isStrictCxxApiEnabled_withEnabledViaScopedProperty_returnsTrue() {
133+
val project = createProject()
134+
project.extensions.extraProperties.set("react.strictCxxApiEnabled", "true")
135+
assertThat(project.isStrictCxxApiEnabled).isTrue()
136+
}
137+
138+
@Test
139+
fun isStrictCxxApiEnabled_withDisabledViaProperty_returnsFalse() {
140+
val project = createProject()
141+
project.extensions.extraProperties.set("strictCxxApiEnabled", "false")
142+
assertThat(project.isStrictCxxApiEnabled).isFalse()
143+
}
144+
145+
@Test
146+
fun isStrictCxxApiEnabled_withInvalidViaProperty_returnsFalse() {
147+
val project = createProject()
148+
project.extensions.extraProperties.set("strictCxxApiEnabled", "¯\\_(ツ)_/¯")
149+
assertThat(project.isStrictCxxApiEnabled).isFalse()
150+
}
151+
118152
@Test
119153
fun needsCodegenFromPackageJson_withCodegenConfigInPackageJson_returnsTrue() {
120154
val project = createProject()

‎packages/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ target_link_libraries(${CMAKE_PROJECT_NAME}
8989
add_library(common_flags INTERFACE)
9090
target_compile_options(common_flags INTERFACE ${folly_FLAGS})
9191

92+
if(RN_STRICT_API)
93+
target_compile_definitions(common_flags INTERFACE RN_STRICT_API)
94+
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE RN_STRICT_API)
95+
endif()
96+
9297
# Defines the `reactnative_pch` target and `target_reuse_reactnative_pch()`, so
9398
# the codegen targets below share a single precompiled header. Has to come after
9499
# `common_flags`, as the precompiled header is built with the same flags as its

‎packages/react-native/ReactAndroid/cmake-utils/precompiled-header/pch.h‎

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,10 @@
77

88
#pragma once
99

10-
#include <ReactCommon/JavaTurboModule.h>
11-
#include <ReactCommon/TurboModule.h>
10+
#include <React/Bridging.h>
11+
#include <React/ComponentRegistry.h>
12+
#include <React/NativeModuleCore.h>
13+
#include <React/RendererCore.h>
14+
#include <React/View.h>
1215
#include <folly/dynamic.h>
1316
#include <jsi/jsi.h>
14-
#include <react/bridging/Bridging.h>
15-
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
16-
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
17-
#include <react/renderer/components/view/ViewEventEmitter.h>
18-
#include <react/renderer/core/ConcreteComponentDescriptor.h>
19-
#include <react/renderer/core/PropsParserContext.h>
20-
#include <react/renderer/core/StateData.h>
21-
#include <react/renderer/core/propsConversions.h>

0 commit comments

Comments
 (0)