Skip to content

Commit 7013d77

Browse files
zeyapfacebook-github-bot
authored andcommitted
Add c++ AnimatedModule to DefaultTurboModules (#55729)
Summary: This is added so that one can easily enables c++ AnimatedModule in open source. If an app doesn't use `RCTAnimatedModuleProvider`(ios) or `AnimatedCxxReactPackage`(android), it can fallback to this default AnimatedModule when it has both c++animated and shared backend enabled - shared backend removes the need to pass down start/stop callbacks to NativeAnimatedNodesManagerProvider, so we can cleanly initialize it as static default - RCTAnimatedModuleProvider uses the version of AnimatedModule that still relies on a dedicated CADisplayLink for start/stop - AnimatedCxxReactPackage also bundles internal ViewEventModule (for NativeViewEvents) that shares `NativeAnimatedNodesManagerProvider` with AnimatedModule, but NativeViewEvents is not needed for open source - Alternatively we could also expose `NativeAnimatedNodesManagerProvider` via UIManager so other turbomodules can also use it. However I don't think it makes sense to double down on another animation API on UIManager given we have shared backend. - This assumes DefaultTurboModules is always the fallback module provider. So it'll not override when app already uses RCTAnimatedModuleProvider or AnimatedCxxReactPackage ## Changelog: [General] [Added] - Add c++ AnimatedModule to DefaultTurboModules Reviewed By: NickGerleman Differential Revision: D94244698
1 parent a7fe602 commit 7013d77

File tree

8 files changed

+106
-80
lines changed

8 files changed

+106
-80
lines changed

packages/react-native/Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ let reactFabric = RNTarget(
424424
name: .reactFabric,
425425
path: "ReactCommon/react/renderer",
426426
excludedPaths: [
427+
"animated/tests",
427428
"animations/tests",
428429
"attributedstring/tests",
429430
"core/tests",
@@ -456,7 +457,7 @@ let reactFabric = RNTarget(
456457
"components/root/tests",
457458
],
458459
dependencies: [.reactNativeDependencies, .reactJsiExecutor, .rctTypesafety, .reactTurboModuleCore, .jsi, .logger, .reactDebug, .reactFeatureFlags, .reactUtils, .reactRuntimeScheduler, .reactCxxReact, .reactRendererDebug, .reactGraphics, .yoga],
459-
sources: ["animationbackend", "animations", "attributedstring", "core", "componentregistry", "componentregistry/native", "components/root", "components/view", "components/view/platform/cxx", "components/scrollview", "components/scrollview/platform/cxx", "components/scrollview/platform/ios", "components/legacyviewmanagerinterop", "components/legacyviewmanagerinterop/platform/ios", "dom", "scheduler", "mounting", "observers/events", "observers/intersection", "telemetry", "consistency", "leakchecker", "uimanager", "uimanager/consistency"]
460+
sources: ["animated", "animationbackend", "animations", "attributedstring", "core", "componentregistry", "componentregistry/native", "components/root", "components/view", "components/view/platform/cxx", "components/scrollview", "components/scrollview/platform/cxx", "components/scrollview/platform/ios", "components/legacyviewmanagerinterop", "components/legacyviewmanagerinterop/platform/ios", "dom", "scheduler", "mounting", "observers/events", "observers/intersection", "telemetry", "consistency", "leakchecker", "uimanager", "uimanager/consistency"]
460461
)
461462

462463
let reactFabricInputAccessory = RNTarget(

packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ add_react_common_subdir(react/debug)
8282
add_react_common_subdir(react/featureflags)
8383
add_react_common_subdir(react/performance/cdpmetrics)
8484
add_react_common_subdir(react/performance/timeline)
85+
add_react_common_subdir(react/renderer/animated)
8586
add_react_common_subdir(react/renderer/animationbackend)
8687
add_react_common_subdir(react/renderer/animations)
8788
add_react_common_subdir(react/renderer/attributedstring)
@@ -201,6 +202,7 @@ add_library(reactnative
201202
$<TARGET_OBJECTS:react_newarchdefaults>
202203
$<TARGET_OBJECTS:react_performance_cdpmetrics>
203204
$<TARGET_OBJECTS:react_performance_timeline>
205+
$<TARGET_OBJECTS:react_renderer_animated>
204206
$<TARGET_OBJECTS:react_renderer_animationbackend>
205207
$<TARGET_OBJECTS:react_renderer_animations>
206208
$<TARGET_OBJECTS:react_renderer_attributedstring>
@@ -295,6 +297,7 @@ target_include_directories(reactnative
295297
$<TARGET_PROPERTY:react_newarchdefaults,INTERFACE_INCLUDE_DIRECTORIES>
296298
$<TARGET_PROPERTY:react_performance_cdpmetrics,INTERFACE_INCLUDE_DIRECTORIES>
297299
$<TARGET_PROPERTY:react_performance_timeline,INTERFACE_INCLUDE_DIRECTORIES>
300+
$<TARGET_PROPERTY:react_renderer_animated,INTERFACE_INCLUDE_DIRECTORIES>
298301
$<TARGET_PROPERTY:react_renderer_animationbackend,INTERFACE_INCLUDE_DIRECTORIES>
299302
$<TARGET_PROPERTY:react_renderer_animations,INTERFACE_INCLUDE_DIRECTORIES>
300303
$<TARGET_PROPERTY:react_renderer_attributedstring,INTERFACE_INCLUDE_DIRECTORIES>

packages/react-native/ReactApple/RCTAnimatedModuleProvider/RCTAnimatedModuleProvider.mm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ - (void)_onDisplayLinkTick
7070
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
7171
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
7272
{
73-
if (facebook::react::ReactNativeFeatureFlags::cxxNativeAnimatedEnabled()) {
73+
if (facebook::react::ReactNativeFeatureFlags::cxxNativeAnimatedEnabled() &&
74+
// initialization is moved to DefaultTurboModules when using shared animated backend
75+
// TODO: T257053961 deprecate RCTAnimatedModuleProvider.
76+
!facebook::react::ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
7477
if (name == facebook::react::AnimatedModule::kModuleName) {
7578
__weak RCTAnimatedModuleProvider *weakSelf = self;
7679
auto provider = std::make_shared<facebook::react::NativeAnimatedNodesManagerProvider>(

packages/react-native/ReactCommon/react/nativemodule/defaults/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ target_link_libraries(react_nativemodule_defaults
2323
react_nativemodule_idlecallbacks
2424
react_nativemodule_intersectionobserver
2525
react_nativemodule_webperformance
26+
react_renderer_animated
2627
)
2728
target_compile_reactnative_options(react_nativemodule_defaults PRIVATE)
2829
target_compile_options(react_nativemodule_defaults PRIVATE -Wpedantic)

packages/react-native/ReactCommon/react/nativemodule/defaults/DefaultTurboModules.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <react/nativemodule/intersectionobserver/NativeIntersectionObserver.h>
1414
#include <react/nativemodule/microtasks/NativeMicrotasks.h>
1515
#include <react/nativemodule/webperformance/NativePerformance.h>
16+
#include <react/renderer/animated/AnimatedModule.h>
1617

1718
#ifdef REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY
1819
#include <react/nativemodule/devtoolsruntimesettings/DevToolsRuntimeSettingsModule.h>
@@ -49,6 +50,13 @@ namespace facebook::react {
4950
}
5051
}
5152

53+
if (ReactNativeFeatureFlags::cxxNativeAnimatedEnabled() &&
54+
ReactNativeFeatureFlags::useSharedAnimatedBackend() &&
55+
name == AnimatedModule::kModuleName) {
56+
return std::make_shared<AnimatedModule>(
57+
jsInvoker, std::make_shared<NativeAnimatedNodesManagerProvider>());
58+
}
59+
5260
#ifdef REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY
5361
if (name == DevToolsRuntimeSettingsModule::kModuleName) {
5462
return std::make_shared<DevToolsRuntimeSettingsModule>(jsInvoker);

packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManagerProvider.cpp

Lines changed: 79 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,16 @@ std::shared_ptr<NativeAnimatedNodesManager>
4545
NativeAnimatedNodesManagerProvider::getOrCreate(
4646
jsi::Runtime& runtime,
4747
std::shared_ptr<CallInvoker> jsInvoker) {
48-
if (nativeAnimatedNodesManager_ == nullptr) {
49-
auto* uiManager = &UIManagerBinding::getBinding(runtime)->getUIManager();
48+
if (nativeAnimatedNodesManager_ != nullptr) {
49+
return nativeAnimatedNodesManager_;
50+
}
51+
52+
auto* uiManager = &UIManagerBinding::getBinding(runtime)->getUIManager();
53+
54+
if (!ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
55+
// === PATH 1: Legacy Backend (useSharedAnimatedBackend = false) ===
56+
// Uses the architecture with MergedValueDispatcher and
57+
// AnimatedMountingOverrideDelegate
5058

5159
mergedValueDispatcher_ = std::make_unique<MergedValueDispatcher>(
5260
[jsInvoker](std::function<void()>&& func) {
@@ -84,78 +92,78 @@ NativeAnimatedNodesManagerProvider::getOrCreate(
8492
}
8593
};
8694

87-
if (ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
88-
auto animationBackend = uiManager->unstable_getAnimationBackend().lock();
89-
react_native_assert(
90-
animationBackend != nullptr && "animationBackend is nullptr");
91-
animationBackend->registerJSInvoker(jsInvoker);
92-
93-
nativeAnimatedNodesManager_ =
94-
std::make_shared<NativeAnimatedNodesManager>(animationBackend);
95-
} else {
96-
nativeAnimatedNodesManager_ =
97-
std::make_shared<NativeAnimatedNodesManager>(
98-
std::move(directManipulationCallback),
99-
std::move(fabricCommitCallback),
100-
std::move(resolvePlatformColor),
101-
std::move(startOnRenderCallback_),
102-
std::move(stopOnRenderCallback_),
103-
std::move(frameRateListenerCallback_));
104-
105-
nativeAnimatedDelegate_ =
106-
std::make_shared<UIManagerNativeAnimatedDelegateImpl>(
107-
nativeAnimatedNodesManager_);
108-
}
109-
110-
addEventEmitterListener(
111-
nativeAnimatedNodesManager_->getEventEmitterListener());
112-
113-
uiManager->addEventListener(
114-
std::make_shared<EventListener>(
115-
[eventEmitterListenerContainerWeak =
116-
std::weak_ptr<EventEmitterListenerContainer>(
117-
eventEmitterListenerContainer_)](
118-
const RawEvent& rawEvent) {
119-
const auto& eventTarget = rawEvent.eventTarget;
120-
const auto& eventPayload = rawEvent.eventPayload;
121-
if (eventTarget && eventPayload) {
122-
if (auto eventEmitterListenerContainer =
123-
eventEmitterListenerContainerWeak.lock();
124-
eventEmitterListenerContainer != nullptr) {
125-
return eventEmitterListenerContainer->willDispatchEvent(
126-
eventTarget->getTag(), rawEvent.type, *eventPayload);
127-
}
128-
}
129-
return false;
130-
}));
95+
nativeAnimatedNodesManager_ = std::make_shared<NativeAnimatedNodesManager>(
96+
std::move(directManipulationCallback),
97+
std::move(fabricCommitCallback),
98+
std::move(resolvePlatformColor),
99+
std::move(startOnRenderCallback_),
100+
std::move(stopOnRenderCallback_),
101+
std::move(frameRateListenerCallback_));
102+
103+
nativeAnimatedDelegate_ =
104+
std::make_shared<UIManagerNativeAnimatedDelegateImpl>(
105+
nativeAnimatedNodesManager_);
106+
107+
animatedMountingOverrideDelegate_ =
108+
std::make_shared<AnimatedMountingOverrideDelegate>(
109+
*nativeAnimatedNodesManager_, *scheduler);
110+
111+
// Register on existing surfaces
112+
uiManager->getShadowTreeRegistry().enumerate(
113+
[animatedMountingOverrideDelegate =
114+
std::weak_ptr<const AnimatedMountingOverrideDelegate>(
115+
animatedMountingOverrideDelegate_)](
116+
const ShadowTree& shadowTree, bool& /*stop*/) {
117+
shadowTree.getMountingCoordinator()->setMountingOverrideDelegate(
118+
animatedMountingOverrideDelegate);
119+
});
131120

132-
uiManager->setNativeAnimatedDelegate(nativeAnimatedDelegate_);
121+
// Register on surfaces started in the future
122+
uiManager->setOnSurfaceStartCallback(
123+
[animatedMountingOverrideDelegate =
124+
std::weak_ptr<const AnimatedMountingOverrideDelegate>(
125+
animatedMountingOverrideDelegate_)](
126+
const ShadowTree& shadowTree) {
127+
shadowTree.getMountingCoordinator()->setMountingOverrideDelegate(
128+
animatedMountingOverrideDelegate);
129+
});
133130

134-
if (!ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
135-
animatedMountingOverrideDelegate_ =
136-
std::make_shared<AnimatedMountingOverrideDelegate>(
137-
*nativeAnimatedNodesManager_, *scheduler);
138-
139-
// Register on existing surfaces
140-
uiManager->getShadowTreeRegistry().enumerate(
141-
[animatedMountingOverrideDelegate =
142-
std::weak_ptr<const AnimatedMountingOverrideDelegate>(
143-
animatedMountingOverrideDelegate_)](
144-
const ShadowTree& shadowTree, bool& /*stop*/) {
145-
shadowTree.getMountingCoordinator()->setMountingOverrideDelegate(
146-
animatedMountingOverrideDelegate);
147-
});
148-
// Register on surfaces started in the future
149-
uiManager->setOnSurfaceStartCallback(
150-
[animatedMountingOverrideDelegate =
151-
std::weak_ptr<const AnimatedMountingOverrideDelegate>(
152-
animatedMountingOverrideDelegate_)](
153-
const ShadowTree& shadowTree) {
154-
shadowTree.getMountingCoordinator()->setMountingOverrideDelegate(
155-
animatedMountingOverrideDelegate);
156-
});
157-
}
131+
uiManager->setNativeAnimatedDelegate(nativeAnimatedDelegate_);
132+
} else {
133+
// === PATH 2: Shared AnimationBackend (useSharedAnimatedBackend = true) ===
134+
// Uses the shared AnimationBackend from UIManager. The backend handles all
135+
// animation commits and platform integration internally.
136+
137+
auto animationBackend = uiManager->unstable_getAnimationBackend().lock();
138+
react_native_assert(
139+
animationBackend != nullptr && "animationBackend is nullptr");
140+
animationBackend->registerJSInvoker(jsInvoker);
141+
142+
nativeAnimatedNodesManager_ =
143+
std::make_shared<NativeAnimatedNodesManager>(animationBackend);
158144
}
145+
146+
addEventEmitterListener(
147+
nativeAnimatedNodesManager_->getEventEmitterListener());
148+
149+
uiManager->addEventListener(
150+
std::make_shared<EventListener>(
151+
[eventEmitterListenerContainerWeak =
152+
std::weak_ptr<EventEmitterListenerContainer>(
153+
eventEmitterListenerContainer_)](const RawEvent& rawEvent) {
154+
const auto& eventTarget = rawEvent.eventTarget;
155+
const auto& eventPayload = rawEvent.eventPayload;
156+
if (eventTarget && eventPayload) {
157+
if (auto eventEmitterListenerContainer =
158+
eventEmitterListenerContainerWeak.lock();
159+
eventEmitterListenerContainer != nullptr) {
160+
return eventEmitterListenerContainer->willDispatchEvent(
161+
eventTarget->getTag(), rawEvent.type, *eventPayload);
162+
}
163+
}
164+
return false;
165+
}));
166+
159167
return nativeAnimatedNodesManager_;
160168
}
161169

packages/react-native/ReactCxxPlatform/react/runtime/TurboModuleManager.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,19 @@ std::shared_ptr<TurboModule> TurboModuleManager::operator()(
6262
}
6363
}
6464

65+
if (animatedNodesManagerProvider_ != nullptr &&
66+
name == AnimatedModule::kModuleName) {
67+
// when animatedNodesManagerProvider_ is null, defer to default
68+
return std::make_shared<AnimatedModule>(
69+
jsInvoker_, animatedNodesManagerProvider_);
70+
}
71+
6572
if (auto turboModule =
6673
DefaultTurboModules::getTurboModule(name, jsInvoker_)) {
6774
return turboModule;
6875
}
6976

70-
if (name == AnimatedModule::kModuleName) {
71-
return std::make_shared<AnimatedModule>(
72-
jsInvoker_, animatedNodesManagerProvider_);
73-
} else if (name == AppStateModule::kModuleName) {
77+
if (name == AppStateModule::kModuleName) {
7478
return std::make_shared<AppStateModule>(jsInvoker_);
7579
} else if (name == DeviceInfoModule::kModuleName) {
7680
return std::make_shared<DeviceInfoModule>(jsInvoker_);

private/react-native-fantom/tester/src/TesterAppDelegate.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,7 @@ TesterAppDelegate::TesterAppDelegate(
112112

113113
std::shared_ptr<NativeAnimatedNodesManagerProvider> provider;
114114

115-
if (ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
116-
provider = std::make_shared<NativeAnimatedNodesManagerProvider>();
117-
} else {
115+
if (!ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
118116
provider = std::make_shared<NativeAnimatedNodesManagerProvider>(
119117
[this](std::function<void()>&& onRender, bool /*isAsync*/) {
120118
onAnimationRender_ = std::move(onRender);

0 commit comments

Comments
 (0)