From 12deb38cbade6e2469925c249d89719d11968592 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Tue, 28 Oct 2025 16:29:56 +0100 Subject: [PATCH 01/18] run danger --- .github/workflows/danger-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/danger-pr.yml b/.github/workflows/danger-pr.yml index cf28b788105a..06daf7ee8378 100644 --- a/.github/workflows/danger-pr.yml +++ b/.github/workflows/danger-pr.yml @@ -15,7 +15,7 @@ permissions: jobs: danger: runs-on: ubuntu-latest - if: github.repository == 'facebook/react-native' + if: github.repository == 'coado/react-native' steps: - uses: actions/checkout@v4 - name: Setup Node.js From 085854dade519ca8052f86edfe42f233ce3f547c Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Tue, 28 Oct 2025 16:51:45 +0100 Subject: [PATCH 02/18] changing API --- packages/react-native/ReactNativeApi.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 2ac82083cbfe..402e13c84392 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -36,7 +36,7 @@ declare const $$AnimatedImage: AnimatedComponentType< React.ComponentRef > declare const $$AnimatedImplementation: { - add: typeof addImpl + // add: typeof addImpl attachNativeEvent: typeof attachNativeEventImpl Color: typeof AnimatedColor_default createAnimatedComponent: typeof createAnimatedComponent_default From 2c2c7be5a4028a659212866a65630763543294a5 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Tue, 28 Oct 2025 16:52:53 +0100 Subject: [PATCH 03/18] change API --- packages/react-native/ReactNativeApi.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 402e13c84392..2ac82083cbfe 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -36,7 +36,7 @@ declare const $$AnimatedImage: AnimatedComponentType< React.ComponentRef > declare const $$AnimatedImplementation: { - // add: typeof addImpl + add: typeof addImpl attachNativeEvent: typeof attachNativeEventImpl Color: typeof AnimatedColor_default createAnimatedComponent: typeof createAnimatedComponent_default From 6e1028be5458bd936623c0a40efbe15ebf14b3e3 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Tue, 28 Oct 2025 17:19:39 +0100 Subject: [PATCH 04/18] snapshot output --- private/react-native-bots/dangerfile.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/private/react-native-bots/dangerfile.js b/private/react-native-bots/dangerfile.js index 1bff20819a97..005ff55d67d7 100644 --- a/private/react-native-bots/dangerfile.js +++ b/private/react-native-bots/dangerfile.js @@ -39,6 +39,9 @@ const snapshot_output = JSON.parse( 'utf8', ), ); + +console.log('Snapshot output:', snapshot_output); + if (snapshot_output && snapshot_output.result !== 'NON_BREAKING') { const title = ':exclamation: JavaScript API change detected'; const idea = From 5db6f3cff8374623ca7055e88cad62861227b8c6 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Mon, 3 Nov 2025 10:36:36 +0100 Subject: [PATCH 05/18] changing api --- packages/react-native/ReactNativeApi.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 2ac82083cbfe..ff992b3137d8 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -6115,7 +6115,7 @@ export { SectionListData, // 119baf83 SectionListProps, // c9ac8e07 SectionListRenderItem, // 1fad0435 - SectionListRenderItemInfo, // 745e1992 + SectionListRenderItemInfo, // 745e1994 Separators, // 6a45f7e3 Settings, // 4282b0da Share, // e4591b32 From 074b2daee01580175e2e6c7958ea5c5ecd0e7818 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Mon, 3 Nov 2025 10:37:45 +0100 Subject: [PATCH 06/18] revert: --- packages/react-native/ReactNativeApi.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index ff992b3137d8..2ac82083cbfe 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -6115,7 +6115,7 @@ export { SectionListData, // 119baf83 SectionListProps, // c9ac8e07 SectionListRenderItem, // 1fad0435 - SectionListRenderItemInfo, // 745e1994 + SectionListRenderItemInfo, // 745e1992 Separators, // 6a45f7e3 Settings, // 4282b0da Share, // e4591b32 From f931c523caebde6da28bc4559e66ffc67957edb6 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Mon, 3 Nov 2025 10:38:20 +0100 Subject: [PATCH 07/18] api change --- packages/react-native/ReactNativeApi.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 2ac82083cbfe..073a1f2a9a1e 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -6109,7 +6109,7 @@ export { ScrollViewProps, // 27986ff5 ScrollViewPropsAndroid, // 84e2134b ScrollViewPropsIOS, // d83c9733 - ScrollViewScrollToOptions, // 3313411e + ScrollViewScrollToOptions, // 33134111 SectionBase, // b376bddc SectionList, // ff1193b2 SectionListData, // 119baf83 From adc4279fb37abdca35e776e3111a7ce5b1ebe730 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Mon, 3 Nov 2025 10:43:07 +0100 Subject: [PATCH 08/18] danger fix --- .../diff-js-api-breaking-changes/action.yml | 3 ++ private/react-native-bots/dangerfile.js | 32 ++++++++----------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.github/actions/diff-js-api-breaking-changes/action.yml b/.github/actions/diff-js-api-breaking-changes/action.yml index bc45b1b207aa..8dbd744916d9 100644 --- a/.github/actions/diff-js-api-breaking-changes/action.yml +++ b/.github/actions/diff-js-api-breaking-changes/action.yml @@ -17,6 +17,9 @@ runs: env: SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-breaking-changes run: | + # Check if the file was changed in this PR, if not, exit early without saving to the output.json + git diff --name-status | awk '{print $2}' | grep 'packages/react-native/ReactNativeApi.d.ts' || exit 0 + node ./scripts/js-api/diff-api-snapshot \ ${{ github.workspace }}/packages/react-native/ReactNativeApi.d.ts \ $SCRATCH_DIR/ReactNativeApi-after.d.ts \ diff --git a/private/react-native-bots/dangerfile.js b/private/react-native-bots/dangerfile.js index 005ff55d67d7..07a4a921e566 100644 --- a/private/react-native-bots/dangerfile.js +++ b/private/react-native-bots/dangerfile.js @@ -30,26 +30,22 @@ const isFromPhabricator = body_contains('differential revision:'); // Provides advice if a summary section is missing, or body is too short const includesSummary = body_contains('## summary', 'summary:'); -const snapshot_output = JSON.parse( - fs.readFileSync( - path.join( - process.env.RUNNER_TEMP, - 'diff-js-api-breaking-changes/output.json', - ), - 'utf8', - ), +const snapshot_path = path.join( + process.env.RUNNER_TEMP, + 'diff-js-api-breaking-changes/output.json', ); -console.log('Snapshot output:', snapshot_output); - -if (snapshot_output && snapshot_output.result !== 'NON_BREAKING') { - const title = ':exclamation: JavaScript API change detected'; - const idea = - 'This PR commits an update to ReactNativeApi.d.ts, indicating a change to React Native's public JavaScript API. ' + - 'Please include a clear changelog message. ' + - 'This change will be subject to extra review.\n\n' + - `This change was flagged as: ${snapshot_output.result}`; - warn(`${title} - ${idea}`); +if (fs.existsSync(snapshot_path)) { + const snapshot_output = JSON.parse(fs.readFileSync(snapshot_path, 'utf8')); + if (snapshot_output && snapshot_output.result !== 'NON_BREAKING') { + const title = ':exclamation: JavaScript API change detected'; + const idea = + 'This PR commits an update to ReactNativeApi.d.ts, indicating a change to React Native's public JavaScript API. ' + + 'Please include a clear changelog message. ' + + 'This change will be subject to extra review.\n\n' + + `This change was flagged as: ${snapshot_output.result}`; + warn(`${title} - ${idea}`); + } } const hasNoUsefulBody = From b5d5f890a86e2ec7c2231426383b7efb0b66f6a0 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Mon, 3 Nov 2025 10:53:16 +0100 Subject: [PATCH 09/18] update danger --- .github/actions/diff-js-api-breaking-changes/action.yml | 2 +- private/react-native-bots/dangerfile.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/actions/diff-js-api-breaking-changes/action.yml b/.github/actions/diff-js-api-breaking-changes/action.yml index 8dbd744916d9..182f323d6b61 100644 --- a/.github/actions/diff-js-api-breaking-changes/action.yml +++ b/.github/actions/diff-js-api-breaking-changes/action.yml @@ -18,7 +18,7 @@ runs: SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-breaking-changes run: | # Check if the file was changed in this PR, if not, exit early without saving to the output.json - git diff --name-status | awk '{print $2}' | grep 'packages/react-native/ReactNativeApi.d.ts' || exit 0 + git diff --name-status | awk '{print $2}' | grep 'packages/react-native/ReactNativeApi.d.ts' || echo "ReactNativeApi.d.ts not found, exiting" && exit 0 node ./scripts/js-api/diff-api-snapshot \ ${{ github.workspace }}/packages/react-native/ReactNativeApi.d.ts \ diff --git a/private/react-native-bots/dangerfile.js b/private/react-native-bots/dangerfile.js index 07a4a921e566..7ed51328e3d3 100644 --- a/private/react-native-bots/dangerfile.js +++ b/private/react-native-bots/dangerfile.js @@ -36,7 +36,9 @@ const snapshot_path = path.join( ); if (fs.existsSync(snapshot_path)) { + console.log('JS API snapshot found, checking for changes...'); const snapshot_output = JSON.parse(fs.readFileSync(snapshot_path, 'utf8')); + console.log('Snapshot output:', snapshot_output); if (snapshot_output && snapshot_output.result !== 'NON_BREAKING') { const title = ':exclamation: JavaScript API change detected'; const idea = @@ -46,6 +48,8 @@ if (fs.existsSync(snapshot_path)) { `This change was flagged as: ${snapshot_output.result}`; warn(`${title} - ${idea}`); } +} else { + console.log('No JS API snapshot found, skipping JS API change check.'); } const hasNoUsefulBody = From d070c8bc553564f5a9c0b1edbc37cb0e847d1c45 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Mon, 3 Nov 2025 10:58:33 +0100 Subject: [PATCH 10/18] logs --- .github/actions/diff-js-api-breaking-changes/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/diff-js-api-breaking-changes/action.yml b/.github/actions/diff-js-api-breaking-changes/action.yml index 182f323d6b61..c3b1ae212480 100644 --- a/.github/actions/diff-js-api-breaking-changes/action.yml +++ b/.github/actions/diff-js-api-breaking-changes/action.yml @@ -18,6 +18,8 @@ runs: SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-breaking-changes run: | # Check if the file was changed in this PR, if not, exit early without saving to the output.json + git diff --name-status + git diff --name-status | awk '{print $2}' git diff --name-status | awk '{print $2}' | grep 'packages/react-native/ReactNativeApi.d.ts' || echo "ReactNativeApi.d.ts not found, exiting" && exit 0 node ./scripts/js-api/diff-api-snapshot \ From 52d2db34267ef4b1dd91a99a78f01dcfcfd40160 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Wed, 5 Nov 2025 16:30:11 +0100 Subject: [PATCH 11/18] cxx animated config --- .../React-RCTAnimatedModuleProvider.podspec | 62 +++++++++++++++++++ .../ReactNativeFeatureFlagsDefaults.h | 2 +- .../ios/ReactCommon/RCTTurboModuleManager.mm | 12 ++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 packages/react-native/ReactApple/RCTAnimatedModuleProvider/React-RCTAnimatedModuleProvider.podspec diff --git a/packages/react-native/ReactApple/RCTAnimatedModuleProvider/React-RCTAnimatedModuleProvider.podspec b/packages/react-native/ReactApple/RCTAnimatedModuleProvider/React-RCTAnimatedModuleProvider.podspec new file mode 100644 index 000000000000..3e6e68539a3a --- /dev/null +++ b/packages/react-native/ReactApple/RCTAnimatedModuleProvider/React-RCTAnimatedModuleProvider.podspec @@ -0,0 +1,62 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json"))) +version = package['version'] + +source = { :git => 'https://github.com/facebook/react-native.git' } +if version == '1000.0.0' + # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. + source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") +else + source[:tag] = "v#{version}" +end + +header_search_paths = [ + "\"$(PODS_TARGET_SRCROOT)/../../ReactCommon\"", + "\"$(PODS_ROOT)/Headers/Public/React-Core\"", + "\"$(PODS_ROOT)/Headers/Private/Yoga\"" +] + +Pod::Spec.new do |s| + s.name = "React-RCTAnimatedModuleProvider" + s.version = version + s.summary = "Animated TurboModule provider for iOS (bridgeless)" + s.homepage = "https://reactnative.dev/" + s.license = package["license"] + s.author = "Meta Platforms, Inc. and its affiliates" + s.platforms = min_supported_versions + s.source = source + s.source_files = podspec_sources("*.{m,mm}", "**/*.h") + s.public_header_files = "*.h" + s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs" + s.header_dir = "RCTAnimatedModuleProvider" + s.pod_target_xcconfig = { + "USE_HEADERMAP" => "YES", + "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(), + # "HEADER_SEARCH_PATHS" => '$(inherited) "$(PODS_ROOT)/Headers/Public/Yoga" "$(PODS_ROOT)/Headers/Private/Yoga"' + "HEADER_SEARCH_PATHS" => header_search_paths.join(' ') + } + +# resolve_use_frameworks(s, header_mappings_dir: "./", module_name: "React_RCTAnimatedModuleProvider") + resolve_use_frameworks(s, header_mappings_dir: "./") + + + # Dependencies needed for TurboModule types and feature flags access + s.dependency "React-Core" + s.dependency "React-jsi" + add_dependency(s, "ReactCommon", :subspec => "turbomodule/core") + add_dependency(s, "React-callinvoker") + add_dependency(s, "React-featureflags") + add_dependency(s, "React-Fabric", :subspec => "animated", :additional_framework_paths => ["react/renderer/animated"]) + add_dependency(s, "Yoga") + + add_rn_third_party_dependencies(s) + add_rncore_dependency(s) +end + + diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index d3e884a76728..d6fd4cdf592d 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -36,7 +36,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { } bool cxxNativeAnimatedEnabled() override { - return false; + return true; } bool cxxNativeAnimatedRemoveJsSync() override { diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm index ac4c5c5c2a0f..ccd64bc30209 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm @@ -15,6 +15,7 @@ #import +#import #import #import #import @@ -219,6 +220,7 @@ @implementation RCTTurboModuleManager { RCTDevMenuConfigurationDecorator *_devMenuConfigurationDecorator; dispatch_queue_t _sharedModuleQueue; + RCTAnimatedModuleProvider *animatedModuleProvider; } - (instancetype)initWithBridge:(RCTBridge *)bridge @@ -260,6 +262,10 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge _legacyEagerlyRegisteredModuleClasses = legacyEagerlyRegisteredModuleClasses; } + if (ReactNativeFeatureFlags::cxxNativeAnimatedEnabled()) { + animatedModuleProvider = [RCTAnimatedModuleProvider new]; + } + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(bridgeWillInvalidateModules:) name:RCTBridgeWillInvalidateModulesNotification @@ -356,6 +362,12 @@ - (instancetype)initWithBridgeProxy:(RCTBridgeProxy *)bridgeProxy return turboModule; } + if (ReactNativeFeatureFlags::cxxNativeAnimatedEnabled()) { + if (auto module = [animatedModuleProvider getTurboModule:moduleName jsInvoker:_jsInvoker]) { + return module; + } + } + /** * Step 2: Look for platform-specific modules. */ From 89920ce24fdb6d8af0ee903a7107b32c7f321a7a Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Wed, 5 Nov 2025 17:13:55 +0100 Subject: [PATCH 12/18] include RCTAnimatedModuleProvider pod --- packages/react-native/scripts/react_native_pods.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-native/scripts/react_native_pods.rb b/packages/react-native/scripts/react_native_pods.rb index 72c267389c39..ce347e52a8e2 100644 --- a/packages/react-native/scripts/react_native_pods.rb +++ b/packages/react-native/scripts/react_native_pods.rb @@ -153,6 +153,8 @@ def use_react_native! ( pod 'React-jsi', :path => "#{prefix}/ReactCommon/jsi" pod 'RCTSwiftUI', :path => "#{prefix}/ReactApple/RCTSwiftUI" pod 'RCTSwiftUIWrapper', :path => "#{prefix}/ReactApple/RCTSwiftUIWrapper" + # Provide Animated TurboModule for iOS bridgeless via Objective-C++ provider + pod 'React-RCTAnimatedModuleProvider', :path => "#{prefix}/ReactApple/RCTAnimatedModuleProvider" if hermes_enabled setup_hermes!(:react_native_path => prefix) From 8071a05ff337ad413889e8ec9417a046f9ebb5eb Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Fri, 7 Nov 2025 12:13:12 +0100 Subject: [PATCH 13/18] enable RN_USE_ANIMATION_BACKEND --- packages/react-native/ReactCommon/React-Fabric.podspec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/react-native/ReactCommon/React-Fabric.podspec b/packages/react-native/ReactCommon/React-Fabric.podspec index e19c74b1138c..cdd5bd440e05 100644 --- a/packages/react-native/ReactCommon/React-Fabric.podspec +++ b/packages/react-native/ReactCommon/React-Fabric.podspec @@ -59,6 +59,9 @@ Pod::Spec.new do |s| ss.source_files = podspec_sources("react/renderer/animated/**/*.{m,mm,cpp,h}", "react/renderer/animated/**/*.{h}") ss.exclude_files = "react/renderer/animated/tests" ss.header_dir = "react/renderer/animated" + ss.pod_target_xcconfig = { + "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) RN_USE_ANIMATION_BACKEND=1", + } end s.subspec "animations" do |ss| From dd5adf447e9cf22caa68799041f8fb2c94708c18 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Wed, 12 Nov 2025 18:04:07 +0100 Subject: [PATCH 14/18] Load AnimatedModule on Android --- .../react/animated/AnimatedCxxReactPackage.kt | 26 +++++++++ .../soloader/OpenSourceMergedSoMapping.kt | 4 ++ .../ReactAndroid/src/main/jni/CMakeLists.txt | 9 ++++ .../animated/AnimatedCxxReactPackage.cpp | 52 ++++++++++++++++++ .../react/animated/AnimatedCxxReactPackage.h | 54 +++++++++++++++++++ .../main/jni/react/animated/CMakeLists.txt | 33 ++++++++++++ .../src/main/jni/react/animated/OnLoad.cpp | 15 ++++++ 7 files changed, 193 insertions(+) create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedCxxReactPackage.kt create mode 100644 packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp create mode 100644 packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.h create mode 100644 packages/react-native/ReactAndroid/src/main/jni/react/animated/CMakeLists.txt create mode 100644 packages/react-native/ReactAndroid/src/main/jni/react/animated/OnLoad.cpp diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedCxxReactPackage.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedCxxReactPackage.kt new file mode 100644 index 000000000000..658a5a8ba1e3 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedCxxReactPackage.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + package com.facebook.react.animated + import com.facebook.jni.HybridData + import com.facebook.react.bridge.ReactApplicationContext + import com.facebook.react.runtime.cxxreactpackage.CxxReactPackage + import com.facebook.soloader.SoLoader + + public class AnimatedCxxReactPackage(public val context: ReactApplicationContext) : CxxReactPackage(null) { + init { + mHybridData = initHybrid() + } + + private external fun initHybrid(): HybridData + + public companion object { + init { + SoLoader.loadLibrary("react_animatedjni") + } + } + } \ No newline at end of file diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/soloader/OpenSourceMergedSoMapping.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/soloader/OpenSourceMergedSoMapping.kt index c8ba2b2190c4..c17f6f180874 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/soloader/OpenSourceMergedSoMapping.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/soloader/OpenSourceMergedSoMapping.kt @@ -26,6 +26,7 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping { "jsinspector", "mapbufferjni", "react_devsupportjni", + "react_animatedjni", "react_featureflagsjni", "react_newarchdefaults", "reactnativeblob", @@ -55,6 +56,7 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping { "jsinspector" -> libjsinspector_so() "mapbufferjni" -> libmapbufferjni_so() "react_devsupportjni" -> libreact_devsupportjni_so() + "react_animatedjni" -> libreact_animatedjni_so() "react_featureflagsjni" -> libreact_featureflagsjni_so() "react_newarchdefaults" -> libreact_newarchdefaults_so() "reactnative" -> libreactnative_so() @@ -84,6 +86,8 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping { public external fun libreact_devsupportjni_so(): Int + public external fun libreact_animatedjni_so(): Int + public external fun libreact_featureflagsjni_so(): Int public external fun libreact_newarchdefaults_so(): Int diff --git a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt index 04676e762177..dea8a2a51f58 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt @@ -83,6 +83,8 @@ add_react_common_subdir(react/featureflags) add_react_common_subdir(react/performance/cdpmetrics) add_react_common_subdir(react/performance/timeline) add_react_common_subdir(react/renderer/animations) +add_react_common_subdir(react/renderer/animated) +add_react_common_subdir(react/renderer/animationbackend) add_react_common_subdir(react/renderer/attributedstring) add_react_common_subdir(react/renderer/componentregistry) add_react_common_subdir(react/renderer/mounting) @@ -153,6 +155,7 @@ add_react_android_subdir(src/main/jni/react/runtime/cxxreactpackage) add_react_android_subdir(src/main/jni/react/runtime/jni) add_react_android_subdir(src/main/jni/react/runtime/hermes/jni) add_react_android_subdir(src/main/jni/react/devsupport) +add_react_android_subdir(src/main/jni/react/animated) # SoMerging Utils include(${REACT_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/SoMerging-utils.cmake) @@ -198,6 +201,9 @@ add_library(reactnative $ $ $ + $ + $ + $ $ $ $ @@ -289,6 +295,9 @@ target_include_directories(reactnative $ $ $ + $ + $ + $ $ $ $ diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp new file mode 100644 index 000000000000..9ff889601e81 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#include "AnimatedCxxReactPackage.h" +#include +#include + +namespace facebook::react { + +AnimatedCxxReactPackage::AnimatedCxxReactPackage( + jni::alias_ref jobj) {} + +jni::local_ref +AnimatedCxxReactPackage::initHybrid( + jni::alias_ref jobj) { + return makeCxxInstance(jobj); +} + +void AnimatedCxxReactPackage::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", AnimatedCxxReactPackage::initHybrid), + }); +} + +std::shared_ptr AnimatedCxxReactPackage::getModule( + const std::string& moduleName, + const std::shared_ptr& jsInvoker) { + if (moduleName == "NativeAnimatedModule") { + return std::make_shared( + jsInvoker, nullptr /* nodesManagerProvider */ + ); + } + + return nullptr; +} + +std::shared_ptr +AnimatedCxxReactPackage::getNativeAnimatedNodesManagerProvider() { + if (auto provider = nativeAnimatedNodesManagerProvider_.lock()) { + return provider; + } + + nativeAnimatedNodesManagerProvider_ = + std::make_shared( + [](std::function, bool) {}, [](bool) {}); + return nativeAnimatedNodesManagerProvider_.lock(); +} + +} // namespace facebook::react \ No newline at end of file diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.h b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.h new file mode 100644 index 000000000000..d14e30d583ae --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#include +#include +#include "AnimatedCxxReactPackage.h" + +namespace facebook::react { + +AnimatedCxxReactPackage::AnimatedCxxReactPackage( + jni::alias_ref jobj) {} + +jni::local_ref +AnimatedCxxReactPackage::initHybrid( + jni::alias_ref jobj) { + return makeCxxInstance(jobj); +} + +void AnimatedCxxReactPackage::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", AnimatedCxxReactPackage::initHybrid), + }); +} + +std::shared_ptr AnimatedCxxReactPackage::getModule( + const std::string& moduleName, + const std::shared_ptr& jsInvoker) { + if (moduleName == "NativeAnimatedModule") { + auto provider = getNativeAnimatedNodesManagerProvider(); + return std::make_shared( + jsInvoker, provider /* nodesManagerProvider */ + ); + } + + return nullptr; +} + +std::shared_ptr +AnimatedCxxReactPackage::getNativeAnimatedNodesManagerProvider() { + if (auto provider = nativeAnimatedNodesManagerProvider_.lock()) { + return provider; + } + + auto nativeAnimatedNodesManagerProvider = + std::make_shared(nullptr, nullptr); + + nativeAnimatedNodesManagerProvider_ = nativeAnimatedNodesManagerProvider; + return nativeAnimatedNodesManagerProvider; +} + +} // namespace facebook::react \ No newline at end of file diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/animated/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/react/animated/CMakeLists.txt new file mode 100644 index 000000000000..e64d3c3b9493 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/animated/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +# include(${REACT_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/SoMerging-utils.cmake) +include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake) + +file(GLOB react_animatedjni_SRC CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) + +add_library(react_animatedjni OBJECT ${react_animatedjni_SRC}) + +target_include_directories(react_animatedjni PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +# target_merge_so(react_animatedjni) + +target_link_libraries(react_animatedjni + fbjni + react_codegen_rncore + react_debug + react_renderer_core + react_renderer_graphics + react_renderer_mounting + react_renderer_uimanager + react_renderer_scheduler + react_renderer_animationbackend + react_cxxreactpackage + glog + folly_runtime) + +target_compile_reactnative_options(react_animatedjni PRIVATE) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/animated/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/animated/OnLoad.cpp new file mode 100644 index 000000000000..a9358dc75241 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/animated/OnLoad.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include "AnimatedCxxReactPackage.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*reserved*/) { + return facebook::jni::initialize( + vm, [] { facebook::react::AnimatedCxxReactPackage::registerNatives(); }); +} \ No newline at end of file From 88bf11d8a04f67a7b3673c931ec83d3b2df108fc Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Wed, 12 Nov 2025 18:07:34 +0100 Subject: [PATCH 15/18] AnimatedCxxReactPackage --- .../animated/AnimatedCxxReactPackage.cpp | 11 +-- .../react/animated/AnimatedCxxReactPackage.h | 80 ++++++++----------- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp index 9ff889601e81..ea4b67b99c9e 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp @@ -30,8 +30,7 @@ std::shared_ptr AnimatedCxxReactPackage::getModule( const std::shared_ptr& jsInvoker) { if (moduleName == "NativeAnimatedModule") { return std::make_shared( - jsInvoker, nullptr /* nodesManagerProvider */ - ); + jsInvoker, getNativeAnimatedNodesManagerProvider()); } return nullptr; @@ -43,10 +42,12 @@ AnimatedCxxReactPackage::getNativeAnimatedNodesManagerProvider() { return provider; } - nativeAnimatedNodesManagerProvider_ = + auto nativeAnimatedNodesManagerProvider = std::make_shared( - [](std::function, bool) {}, [](bool) {}); - return nativeAnimatedNodesManagerProvider_.lock(); + [](std::function&& cb, bool) { cb(); }, [](bool) {}); + + nativeAnimatedNodesManagerProvider_ = nativeAnimatedNodesManagerProvider; + return nativeAnimatedNodesManagerProvider; } } // namespace facebook::react \ No newline at end of file diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.h b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.h index d14e30d583ae..61b5eff3af7d 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.h @@ -4,51 +4,41 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -#include -#include -#include "AnimatedCxxReactPackage.h" + +#pragma once + +#include +#include +#include namespace facebook::react { +class AnimatedCxxReactPackage + : public jni::HybridClass { + public: + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/animated/AnimatedCxxReactPackage;"; + + static jni::local_ref initHybrid( + jni::alias_ref + jobj); + + static void registerNatives(); + + AnimatedCxxReactPackage( + jni::alias_ref jobj); + + std::shared_ptr getModule( + const std::string& moduleName, + const std::shared_ptr& jsInvoker) override; + + private: + std::weak_ptr + nativeAnimatedNodesManagerProvider_; + + std::shared_ptr + getNativeAnimatedNodesManagerProvider(); -AnimatedCxxReactPackage::AnimatedCxxReactPackage( - jni::alias_ref jobj) {} - -jni::local_ref -AnimatedCxxReactPackage::initHybrid( - jni::alias_ref jobj) { - return makeCxxInstance(jobj); -} - -void AnimatedCxxReactPackage::registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", AnimatedCxxReactPackage::initHybrid), - }); -} - -std::shared_ptr AnimatedCxxReactPackage::getModule( - const std::string& moduleName, - const std::shared_ptr& jsInvoker) { - if (moduleName == "NativeAnimatedModule") { - auto provider = getNativeAnimatedNodesManagerProvider(); - return std::make_shared( - jsInvoker, provider /* nodesManagerProvider */ - ); - } - - return nullptr; -} - -std::shared_ptr -AnimatedCxxReactPackage::getNativeAnimatedNodesManagerProvider() { - if (auto provider = nativeAnimatedNodesManagerProvider_.lock()) { - return provider; - } - - auto nativeAnimatedNodesManagerProvider = - std::make_shared(nullptr, nullptr); - - nativeAnimatedNodesManagerProvider_ = nativeAnimatedNodesManagerProvider; - return nativeAnimatedNodesManagerProvider; -} - -} // namespace facebook::react \ No newline at end of file + friend HybridBase; + using HybridBase::HybridBase; +}; +} // namespace facebook::react From e10aeffbd762fe76627e17dcba02267acbe1b0a9 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Wed, 12 Nov 2025 18:18:14 +0100 Subject: [PATCH 16/18] enable cxxNativeAnimatedEnabled kotlin --- .../internal/featureflags/ReactNativeFeatureFlagsDefaults.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index 3eb6dec1a899..ddf478d38f4e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -27,7 +27,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun cdpInteractionMetricsEnabled(): Boolean = false - override fun cxxNativeAnimatedEnabled(): Boolean = false + override fun cxxNativeAnimatedEnabled(): Boolean = true override fun cxxNativeAnimatedRemoveJsSync(): Boolean = false From 8e51d0db3c3ed6f275865f67385218a21aab5e06 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Wed, 12 Nov 2025 18:20:49 +0100 Subject: [PATCH 17/18] clean nativeAnimatedNodesManagerProvider --- .../src/main/jni/react/animated/AnimatedCxxReactPackage.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp index ea4b67b99c9e..fa4c0d3b848a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/animated/AnimatedCxxReactPackage.cpp @@ -43,8 +43,7 @@ AnimatedCxxReactPackage::getNativeAnimatedNodesManagerProvider() { } auto nativeAnimatedNodesManagerProvider = - std::make_shared( - [](std::function&& cb, bool) { cb(); }, [](bool) {}); + std::make_shared(nullptr, nullptr); nativeAnimatedNodesManagerProvider_ = nativeAnimatedNodesManagerProvider; return nativeAnimatedNodesManagerProvider; From eaab11b7bc6f8cf4aeafb7b776f149446aa195b9 Mon Sep 17 00:00:00 2001 From: Dawid Malecki Date: Fri, 14 Nov 2025 10:21:39 +0100 Subject: [PATCH 18/18] register cxx package --- .../main/java/com/facebook/react/defaults/DefaultReactHost.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt index 5aae109d5819..bd2a50c1d447 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt @@ -13,6 +13,7 @@ import android.content.Context import com.facebook.react.ReactHost import com.facebook.react.ReactNativeHost import com.facebook.react.ReactPackage +import com.facebook.react.animated.AnimatedCxxReactPackage import com.facebook.react.bridge.JSBundleLoader import com.facebook.react.bridge.ReactContext import com.facebook.react.common.annotations.UnstableReactNativeAPI @@ -85,6 +86,7 @@ public object DefaultReactHost { } val defaultTmmDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder() cxxReactPackageProviders.forEach { defaultTmmDelegateBuilder.addCxxReactPackage(it) } + defaultTmmDelegateBuilder.addCxxReactPackage { context -> AnimatedCxxReactPackage(context) } val defaultReactHostDelegate = DefaultReactHostDelegate( jsMainModulePath = jsMainModulePath,