react-native-shadow-2 icon indicating copy to clipboard operation
react-native-shadow-2 copied to clipboard

Crash on Android runtime

Open ScreamZ opened this issue 2 years ago • 5 comments

Hello,

When I use this library on android my app is crashing on expo-dev-client android with "react-native-shadow-2": "^6.0.4".

Expo SDK 44 -> "react-native-svg": "12.1.1"

ℹ️ EDIT: This does not crash when the Shadow ~~is not wrapping a TouchableOpacity or~~ doesn't provide viewStyle with an excessive borderRadius or a child with an excessive borderRadius. So It might be nice to write it somewhere in the doc or handle this case.

For tailwind user : rounded-full implementation gives 9999 as radius and looking at your code this might cause a crash with react native SVG.

For the rest of the code:

tw("bg-primary-strong rounded-full p-5")

Generate following code

{
  "backgroundColor": "rgba(244, 23, 51, 1)",
  "borderBottomLeftRadius": 9999,
  "borderBottomRightRadius": 9999,
  "borderTopLeftRadius": 9999,
  "borderTopRightRadius": 9999,
  "paddingBottom": 20,
  "paddingLeft": 20,
  "paddingRight": 20,
  "paddingTop": 20,
}

✅ Works

<TouchableOpacity activeOpacity={0.7}>
      <Shadow>
        <QRCodeIcon
          width={32}
          height={32}
          color={tailwindConfig.theme.colors.white}
        />
      </Shadow>
    </TouchableOpacity>

❌ Crash with viewStyle with excessive borderRadius

<TouchableOpacity activeOpacity={0.7}>
      <Shadow viewStyle={tw("bg-primary-strong rounded-full p-5")}>
        <QRCodeIcon
          width={32}
          height={32}
          color={tailwindConfig.theme.colors.white}
        />
      </Shadow>
    </TouchableOpacity>

⚠️ The crash seems related to 9999 value.

Old question : Crash ❌

import { QRCodeIcon } from "@modules/ui/icons/QRCodeIcon";
import React from "react";
import { TouchableOpacity } from "react-native";
import { Shadow } from "react-native-shadow-2";
import { useTailwind } from "tailwind-rn";
import tailwindConfig from "tailwind.config";

export const ScanStationButton: React.FC = () => {
  const tw = useTailwind();

  return (
    <Shadow>
      <TouchableOpacity
        activeOpacity={0.7}
        style={tw("bg-primary-strong rounded-full p-5")}
      >
        <QRCodeIcon
          width={32}
          height={32}
          color={tailwindConfig.theme.colors.white}
        />
      </TouchableOpacity>
    </Shadow>
  );
};

expo-env-info 1.0.3 environment info:
    System:
      OS: macOS 12.0.1
      Shell: 5.8 - /bin/zsh
    Binaries:
      Node: 16.14.2 - ~/.volta/tools/image/node/16.14.2/bin/node
      Yarn: 1.22.18 - ~/.volta/tools/image/yarn/1.22.18/bin/yarn
      npm: 8.5.0 - ~/.volta/tools/image/node/16.14.2/bin/npm
      Watchman: 2022.03.21.00 - /usr/local/bin/watchman
    Managers:
      CocoaPods: 1.11.3 - /usr/local/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 21.2, iOS 15.2, macOS 12.1, tvOS 15.2, watchOS 8.3
      Android SDK:
        API Levels: 26, 28, 29, 30, 31
        Build Tools: 28.0.3, 29.0.2, 29.0.3, 30.0.2
        System Images: android-30 | Google APIs Intel x86 Atom, android-30 | Google Play Intel x86 Atom
        Android NDK: 24.0.8215888
    IDEs:
      Android Studio: 2021.1 AI-211.7628.21.2111.8309675
      Xcode: 13.2.1/13C100 - /usr/bin/xcodebuild
    npmPackages:
      expo: ~44.0.0 => 44.0.6 
      react: 17.0.1 => 17.0.1 
      react-dom: 17.0.1 => 17.0.1 
      react-native: 0.64.3 => 0.64.3 
      react-native-web: 0.17.1 => 0.17.1 
    Expo Workflow: managed

Crash log (android hermes)

FATAL EXCEPTION: main
Process: com.power.stride.staging, PID: 6412
java.lang.OutOfMemoryError
	at android.graphics.Bitmap.nativeCreate(Native Method)
	at android.graphics.Bitmap.createBitmap(Bitmap.java:1129)
	at android.graphics.Bitmap.createBitmap(Bitmap.java:1087)
	at android.graphics.Bitmap.createBitmap(Bitmap.java:1037)
	at android.graphics.Bitmap.createBitmap(Bitmap.java:998)
	at com.horcrux.svg.SvgView.drawOutput(SvgView.java:250)
	at com.horcrux.svg.SvgView.onDraw(SvgView.java:106)
	at android.view.View.draw(View.java:21594)
	at android.view.View.updateDisplayListIfDirty(View.java:20471)
	at android.view.View.draw(View.java:21326)
	at android.view.ViewGroup.drawChild(ViewGroup.java:4413)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4174)
	at com.facebook.react.views.view.ReactViewGroup.dispatchDraw(ReactViewGroup.java:710)
	at android.view.View.updateDisplayListIfDirty(View.java:20462)
	at android.view.View.draw(View.java:21326)
	at android.view.ViewGroup.drawChild(ViewGroup.java:4413)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4174)
	at com.facebook.react.views.view.ReactViewGroup.dispatchDraw(ReactViewGroup.java:710)
	at android.view.View.draw(View.java:21597)
	at android.view.View.updateDisplayListIfDirty(View.java:20471)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4397)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4370)
	at android.view.View.updateDisplayListIfDirty(View.java:20431)
	at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:580)
	at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:586)
	at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:659)
	at android.view.ViewRootImpl.draw(ViewRootImpl.java:3871)
	at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3671)
	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2993)
	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1930)
	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7988)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1154)
	at android.view.Choreographer.doCallbacks(Choreographer.java:977)
	at android.view.Choreographer.doFrame(Choreographer.java:893)
	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1139)
	at android.os.Handler.handleCallback(Handler.java:883)
	at android.os.Handler.dispatchMessage(Handler.java:100)
	at android.os.Looper.loop(Looper.java:214)
	at android.app.ActivityThread.main(ActivityThread.java:7682)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

ScreamZ avatar Apr 28 '22 10:04 ScreamZ

Thanks for the report.

If you set the radius to 100 or 200, does it happen? Can you keep increasing to see what aproximated value causes this?

SrBrahma avatar Apr 28 '22 15:04 SrBrahma

Looks like around 2000/3000 it's still working, but I'm not sure this can be a relevant fix to cap this value. It should be a fraction of the size of the element or something like this. This main idea is being able to make perfect circles with rectangle.

ScreamZ avatar Apr 29 '22 08:04 ScreamZ

Thanks! I will only cap it if I can't find a better workaround, but anyway it's a useful info to know this aproximated value.

In theory the max radius is 100% of the element side length (like an arc from bottomLeft to topRight) or 50% for a circle, but we only know the element size after the first render via onLayout. Right now we can't use x% radii, but maybe I can add a prop like circle to get this working.

Also, if you use the saferRender prop, you should not get this crash, as we already limit the radii on 2nd render and beyond.

SrBrahma avatar Apr 29 '22 16:04 SrBrahma

Can you tell me if this error happens on [email protected]? Although Expo SDK 44 doesn't say it supports this latest version, it does fine.

I tried to find a way to have the circle property but I fear it isn't possible to have it on the first render, via proportional sizings and positionings. I will keep trying to find a way, but looks like it isn't possible.

I could cap the value to 2000, but you would have a huge visual artifact on the first render, like, a colossal corner. At least you wouldn't have a crash, and maybe other devs in similar position would then look for the safeRender solution to avoid this artifact.

SrBrahma avatar May 20 '22 06:05 SrBrahma

Can you tell me if this error happens on [email protected]? Although Expo SDK 44 doesn't say it supports this latest version, it does fine.

I tried to find a way to have the circle property but I fear it isn't possible to have it on the first render, via proportional sizings and positionings. I will keep trying to find a way, but looks like it isn't possible.

I could cap the value to 2000, but you would have a huge visual artifact on the first render, like, a colossal corner. At least you wouldn't have a crash, and maybe other devs in similar position would then look for the safeRender solution to avoid this artifact.

I can try, I think a good way could be to start document this issue, somewhere and add a warning, most of time you don't need huge value like those but you need to adjust à high value specifically for your use case 😌

ScreamZ avatar May 20 '22 07:05 ScreamZ

Hi, I just added this note on README:

image

Closing this as I don't think that limiting the radii values may be the best decision at the moment.

SrBrahma avatar Apr 14 '23 16:04 SrBrahma