Standalone apk different from Playstore aab: LinearGradient uses wrong colors

Viewed 141

I have a weird bug. I am developing a React Native app with Expo for Android. In one component I am using LinearGradient (expo-linear-gradient). In Expo Go and a standalone apk everything looks fine. But when I build the aab (expo build:android -t app-bundle), upload it to Playstore, then install it from there, the linear gradient looks different.

I am basically defining 2 gradients, and then choose one depending on the theme (light mode or dark mode). I get the theme from useColorScheme.

const LIGHT_TOP_GRAD = [
  "#ffffffFF", // rgba( 255, 255, 255, 1 )
  "#ffffffE6", // rgba( 255, 255, 255, 0.9 )
  "#ffffffB3", // rgba( 255, 255, 255, 0.7 )
  "#ffffff80", // rgba( 255, 255, 255, 0.5 )
];

const DARK_TOP_GRAD = [
  "#000000FF", // rgba( 0, 0, 0, 1 )
  "#000000E6", // rgba( 0, 0, 0, 0.9 )
  "#000000B3", // rgba( 0, 0, 0, 0.7 )
  "#00000080", // rgba( 0, 0, 0, 0.5 )
];

// in a component
const colorScheme = useColorScheme();
const darkMode = colorScheme !== "light";

// later in a render
        <LinearGradient
          colors={darkMode ? DARK_TOP_GRAD : LIGHT_TOP_GRAD}
          style={[styles.pickerGradient, { height: gradHeight }]}

In Expo Go and apk:

  • color and backgroundColor settings change depending on useColorScheme (ok)
  • LinearGradient colors change depending on useColorScheme (ok)

In aab:

  • color and backgroundColor settings change depending on useColorScheme (ok)
  • LinearGradient always uses LIGHT_BOT_GRAD independent of useColorScheme (?!)

At first I thought it was the way I define colors. So I switched from rgba( 255, 255, 255, 0.5 ) to #ffffff80 (Hex). I also thought that maybe I am seeing a default gradient. But if I leave out the colors prop I get errors.

I know this question is very vague. But do you have an idea what could be the problem here?

Are there certain things to watch out for? I am new to React Native and Expo.

Edit: Factories

I have now put the gradients into factories. I was worried that maybe something is mutating the arrays.

function getTopGrad(dark: boolean) {
  if (dark) {
    return [
      "#000000FF", // rgba( 0, 0, 0, 1 )
      "#000000E6", // rgba( 0, 0, 0, 0.9 )
      "#000000B3", // rgba( 0, 0, 0, 0.7 )
      "#00000080", // rgba( 0, 0, 0, 0.5 )
    ];
  }
  return [
    "#ffffffFF", // rgba( 255, 255, 255, 1 )
    "#ffffffE6", // rgba( 255, 255, 255, 0.9 )
    "#ffffffB3", // rgba( 255, 255, 255, 0.7 )
    "#ffffff80", // rgba( 255, 255, 255, 0.5 )
  ];
}

Anyway it doesn't help. It is like alpha is only supported for white.

Edit: No Hex Codes

I also tried below version where I only supply 2 colors. One is either white or black, the other is transparent. I was hoping that I can resolve this issue by avoiding Hex codes.

function getTopGrad(dark: boolean) {
  return [dark ? "black" : "white", "transparent"];
}

Anyway it also doesn't work. It always shows the white gradient.

Edit: It's the dark mode

I am getting kind of desperate now. I tried to supplement the gradients with .pngs I created. Even those are being converted to a bright color while in dark mode.

  • black becomes white
  • white stays white
  • blue becomes purple
  • a really dark gray becomes a really light gray

It seems the dark mode tries to make everything very bright. This is all only showing up in the aab.

1 Answers

I think this is related to issues with the dark mode on some devices in general:

In my desperation I fell back to some extreme solutions: I noticed that the style background-color is not affected by this whole color converion black box. So, I created a gradient by layering multiple divs with partly transparent background colors. This is the component:

function StepGradient(props: {
  height: number;
  layerCol: string;
  top: boolean;
}): JSX.Element {
  const n = 20;
  const just = props.top ? "flex-start" : "flex-end";

  let div = <></>;
  for (let i = 1; i <= n; i++) {
    div = (
      <View
        style={[
          styles.gradient,
          { justifyContent: just },
          { backgroundColor: props.layerCol },
          { height: (props.height * i) / n },
        ]}
      >
        {div}
      </View>
    );
  }
  return div;
}

const styles = StyleSheet.create({
  gradientWrapper: {
    position: "absolute",
    width: "100%",
  },
  gradient: {
    width: "100%",
  },
});

Then I use it like this:

      <View
        pointerEvents="none"
        style={[
          styles.gradientWrapper,
          { height: 200 },
        ]}
      >
        <StepGradient
          height={200}
          top={true}
          layerCol={darkMode ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)"}
        />
      </View>

This is the only way I was able to make it work (after 3 days trial-and-error).

Related