Compare commits

...
Author SHA1 Message Date
Devmate BotandFacebook GitHub Bot 53d8c9d2d7 xplat/js/react-native-github/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tests/TaskTestUtils.kt
Reviewed By: rshest

Differential Revision: D80931289
2025-08-26 03:56:36 -07:00
Christian FalchandFacebook GitHub Bot 939a75b5ce add SWIFT_ENABLE_EXPLICIT_MODULES to xcode 26 (#53457)
Summary:
XCode 26 introduces building explicit swift modules turned on (SWIFT_ENABLE_EXPLICIT_MODULES). This breaks building with precompiled binaries.

This commit fixes this by adding a step when not building from source where we explicitly set the `SWIFT_ENABLE_EXPLICIT_MODULES` flag to `NO`.

## Changelog:

[IOS] [FIXED] - Added setting SWIFT_ENABLE_EXPLICIT_MODULES=NO when using precompiled to support Xcode 26

Pull Request resolved: https://github.com/facebook/react-native/pull/53457

Test Plan:
```bash
npx react-native-community/cli init MyApp --version nightly --skip-install
cd MyApp
yarn
cd ios
bundle install
RCT_USE_RN_DEP=1 RCT_USE_PREBUILT_RNCORE=1 bundle exec pod install
```

Build above app with Xcode 26 and verify that it no longer fails

Reviewed By: motiz88

Differential Revision: D81025367

Pulled By: cipolleschi

fbshipit-source-id: 1db7c4d7de07d62f43b355aa784d7d9de478023c
2025-08-26 03:39:49 -07:00
generatedunixname537391475639613andFacebook GitHub Bot ec1ee19cda xplat/js/react-native-github/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/PrepareBoostTaskTest.kt (#53358)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53358

Reviewed By: cortinico, cipolleschi

Differential Revision: D80605883

fbshipit-source-id: cf576ee6e6c941eaef25ebf835c771e9bb3d5669
2025-08-25 18:37:02 -07:00
Luna WeiandFacebook GitHub Bot 792e450aff Introduce hysteresis window (#53345)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53345

Changelog: [Internal] - Introduce hysteresis window that is nested between the prerender and hidden window sizes. Currently set to enlargening the prerender window by hysteresis ratio

When a VirtualView intersects with the hysteresis window, it mode remains unchanged.

This prevents us dispatch mode changes for things like overscroll.

I put the hysteresis between prerender and hidden because we already avoid dispatching mode changes from visible -> prerender. For prerender -> visible, we use renderState

Reviewed By: yungsters

Differential Revision: D80511627

fbshipit-source-id: cd14256abc898e7120705e277147d52a06c865a9
2025-08-25 12:58:22 -07:00
Pieter De BaetsandFacebook GitHub Bot 870836ff84 Namespace Perfetto usage (#53424)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53424

Use the namespaced version of these macros to avoid symbol conflicts when multiple instances of `PERFETTO_DEFINE_CATEGORIES` are in the same binary.

The current macro is effectively deprecated: https://github.com/a6f/perfetto_protos/blob/master/CHANGELOG#L691-L696

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D80697205

fbshipit-source-id: 713fec4d41137ddd2f025c7e7130dc44c5a3a656
2025-08-25 11:16:51 -07:00
Andrew DatsenkoandFacebook GitHub Bot 42b94fc709 Add babel-plugin-istanbul for code covearage (#53413)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53413

Changelog: [Internal]
Add dependency on istanbul plugin so we can collect code coverage.

Reviewed By: christophpurrer

Differential Revision: D80723825

fbshipit-source-id: bf0ac0e49e12ea1b01f72c11362019ef68e09ff9
2025-08-25 10:45:16 -07:00
Pieter De BaetsandFacebook GitHub Bot 8881faa7ec Rollout useRawPropsJsiValue (#53426)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53426

Experiment review for this was completed internally, and we can now change the default behaviour to no longer allocate an intermediate folly::dynamic when parsing props.

RawValue will continue supporting a folly::dynamic constructor as some paths go through code path (eg animations)

There should be no user-visible difference in parsing behaviour.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D80799833

fbshipit-source-id: 8eeae656157757eb38f69a2af14409da23b510c8
2025-08-25 07:09:34 -07:00
Phil PluckthunandFacebook GitHub Bot b054540092 Mark @react-native/metro-config as optional peer to fix warning (#53314)
Summary:
The `react-native/metro-config` peer was added in https://github.com/facebook/react-native/commit/fe2bcbf4ba7ce983fac0cd09727c165517b6337f / https://github.com/facebook/react-native/issues/51836 by robhogan

Side-note: It's pulled in via `react-native/community-cli-plugin` which is a direct dependency of `react-native` for the `scripts/bundle.js` script. While, for expo, we'd love to find a way to make this an optional dependency (to avoid excessive deps that `expo` replaces otherwise), for now, it's a direct dependency.

The problem here is that this isn't optional, which means:
- with auto-installing peer dependencies it is directly fulfilled (while `react-native-community/cli` is already marked as optional and skipped)
- with legacy/non-auto peer-dependencies it is flagged as missing, but in an Expo project it wouldn't make sense to install directly

This causes a **package manager regression in the form of either a peer dependency warning**, that shouldn't be fulfilled in an Expo project, or (in the best case scenario) pulls in dependencies [that a user does not need](https://npmgraph.js.org/?q=%40react-native%2Fmetro-config#zoom=w&select=exact%3A%40react-native%2Fmetro-config%400.81.0).

An error message is already in place to inform the user of this being missing when it's not installed, so marking it as optional seems appropriate.

## Changelog:

[INTERNAL] [FIXED] Mark added `react-native/metro-config` peer dependency as optional

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests

Pull Request resolved: https://github.com/facebook/react-native/pull/53314

Test Plan:
Warnings like the following won't occur in fresh Expo (54/preview/`next`) projects
```
warning "workspace-aggregator-484d9ec3-587b-43cb-97de-4dcce3876578 > microfoam-mobile > react-native > react-native/community-cli-plugin@0.81.0" has unmet peer dependency "react-native/metro-config@*".
```

Reviewed By: cortinico

Differential Revision: D80450287

Pulled By: robhogan

fbshipit-source-id: c622fd4c24025676c0ec74de826f863f1e291669
2025-08-24 14:18:42 -07:00
35 changed files with 235 additions and 64 deletions
@@ -40,6 +40,9 @@
"peerDependenciesMeta": {
"@react-native-community/cli": {
"optional": true
},
"@react-native/metro-config": {
"optional": true
}
},
"engines": {
@@ -58,11 +58,11 @@ class PrepareBoostTaskTest {
val boostThirdPartyJniPath = tempFolder.newFolder("boostpath/jni")
val output = tempFolder.newFolder("output")
val task =
createTestTask<PrepareBoostTask> {
it.boostPath.setFrom(boostpath)
it.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
it.boostVersion.set("1.0.0")
it.outputDir.set(output)
createTestTask<PrepareBoostTask> { task ->
task.boostPath.setFrom(boostpath)
task.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
task.boostVersion.set("1.0.0")
task.outputDir.set(output)
}
File(boostpath, "asm/asm.S").apply {
parentFile.mkdirs()
@@ -79,11 +79,11 @@ class PrepareBoostTaskTest {
val boostThirdPartyJniPath = tempFolder.newFolder("boostpath/jni")
val output = tempFolder.newFolder("output")
val task =
createTestTask<PrepareBoostTask> {
it.boostPath.setFrom(boostpath)
it.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
it.boostVersion.set("1.0.0")
it.outputDir.set(output)
createTestTask<PrepareBoostTask> { task ->
task.boostPath.setFrom(boostpath)
task.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
task.boostVersion.set("1.0.0")
task.outputDir.set(output)
}
File(boostpath, "boost_1.0.0/boost/config.hpp").apply {
parentFile.mkdirs()
@@ -100,11 +100,11 @@ class PrepareBoostTaskTest {
val boostThirdPartyJniPath = tempFolder.newFolder("boostpath/jni")
val output = tempFolder.newFolder("output")
val task =
createTestTask<PrepareBoostTask> {
it.boostPath.setFrom(boostpath)
it.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
it.boostVersion.set("1.0.0")
it.outputDir.set(output)
createTestTask<PrepareBoostTask> { task ->
task.boostPath.setFrom(boostpath)
task.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
task.boostVersion.set("1.0.0")
task.outputDir.set(output)
}
File(boostpath, "boost/boost/config.hpp").apply {
parentFile.mkdirs()
@@ -59,8 +59,8 @@ internal fun createZip(dest: File, paths: List<String>) {
val uri = URI.create("jar:file:$dest")
FileSystems.newFileSystem(uri, env).use { zipfs ->
paths.forEach {
val zipEntryPath = zipfs.getPath(it)
paths.forEach { path ->
val zipEntryPath = zipfs.getPath(path)
val zipEntryFolder = zipEntryPath.subpath(0, zipEntryPath.nameCount - 1)
Files.createDirectories(zipEntryFolder)
Files.createFile(zipEntryPath)
@@ -230,21 +230,34 @@ static BOOL sIsAccessibilityUsed = NO;
scrollView.contentOffset.y,
scrollView.frame.size.width,
scrollView.frame.size.height);
const CGFloat visibleWidth = thresholdRect.size.width;
const CGFloat visibleHeight = thresholdRect.size.height;
if (CGRectOverlaps(targetRect, thresholdRect)) {
newMode = RCTVirtualViewModeVisible;
} else {
auto prerender = false;
const CGFloat prerenderRatio = ReactNativeFeatureFlags::virtualViewPrerenderRatio();
if (prerenderRatio > 0) {
thresholdRect = CGRectInset(
thresholdRect, -thresholdRect.size.width * prerenderRatio, -thresholdRect.size.height * prerenderRatio);
thresholdRect = CGRectInset(thresholdRect, -visibleWidth * prerenderRatio, -visibleHeight * prerenderRatio);
prerender = CGRectOverlaps(targetRect, thresholdRect);
}
if (prerender) {
newMode = RCTVirtualViewModePrerender;
} else {
newMode = RCTVirtualViewModeHidden;
thresholdRect = CGRectZero;
const CGFloat hysteresisRatio = ReactNativeFeatureFlags::virtualViewHysteresisRatio();
if (_mode.has_value() && hysteresisRatio > 0) {
thresholdRect = CGRectInset(thresholdRect, -visibleWidth * hysteresisRatio, -visibleHeight * hysteresisRatio);
if (CGRectOverlaps(targetRect, thresholdRect)) {
newMode = _mode.value();
} else {
newMode = RCTVirtualViewModeHidden;
thresholdRect = CGRectZero;
}
} else {
newMode = RCTVirtualViewModeHidden;
thresholdRect = CGRectZero;
}
}
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<1e8a84a53072fa0c8665aead80d0199f>>
* @generated SignedSource<<34c12f5a31aab5bfb874953f1beefef1>>
*/
/**
@@ -432,6 +432,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun useTurboModules(): Boolean = accessor.useTurboModules()
/**
* Sets a hysteresis window for transition between prerender and hidden modes.
*/
@JvmStatic
public fun virtualViewHysteresisRatio(): Double = accessor.virtualViewHysteresisRatio()
/**
* Initial prerender ratio for VirtualView.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<d07316109dce5cc1ce7b0dc010962c3c>>
* @generated SignedSource<<392da016e0bf4193b72c44a508811e10>>
*/
/**
@@ -87,6 +87,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
private var useShadowNodeStateOnCloneCache: Boolean? = null
private var useTurboModuleInteropCache: Boolean? = null
private var useTurboModulesCache: Boolean? = null
private var virtualViewHysteresisRatioCache: Double? = null
private var virtualViewPrerenderRatioCache: Double? = null
override fun commonTestFlag(): Boolean {
@@ -692,6 +693,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun virtualViewHysteresisRatio(): Double {
var cached = virtualViewHysteresisRatioCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.virtualViewHysteresisRatio()
virtualViewHysteresisRatioCache = cached
}
return cached
}
override fun virtualViewPrerenderRatio(): Double {
var cached = virtualViewPrerenderRatioCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<6e384a07f0e7bc237f72b49a1268e16b>>
* @generated SignedSource<<a0453230524ebca2bfb8fad656a6f54a>>
*/
/**
@@ -162,6 +162,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun useTurboModules(): Boolean
@DoNotStrip @JvmStatic public external fun virtualViewHysteresisRatio(): Double
@DoNotStrip @JvmStatic public external fun virtualViewPrerenderRatio(): Double
@DoNotStrip @JvmStatic public external fun override(provider: Any)
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<3c47ba9c7fdbb37f0e06fdca56de3223>>
* @generated SignedSource<<719706a983a073b6c286c49d993f7f80>>
*/
/**
@@ -149,7 +149,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun useOptimizedEventBatchingOnAndroid(): Boolean = false
override fun useRawPropsJsiValue(): Boolean = false
override fun useRawPropsJsiValue(): Boolean = true
override fun useShadowNodeStateOnClone(): Boolean = false
@@ -157,5 +157,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun useTurboModules(): Boolean = false
override fun virtualViewHysteresisRatio(): Double = 0.0
override fun virtualViewPrerenderRatio(): Double = 5.0
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<1a19e0569371a038ba8d3849fb26eb5c>>
* @generated SignedSource<<594815ba6a984c460ab8bddd91c5cae2>>
*/
/**
@@ -91,6 +91,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
private var useShadowNodeStateOnCloneCache: Boolean? = null
private var useTurboModuleInteropCache: Boolean? = null
private var useTurboModulesCache: Boolean? = null
private var virtualViewHysteresisRatioCache: Double? = null
private var virtualViewPrerenderRatioCache: Double? = null
override fun commonTestFlag(): Boolean {
@@ -763,6 +764,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}
override fun virtualViewHysteresisRatio(): Double {
var cached = virtualViewHysteresisRatioCache
if (cached == null) {
cached = currentProvider.virtualViewHysteresisRatio()
accessedFeatureFlags.add("virtualViewHysteresisRatio")
virtualViewHysteresisRatioCache = cached
}
return cached
}
override fun virtualViewPrerenderRatio(): Double {
var cached = virtualViewPrerenderRatioCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<5f84a9a17209b9ecb95e13e6567e7c3c>>
* @generated SignedSource<<dfbd5e84392f1fda0e68324582c328b2>>
*/
/**
@@ -157,5 +157,7 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun useTurboModules(): Boolean
@DoNotStrip public fun virtualViewHysteresisRatio(): Double
@DoNotStrip public fun virtualViewPrerenderRatio(): Double
}
@@ -41,6 +41,7 @@ public class ReactVirtualView(context: Context) :
internal var modeChangeEmitter: VirtualViewModeChangeEmitter? = null
internal var prerenderRatio: Double = ReactNativeFeatureFlags.virtualViewPrerenderRatio()
internal val debugLogEnabled: Boolean = ReactNativeFeatureFlags.enableVirtualViewDebugFeatures()
private val hysteresisRatio: Double = ReactNativeFeatureFlags.virtualViewHysteresisRatio()
private val onWindowFocusChangeListener =
if (ReactNativeFeatureFlags.enableVirtualViewWindowFocusDetection()) {
@@ -222,6 +223,8 @@ public class ReactVirtualView(context: Context) :
bottom + offsetY,
)
scrollView.getDrawingRect(thresholdRect)
val visibleHeight = thresholdRect.height()
val visibleWidth = thresholdRect.width()
// TODO: Validate whether this is still the case and whether these checks are still needed.
// updateRects will initially get called before the targetRect has any dimensions set, so if
@@ -260,16 +263,32 @@ public class ReactVirtualView(context: Context) :
var prerender = false
if (prerenderRatio > 0.0) {
thresholdRect.inset(
(-thresholdRect.width() * prerenderRatio).toInt(),
(-thresholdRect.height() * prerenderRatio).toInt(),
(-visibleWidth * prerenderRatio).toInt(),
(-visibleHeight * prerenderRatio).toInt(),
)
prerender = rectsOverlap(targetRect, thresholdRect)
}
if (prerender) {
newMode = VirtualViewMode.Prerender
} else {
newMode = VirtualViewMode.Hidden
thresholdRect.setEmpty()
val _mode = mode // local variable so Kotlin knows its not nullable
if (_mode != null && hysteresisRatio > 0.0) {
thresholdRect.inset(
(-visibleWidth * hysteresisRatio).toInt(),
(-visibleHeight * hysteresisRatio).toInt(),
)
if (rectsOverlap(targetRect, thresholdRect)) {
// In hysteresis window, no change to mode
newMode = _mode
debugLog("dispatchOnModeChangeIfNeeded") { "hysteresis, mode=$newMode" }
} else {
newMode = VirtualViewMode.Hidden
thresholdRect.setEmpty()
}
} else {
newMode = VirtualViewMode.Hidden
thresholdRect.setEmpty()
}
}
}
debugLog("dispatchOnModeChangeIfNeeded") {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<1eff5bade524e3ad8e827ad4adb37f1a>>
* @generated SignedSource<<16b12024bb363358ef09b9a42cb2fc97>>
*/
/**
@@ -441,6 +441,12 @@ class ReactNativeFeatureFlagsJavaProvider
return method(javaProvider_);
}
double virtualViewHysteresisRatio() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jdouble()>("virtualViewHysteresisRatio");
return method(javaProvider_);
}
double virtualViewPrerenderRatio() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jdouble()>("virtualViewPrerenderRatio");
@@ -786,6 +792,11 @@ bool JReactNativeFeatureFlagsCxxInterop::useTurboModules(
return ReactNativeFeatureFlags::useTurboModules();
}
double JReactNativeFeatureFlagsCxxInterop::virtualViewHysteresisRatio(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::virtualViewHysteresisRatio();
}
double JReactNativeFeatureFlagsCxxInterop::virtualViewPrerenderRatio(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::virtualViewPrerenderRatio();
@@ -1023,6 +1034,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"useTurboModules",
JReactNativeFeatureFlagsCxxInterop::useTurboModules),
makeNativeMethod(
"virtualViewHysteresisRatio",
JReactNativeFeatureFlagsCxxInterop::virtualViewHysteresisRatio),
makeNativeMethod(
"virtualViewPrerenderRatio",
JReactNativeFeatureFlagsCxxInterop::virtualViewPrerenderRatio),
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<05dba4cd49bd4f490e1ea943dd02cae0>>
* @generated SignedSource<<54118ccd475a8bf1d7db83304b1f17d0>>
*/
/**
@@ -231,6 +231,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool useTurboModules(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static double virtualViewHysteresisRatio(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static double virtualViewPrerenderRatio(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<a7bd9fcbbcb19ee8a939b4c08e0fd508>>
* @generated SignedSource<<12a06ea04fc09c34f1fbdcbdf6046d81>>
*/
/**
@@ -294,6 +294,10 @@ bool ReactNativeFeatureFlags::useTurboModules() {
return getAccessor().useTurboModules();
}
double ReactNativeFeatureFlags::virtualViewHysteresisRatio() {
return getAccessor().virtualViewHysteresisRatio();
}
double ReactNativeFeatureFlags::virtualViewPrerenderRatio() {
return getAccessor().virtualViewPrerenderRatio();
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<4831f7b871223d8347db93f9a0b3a1f9>>
* @generated SignedSource<<eee81e4e9bb13ef5134d4e2d79876b38>>
*/
/**
@@ -374,6 +374,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool useTurboModules();
/**
* Sets a hysteresis window for transition between prerender and hidden modes.
*/
RN_EXPORT static double virtualViewHysteresisRatio();
/**
* Initial prerender ratio for VirtualView.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<d5243da4eb6bdde1e703ae55fcccbf0f>>
* @generated SignedSource<<3c5588a851e6cdefaba22236c5ebb828>>
*/
/**
@@ -1235,6 +1235,24 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() {
return flagValue.value();
}
double ReactNativeFeatureFlagsAccessor::virtualViewHysteresisRatio() {
auto flagValue = virtualViewHysteresisRatio_.load();
if (!flagValue.has_value()) {
// This block is not exclusive but it is not necessary.
// If multiple threads try to initialize the feature flag, we would only
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(67, "virtualViewHysteresisRatio");
flagValue = currentProvider_->virtualViewHysteresisRatio();
virtualViewHysteresisRatio_ = flagValue;
}
return flagValue.value();
}
double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() {
auto flagValue = virtualViewPrerenderRatio_.load();
@@ -1244,7 +1262,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(67, "virtualViewPrerenderRatio");
markFlagAsAccessed(68, "virtualViewPrerenderRatio");
flagValue = currentProvider_->virtualViewPrerenderRatio();
virtualViewPrerenderRatio_ = flagValue;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ce6cfc25358a636fcd9cd6605e9008ed>>
* @generated SignedSource<<f1eb31a7412bff743a5c581224d71e2a>>
*/
/**
@@ -99,6 +99,7 @@ class ReactNativeFeatureFlagsAccessor {
bool useShadowNodeStateOnClone();
bool useTurboModuleInterop();
bool useTurboModules();
double virtualViewHysteresisRatio();
double virtualViewPrerenderRatio();
void override(std::unique_ptr<ReactNativeFeatureFlagsProvider> provider);
@@ -111,7 +112,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 68> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 69> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> cdpInteractionMetricsEnabled_;
@@ -180,6 +181,7 @@ class ReactNativeFeatureFlagsAccessor {
std::atomic<std::optional<bool>> useShadowNodeStateOnClone_;
std::atomic<std::optional<bool>> useTurboModuleInterop_;
std::atomic<std::optional<bool>> useTurboModules_;
std::atomic<std::optional<double>> virtualViewHysteresisRatio_;
std::atomic<std::optional<double>> virtualViewPrerenderRatio_;
};
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<30170e483b919c7bd235bfcfe4174c39>>
* @generated SignedSource<<a76f1a1e8ba0d65b689b4b87d33d7ced>>
*/
/**
@@ -280,7 +280,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
}
bool useRawPropsJsiValue() override {
return false;
return true;
}
bool useShadowNodeStateOnClone() override {
@@ -295,6 +295,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
double virtualViewHysteresisRatio() override {
return 0.0;
}
double virtualViewPrerenderRatio() override {
return 5.0;
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<6030ed59832efdf42e23c13b689da64f>>
* @generated SignedSource<<e2a5086e5586caf4c90ef503416a0e83>>
*/
/**
@@ -648,6 +648,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
return ReactNativeFeatureFlagsDefaults::useTurboModules();
}
double virtualViewHysteresisRatio() override {
auto value = values_["virtualViewHysteresisRatio"];
if (!value.isNull()) {
return value.getDouble();
}
return ReactNativeFeatureFlagsDefaults::virtualViewHysteresisRatio();
}
double virtualViewPrerenderRatio() override {
auto value = values_["virtualViewPrerenderRatio"];
if (!value.isNull()) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<95940b74b0055760be69c501a97a6f45>>
* @generated SignedSource<<feb44bb7ec97d29787eac070103f9e1b>>
*/
/**
@@ -92,6 +92,7 @@ class ReactNativeFeatureFlagsProvider {
virtual bool useShadowNodeStateOnClone() = 0;
virtual bool useTurboModuleInterop() = 0;
virtual bool useTurboModules() = 0;
virtual double virtualViewHysteresisRatio() = 0;
virtual double virtualViewPrerenderRatio() = 0;
};
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<998bdf037d58ca747c22ada099d236f0>>
* @generated SignedSource<<c9c36c1dbece9e27f7b71da7611cb747>>
*/
/**
@@ -379,6 +379,11 @@ bool NativeReactNativeFeatureFlags::useTurboModules(
return ReactNativeFeatureFlags::useTurboModules();
}
double NativeReactNativeFeatureFlags::virtualViewHysteresisRatio(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::virtualViewHysteresisRatio();
}
double NativeReactNativeFeatureFlags::virtualViewPrerenderRatio(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::virtualViewPrerenderRatio();
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<89c5d22cd228da57d82843f7e660f262>>
* @generated SignedSource<<320e69fa54228a352fad210e3a43b947>>
*/
/**
@@ -170,6 +170,8 @@ class NativeReactNativeFeatureFlags
bool useTurboModules(jsi::Runtime& runtime);
double virtualViewHysteresisRatio(jsi::Runtime& runtime);
double virtualViewPrerenderRatio(jsi::Runtime& runtime);
};
@@ -27,8 +27,6 @@ const std::string JS_SAMPLING_TRACK = "JS Sampling";
const int SAMPLING_HZ = 1000;
using perfetto::TrackEvent;
#if defined(__ANDROID__)
std::string getApplicationId() {
pid_t pid = getpid();
@@ -23,8 +23,6 @@ const int SAMPLING_HZ = 100;
int64_t hermesDeltaTime = 0;
using perfetto::TrackEvent;
uint64_t hermesToPerfettoTime(int64_t hermesTs) {
if (hermesDeltaTime == 0) {
hermesDeltaTime = TrackEvent::GetTraceTimeNs() -
@@ -113,7 +111,7 @@ void HermesPerfettoDataSource::OnStart(const StartArgs&) {
"react-native",
perfetto::DynamicString{"Profiling Started"},
getPerfettoWebPerfTrackSync("JS Sampling"),
perfetto::TrackEvent::GetTraceTimeNs());
TrackEvent::GetTraceTimeNs());
}
void HermesPerfettoDataSource::OnFlush(const FlushArgs&) {
@@ -29,7 +29,7 @@ void initializePerfetto() {
args.backends |= perfetto::kSystemBackend;
args.use_monotonic_clock = true;
perfetto::Tracing::Initialize(args);
perfetto::TrackEvent::Register();
TrackEvent::Register();
});
HermesPerfettoDataSource::RegisterDataSource();
@@ -42,7 +42,7 @@ static perfetto::Track createTrack(const std::string& trackName) {
auto track = perfetto::Track(trackId++);
auto desc = track.Serialize();
desc.set_name(trackName);
perfetto::TrackEvent::SetTrackDescriptor(track, desc);
TrackEvent::SetTrackDescriptor(track, desc);
return track;
}
@@ -9,6 +9,7 @@
#include "ReactPerfettoCategories.h"
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
PERFETTO_TRACK_EVENT_STATIC_STORAGE_IN_NAMESPACE(facebook::react);
PERFETTO_USE_CATEGORIES_FROM_NAMESPACE(facebook::react);
#endif
@@ -11,7 +11,8 @@
#include <perfetto.h>
PERFETTO_DEFINE_CATEGORIES(
PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE(
facebook::react,
perfetto::Category("react-native")
.SetDescription("User timing events from React Native"));
@@ -23,7 +23,7 @@ void initializePerfetto() {
#endif
args.use_monotonic_clock = true;
perfetto::Tracing::Initialize(args);
perfetto::TrackEvent::Register();
facebook::react::TrackEvent::Register();
});
}
@@ -18,7 +18,8 @@
#if WITH_PERFETTO
#include <perfetto.h>
PERFETTO_DEFINE_CATEGORIES(
PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE(
facebook::react,
perfetto::Category("rncxx").SetDescription("Events from RN/Granite"));
void initializePerfetto();
@@ -719,13 +719,12 @@ const definitions: FeatureFlagDefinitions = {
ossReleaseStage: 'none',
},
useRawPropsJsiValue: {
defaultValue: false,
defaultValue: true,
metadata: {
dateAdded: '2024-12-02',
description:
'Instead of using folly::dynamic as internal representation in RawProps and RawValue, use jsi::Value',
expectedReleaseValue: true,
purpose: 'experimentation',
purpose: 'release',
},
ossReleaseStage: 'none',
},
@@ -761,6 +760,17 @@ const definitions: FeatureFlagDefinitions = {
},
ossReleaseStage: 'canary',
},
virtualViewHysteresisRatio: {
defaultValue: 0,
metadata: {
dateAdded: '2025-08-22',
description:
'Sets a hysteresis window for transition between prerender and hidden modes.',
expectedReleaseValue: 1,
purpose: 'experimentation',
},
ossReleaseStage: 'none',
},
virtualViewPrerenderRatio: {
defaultValue: 5,
metadata: {
@@ -503,6 +503,13 @@ def react_native_post_install(
ReactNativePodsUtils.updateOSDeploymentTarget(installer)
ReactNativePodsUtils.set_dynamic_frameworks_flags(installer)
ReactNativePodsUtils.add_ndebug_flag_to_pods_in_release(installer)
if !ReactNativeCoreUtils.build_rncore_from_source()
# In XCode 26 we need to revert the new setting SWIFT_ENABLE_EXPLICIT_MODULES when building
# with precompiled binaries.
ReactNativePodsUtils.set_build_setting(installer, build_setting: "SWIFT_ENABLE_EXPLICIT_MODULES", value: "NO")
end
SPM.apply_on_post_install(installer)
if privacy_file_aggregation_enabled
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<6ec32c21e134bd51702d7fcab094c725>>
* @generated SignedSource<<bb685c713f0fdecb402fc14a6158d5ae>>
* @flow strict
* @noformat
*/
@@ -114,6 +114,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{
useShadowNodeStateOnClone: Getter<boolean>,
useTurboModuleInterop: Getter<boolean>,
useTurboModules: Getter<boolean>,
virtualViewHysteresisRatio: Getter<number>,
virtualViewPrerenderRatio: Getter<number>,
}>;
@@ -436,7 +437,7 @@ export const useOptimizedEventBatchingOnAndroid: Getter<boolean> = createNativeF
/**
* Instead of using folly::dynamic as internal representation in RawProps and RawValue, use jsi::Value
*/
export const useRawPropsJsiValue: Getter<boolean> = createNativeFlagGetter('useRawPropsJsiValue', false);
export const useRawPropsJsiValue: Getter<boolean> = createNativeFlagGetter('useRawPropsJsiValue', true);
/**
* Use the state stored on the source shadow node when cloning it instead of reading in the most recent state on the shadow node family.
*/
@@ -449,6 +450,10 @@ export const useTurboModuleInterop: Getter<boolean> = createNativeFlagGetter('us
* When enabled, NativeModules will be executed by using the TurboModule system
*/
export const useTurboModules: Getter<boolean> = createNativeFlagGetter('useTurboModules', false);
/**
* Sets a hysteresis window for transition between prerender and hidden modes.
*/
export const virtualViewHysteresisRatio: Getter<number> = createNativeFlagGetter('virtualViewHysteresisRatio', 0);
/**
* Initial prerender ratio for VirtualView.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<2b0679c42d8e1cb021612807d94d9f4c>>
* @generated SignedSource<<da22f4c43e3bdcd999e3dd1dd5896c63>>
* @flow strict
* @noformat
*/
@@ -92,6 +92,7 @@ export interface Spec extends TurboModule {
+useShadowNodeStateOnClone?: () => boolean;
+useTurboModuleInterop?: () => boolean;
+useTurboModules?: () => boolean;
+virtualViewHysteresisRatio?: () => number;
+virtualViewPrerenderRatio?: () => number;
}
+3
View File
@@ -7,6 +7,9 @@
"scripts": {
"build": "./build.sh"
},
"dependencies": {
"babel-plugin-istanbul": "^7.0.0"
},
"peerDependencies": {
"jest": "^29.7.0",
"jest-snapshot": "^29.7.0"
+12 -1
View File
@@ -2885,6 +2885,17 @@ babel-plugin-istanbul@^6.1.1:
istanbul-lib-instrument "^5.0.4"
test-exclude "^6.0.0"
babel-plugin-istanbul@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz#629a178f63b83dc9ecee46fd20266283b1f11280"
integrity sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@istanbuljs/load-nyc-config" "^1.0.0"
"@istanbuljs/schema" "^0.1.3"
istanbul-lib-instrument "^6.0.2"
test-exclude "^6.0.0"
babel-plugin-jest-hoist@^29.6.3:
version "29.6.3"
resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626"
@@ -5552,7 +5563,7 @@ istanbul-lib-instrument@^5.0.4:
istanbul-lib-coverage "^3.2.0"
semver "^6.3.0"
istanbul-lib-instrument@^6.0.0:
istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.2:
version "6.0.3"
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765"
integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==