software-mansion / react-native-reanimated

React Native's Animated library reimplemented
https://docs.swmansion.com/react-native-reanimated/
MIT License
8.61k stars 1.26k forks source link

Shared Element transition does not work after adding @react-native-firebase on iOS #4966

Open incode-mike-bytenko opened 10 months ago

incode-mike-bytenko commented 10 months ago

Description

took the problem from here https://github.com/software-mansion/react-native-reanimated/discussions/4691 but also just have the same.

Steps to reproduce

  1. To repro just setup basic project with transition (like in reanimated Examples)
  2. After that setup firebase via their instructions.

Snack or a link to a repository

https://github.com/software-mansion/react-native-reanimated/blob/4cba573aad640db1e8912455f1877fbab815f0d3/app/src/examples/SharedElementTransitions/ProgressTransition.tsx

Reanimated version

3.4.1

React Native version

0.72.3

Platforms

iOS

JavaScript runtime

Hermes

Workflow

React Native (without Expo)

Architecture

Paper (Old Architecture)

Build type

Debug mode

Device

iOS simulator

Device model

any

Acknowledgements

Yes

github-actions[bot] commented 10 months ago

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

piaskowyk commented 10 months ago

Hey 👋 Which version of rn-screens do you have?

brandtnewlabs commented 10 months ago

Interesting observation! I just tried to get shared element transitions working with the latest reanimated and latest react-navigation, but it doesn't work. I've also got Firebase integrated but don't know if it's related. However, I always get a warning like [Reanimated] Duplicate shared tag "tag" on the same screen even with the basic examples for documentation.

selven commented 9 months ago

I believe it's use_frameworks that breaks it not necessarily just firebase. Related: https://github.com/software-mansion/react-native-reanimated/issues/4337

rockstar0711 commented 8 months ago

Indeed, I tried the same code base from the React Navigation documentation in both the Firebase/Flipper-setup project and the non-Firebase project. It works well in the non-Firebase setup project, but not in the Firebase project, with a warning log of [Reanimated] Duplicate shared tag "tagName" on the same screen. When will there be an update for this problem? dear @tjzel

tjzel commented 8 months ago

@rockstar0711 I've been sick lately and got a lot of work that piled up. I'll try to get into it eventually.

rockstar0711 commented 8 months ago

Oh, Sorry to hear about that. I hope that you get better soon. Thank you for your hard work! Cheers! 👍💪

julian-gargicevich commented 8 months ago

Upvoting this, having the same issue

tjzel commented 8 months ago

I finally had some time to dig into it, and here are the results.

What

The problem is not with Firebase itself, but the Podfile option it requires for the installation, as you have mentioned:

use_frameworks! :linkage => :static

Adding this line changes how linking is made and because of that the macro defined here resolves to false.

This macro is a simple check if the user has react-native-screens installed (the header is accessible). If yes, then we use actual Shared Element Transitions implementation. If not, then we load a mock. So in this case, we incorrectly use the mock. "Duplicate shared tag" error happening here is just a coincidence - it doesn't have a mock (but it should have).

From what I understand, this is happening because react-native-screens is not a dependency of Reanimated, and using dynamic workflows means it's unavailable (unaccessible) at compile-time, even though static linking is on.

Solution

For the time being, I've found a workaround for it. All you need to do is to add the following to your Podfile:

pre_install do |installer|
  installer.pod_targets.each do |pod|
    if pod.name.eql?('RNScreens')
      def pod.build_type
        Pod::BuildType.static_library
      end
    end
  end
end

This will make RNScreens a static library instead of a dynamic workflow and from my testing everything was working fine.

Notes

Unfortunately, we haven't yet found an elegant solution that wouldn't require additional input from the user (adding to Podfile). By elegant, I mean a way to find if react-native-screens is installed without digging through node_modules with some scripts or else. If someone has some experience with this kind of things, I'd be very glad to read some suggestions.

I will keep the issue open till this kind of solution is found (or we gave up).

brandtnewlabs commented 8 months ago

Thanks a lot for looking into this, @tjzel! I just added your code snippet to my Podfile and noticed you forgot an end in the last line. After updating the Podfile and running pod install I didn't get the shared transition running though. Maybe someone else can try it out in their app? @rockstar0711 ?

I followed instructions in this example https://reactnavigation.org/docs/shared-element-transitions/#minimal-example

My Podfile

require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
# Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
  'require.resolve(
    "react-native/scripts/react_native_pods.rb",
    {paths: [process.argv[1]]},
  )', __dir__]).strip

platform :ios, '13.0'
prepare_react_native_project!
flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled

linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
  Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
  use_frameworks! :linkage => linkage.to_sym
end

target 'weburn' do

  pre_install do |installer|
    installer.pod_targets.each do |pod|
      if pod.name.eql?('RNScreens')
        def pod.build_type
          Pod::BuildType.static_library
        end
      end
    end
  end

  use_expo_modules!
  post_integrate do |installer|
    begin
      expo_patch_react_imports!(installer)
    rescue => e
      Pod::UI.warn e
    end
  end
  config = use_native_modules!

  # Firebase: https://rnfirebase.io/#altering-cocoapods-to-use-frameworks
  use_frameworks! :linkage => :static
  $RNFirebaseAsStaticFramework = true

  # Flags change depending on the env values.
  flags = get_default_flags()

  use_react_native!(
    :path => config[:reactNativePath],
    # Hermes is now enabled by default. Disable by setting this flag to false.
    :hermes_enabled => flags[:hermes_enabled],
    :fabric_enabled => flags[:fabric_enabled],
    # Enables Flipper.
    #
    # Note that if you have use_frameworks! enabled, Flipper will not work and
    # you should disable the next line.
    # :flipper_configuration => flipper_config,
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )

  target 'weburnTests' do
    inherit! :complete
    # Pods for testing
  end

  post_install do |installer|
    # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
    react_native_post_install(
      installer,
      config[:reactNativePath],
      :mac_catalyst_enabled => false
    )
    __apply_Xcode_12_5_M1_post_install_workaround(installer)
  end
end
tjzel commented 8 months ago

@brandtnewww Thanks for noticing the missing end, I edited it 😅.

I used your Podfile with new RN App with all the required packages, using the example you linked, and everything was fine. The only thing I obviously had to change in the Podfile was:

diff ```diff diff --git a/ios/Podfile.old b/ios/Podfile index f2c4042..c35e833 100644 --- a/ios/Podfile.old +++ b/ios/Podfile @@ -16,7 +16,7 @@ if linkage != nil use_frameworks! :linkage => linkage.to_sym end -target 'weburn' do +target 'App' do pre_install do |installer| installer.pod_targets.each do |pod| @@ -59,11 +59,6 @@ target 'weburn' do :app_path => "#{Pod::Config.instance.installation_root}/.." ) - target 'weburnTests' do - inherit! :complete - # Pods for testing - end - post_install do |installer| # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 react_native_post_install( ```
GusttavoCastilho commented 7 months ago

@tjzel I have the same problem, can you help me ? I used your Podfile too

felippewick commented 7 months ago

For expo users:

I could solve it with @tjzel solution and turned it into an expo plugin gist

julian-gargicevich commented 7 months ago

For expo users:

I could solve it with @tjzel solution and turned it into an expo plugin gist

Legend!

tjzel commented 7 months ago

@GusttavoCastilho Could you provide some more info about the problem you are still encountering?

@felippewick That's awesome!

julian-gargicevich commented 4 months ago

For expo users:

I could solve it with @tjzel solution and turned it into an expo plugin gist

Is it still working for you? Getting an error when building on Expo 50

Error: [ios.dangerous]: withIosDangerousBaseMod: Failed to match " flags = get_default_flags()" in contents: require File.join(File.dirname(node --print "require.resolve('expo/package.json')"), "scripts/autolinking") require File.join(File.dirname(node --print "require.resolve('react-native/package.json')"), "scripts/react_native_pods")

peterjskaltsis commented 4 months ago

@julian-gargicevich, I got the above Expo Config plugin working by changing the anchor below to a line that is in my ios Podfile on Expo 50.

-    anchor: '  flags = get_default_flags()', // Seems the '...get_default_flags..' line isn't in the Podfile anymore(?).
+    anchor: '  post_install do |installer|',

Successfully seeing transitions now 🎉 (no patch-package etc required). Thank you @tjzel!

ahmadaIanazi commented 2 months ago

For Expo users who never installed Plugins before, here is how you do it.

You probably have app.json instead of app.config.js file.

  1. Create a file name called "app.config.js"
  2. Paste this code:
    
    const { withPlugins } = require('expo/config-plugins')
    const withReanimatedUseFrameworks = require('./withReanimatedUseFrameworks') // adjust the path if necessary

module.exports = ({ config }) => { return withPlugins( { ...config, expo: { ...// the rest of your app.json }, }, [withReanimatedUseFrameworks] ) }


3. Add the content of your app.json into the commented area and dont forget to DELETE your app.json file. 
4. Copy the plugin file that was provided above by the legends, and create a file "withReanimatedUseFrameworks.js" in your root directory. 

That it is you should be all set to go, try building the app now, and it should work as expected. 

Note: The animation transition still didn't work for me but it might actually work for you, I have a large project with so many dependencies with Firebase SDK + RN-firebase both installed, and other libraries as well. So I am still working on the solution. 
Ramzyn12 commented 1 month ago

For anyone trying to install the plugin following the method above and is finding that their podfile isn't being updated. Mine started working when I remove the expo object and replaced with the actual data. So replaced:

const { withPlugins } = require('expo/config-plugins')
const withReanimatedUseFrameworks = require('./withReanimatedUseFrameworks') // adjust the path if necessary

module.exports = ({ config }) => {
  return withPlugins(
    {
      ...config,
      expo: {
        name: "AppName",
        slug: "AppSlug",
        ...
      },
    },
    [withReanimatedUseFrameworks]
  )
}

With

const { withPlugins } = require('expo/config-plugins')
const withReanimatedUseFrameworks = require('./withReanimatedUseFrameworks') // adjust the path if necessary

module.exports = ({ config }) => {
  return withPlugins(
    {
      ...config,
        name: "AppName",
        slug: "AppSlug",
        ...
    },
    [withReanimatedUseFrameworks]
  )
}
tsalama commented 1 month ago

FYI I was only able to get the config plugin to work with the following mergeContents options so that it was under the correct target:

anchor: 'config = use_native_modules!',
offset: 2,
Lobovem commented 1 month ago

I finally had some time to dig into it, and here are the results.

What

The problem is not with Firebase itself, but the Podfile option it requires for the installation, as you have mentioned:

use_frameworks! :linkage => :static

Adding this line changes how linking is made and because of that the macro defined here resolves to false.

This macro is a simple check if the user has react-native-screens installed (the header is accessible). If yes, then we use actual Shared Element Transitions implementation. If not, then we load a mock. So in this case, we incorrectly use the mock. "Duplicate shared tag" error happening here is just a coincidence - it doesn't have a mock (but it should have).

From what I understand, this is happening because react-native-screens is not a dependency of Reanimated, and using dynamic workflows means it's unavailable (unaccessible) at compile-time, even though static linking is on.

Solution

For the time being, I've found a workaround for it. All you need to do is to add the following to your Podfile:

pre_install do |installer|
  installer.pod_targets.each do |pod|
    if pod.name.eql?('RNScreens')
      def pod.build_type
        Pod::BuildType.static_library
      end
    end
  end
end

This will make RNScreens a static library instead of a dynamic workflow and from my testing everything was working fine.

Notes

Unfortunately, we haven't yet found an elegant solution that wouldn't require additional input from the user (adding to Podfile). By elegant, I mean a way to find if react-native-screens is installed without digging through node_modules with some scripts or else. If someone has some experience with this kind of things, I'd be very glad to read some suggestions.

I will keep the issue open till this kind of solution is found (or we gave up).

It is work a way