react-native-svg: [Android] [Reanimated] crash with react-native-svg 13.0.0

Bug

After update from react-native-svg 12.1.0 to 13.0.0 I have a crash on android with the following stack trace

java_vm_ext.cc:577] JNI DETECTED ERROR IN APPLICATION: JNI GetObjectRefType called with pending exception java.lang.RuntimeException: Exception in HostFunction: java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String
java_vm_ext.cc:577] 
java_vm_ext.cc:577] [native code]
java_vm_ext.cc:577] /Users/mlecoq/issues/reactNativeSvg13/node_modules/react-native-reanimated/src/reanimated2/UpdateProps.ts (46:26):1:267
java_vm_ext.cc:577] forEach@[native code]
java_vm_ext.cc:577] _f@/Users/mlecoq/issues/reactNativeSvg13/node_modules/react-native-reanimated/src/reanimated2/UpdateProps.ts (46:26):1:229
java_vm_ext.cc:577] [native code]
java_vm_ext.cc:577] styleUpdater@/Users/mlecoq/issues/reactNativeSvg13/node_modules/react-native-reanimated/src/reanimated2/hook/useAnimatedStyle.ts (185:0):1:1810

Unexpected behavior

Crash occurs since 13.0.0

Environment info

Run react-native info in your terminal and copy the results here. Also, include the precise version number of this library that you are using in the project

React native info output:

System:
    OS: macOS 12.5.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 105.06 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.13.1 - /var/folders/md/1qkynwbs1216d57grkbc682h0000gn/T/fnm_multishells/19554_1661241167202/bin/node
    Yarn: 1.22.15 - /var/folders/md/1qkynwbs1216d57grkbc682h0000gn/T/fnm_multishells/19554_1661241167202/bin/yarn
    npm: 8.1.2 - /var/folders/md/1qkynwbs1216d57grkbc682h0000gn/T/fnm_multishells/19554_1661241167202/bin/npm
    Watchman: 2022.03.21.00 - /opt/homebrew/bin/watchman
  Managers:
    CocoaPods: 1.11.3 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: DriverKit 21.4, iOS 15.5, macOS 12.3, tvOS 15.4, watchOS 8.5
    Android SDK: Not Found
  IDEs:
    Android Studio: 2020.3 AI-203.7717.56.2031.7935034
    Xcode: 13.4.1/13F100 - /usr/bin/xcodebuild
  Languages:
    Java: 11.0.13 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 18.0.0 => 18.0.0 
    react-native: 0.69.4 => 0.69.4 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Library version: 13.0.0

Steps To Reproduce

Issues without reproduction steps or code are likely to stall.

  1. git clone https://github.com/mlecoq/reactNativeSvg13
  2. cd reactNativeSvg13
  3. yarn
  4. yarn android

The project crashes at startup (no crash with 12.1.0)

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 5
  • Comments: 33 (11 by maintainers)

Commits related to this issue

Most upvoted comments

As pointed in the https://github.com/react-native-svg/react-native-svg/issues/1845#issuecomment-1247009705, the best way to handle fill and stroke props in by using createAnimatedPropAdapter which was made for this particular case, where props on the native side have different structure than in JS. Also, I changed the value prop to payload so it does not confuse reanimated babel plugin. Your animatedProps should look e.g. like this:

const ellipseAnimatedProps = 
   useAnimatedProps(() => 
   {
     const coordinates = {cx: 50, cy: 50, rx: 40, ry: 40};

     return {
       cx: coordinates.cx,
       cy: coordinates.cy,
       rx: coordinates.rx,
       ry: coordinates.ry,
       stroke: 'rgb(255,0,0)',
       fill: 'yellow',
       opacity: offset.value,
       strokeWidth: 2,
     };
   }
   , [], createAnimatedPropAdapter(
    (props) => {
      if (Object.keys(props).includes('fill')) {
        props.fill = {type: 0, payload: processColor(props.fill)}
      }
      if (Object.keys(props).includes('stroke')) {
        props.stroke = {type: 0, payload: processColor(props.stroke)}
      }
    },
    ['fill', 'stroke']));

Turns out my java.lang.Double cannot be cast to com.facebook.react.bridge.ReadableMap was just a misleading error message. Double check the props you’re passing to <SVG – I was accidentally passing an empty string "" for the fill prop on an svg text element. For some reason that got converted to a java.lang.Double resulting in the confusing error message.

@MarlonAEC I spent went way too long on this example lol, hope it helps! https://snack.expo.dev/@oiver55/svg-reanimated-example-path-fill?platform=android

Unfortunately super weird behavior on Android with Reanimated, useAnimatedProps barely seems to work anymore 😕

This code worked well in 12.4.0, but does not work now (no crash, but it does nothing):

  const animatedProps = useAnimatedProps(() => {
    const pos = getPositionOnCircle(angle.value)

    const x2 = pos.x
    const y2 = pos.y

    const degrees = toDeg(angle.value) + 90

    return {
      x: x2,
      y: y2,
      transform: [{ rotate: `${degrees}deg` }],
    }
  })
  

Guys, If i want to use fill property via useAnimatedProps. Example:

const animatedProps = useAnimatedProps(() => {
    return {
      fill: "#cccccc",
    };
  }
  
  <AnimatedEllipse animatedProps={animatedProps} />

In version 12.3.0 it is working, on 13+ i have similar error. Or i do something incorrect?

Hey @oiver555 I really love the effort you put into this example actually it helped me understand a bunch of things from react-native-reanimated. Now the thing is that I was looking for a way to do it using this Animated from react-native NOT the one from react-native-reanimated. Thanks for your example again it showed me a bunch of cool stuff I haven’t tried with reanimited library! Super helpful!

Hey @WoLewicki

How will we do it in this case?

const animation = useAnimatedProps(() => {
      const fill = interpolateColor(
        progress.value,
        [0, 1],
        [uncheckedBackgroundColor, checkedBackgroundColor]
      );
      const stroke = interpolateColor(
        progress.value,
        [0, 1],
        [uncheckedBorderColor, checkedBorderColor]
      );
      return { fill, stroke };
    });

@WoLewicki thank you it works like a charm 😍

Ok I will close this issue then. Feel free to comment here if something is wrong and we can always reopen it then.

Yes I just saw your example with the adapter, it works fine now, thanks a lot !

Unfortunately I don’t think it is. Since react-native-reanimated updates the props directly and does not go through render method, the typings may differ there leading to a crash 😞

Hi there, I add this here. I have no animation with react-content-loader since react-native-svg 13.0.0 only on Android. Everything works fine on iOS. And I have a fatal crash with this error:

Fatal Exception: java.lang.NullPointerException
Attempt to invoke virtual method 'java.lang.String java.lang.String.trim()' on a null object reference
com.horcrux.svg.SVGLength.<init> (SVGLength.java:37)

This library doesn’t use reanimated but seems to use animation from react-native.

Here an content-loader example:

<ContentLoader
   viewBox="0 0 360 100"
   height={100}
   width={360}
   backgroundColor={'#333'}
   foregroundColor="#999">
      <Circle x="70" y="20" cx="20" cy="20" r="20" />
      <Rect x="110" y="38" rx="0" ry="0" width="20" height="4" />
      <Circle x="130" y="20" cx="20" cy="20" r="20" />
      <Rect x="170" y="38" rx="0" ry="0" width="20" height="4" />
      <Circle x="190" y="20" cx="20" cy="20" r="20" />
      <Rect x="230" y="38" rx="0" ry="0" width="20" height="4" />
      <Circle x="250" y="20" cx="20" cy="20" r="20" />
</ContentLoader>

@WoLewicki thanks for your explanations, yes I started first to stringify params but since my code was failing on stroke (which expects ReadableMap), I did not dig any further.