Skip to content

Canvas renders transparent after resuming app from long background on iOS #3695

@0xEzis

Description

@0xEzis

Description

Our app uses multiple Skia Canvas components as cards / discs backgrounds across the home screen.
After the app has been in the background for an extended period on iOS (e.g. overnight), bringing it back to the foreground results in Canvas components rendering as completely transparent (black is the default background color of the large cards in the attached videos), as if the rendering context was lost or invalidated during background suspension and not recovered by Skia on resume.

Key observations:

  • Only reproduced on real iOS device builds so far. We have not been able to reproduce on the iOS Simulator, though we haven't tested leaving a simulator in the background for hours — it's possible the simulator simply doesn't suspend the app as aggressively as a real device.
  • Only happens when the app resumes from background (no splash screen shown). When iOS fully kills the app and shows the splash screen on relaunch, the Canvas renders correctly because everything initializes fresh.
  • Not confirmed on Android. Android tends to trigger full reloads more often when returning from a long background, which avoids the issue entirely. We haven't tested extensively enough to confirm.
  • This may be related to Metal context invalidation during long background suspension, but we haven't confirmed the exact native-level cause.

React Native Skia Version

2.4.7

React Native Version

0.81.5 (Expo SDK 54)

Using New Architecture

  • Enabled

Steps to Reproduce

  1. Build and install the app on a real iOS device
  2. Open the app and navigate to a screen with a Skia Canvas component rendering visual elements (e.g. a background fill, shapes, etc.)
  3. Confirm the Canvas renders correctly
  4. Put the app in the background
  5. Wait for an extended period (we reliably see this after leaving the app in background overnight — shorter durations may not trigger it)
  6. Bring the app back to the foreground (the app must resume without a full reload — i.e. no splash screen)
  7. Observe: Canvas renders as black/transparent, content is missing

Snack, Code Example, Screenshot, or Link to Repository

Attempted workaround (exploratory)

As an exploration to understand the issue, we created a RemountedCanvasOnForeground wrapper that listens to AppState changes and forces a remount of the Canvas (via a key increment) when the app returns to foreground after being in background for more than 30 seconds:

// RemountedCanvasOnForeground.tsx
import { Canvas, type CanvasProps } from "@shopify/react-native-skia";

export const RemountedCanvasOnForeground = (props: CanvasProps) => {
  const key = useForegroundRemountKey();
  return <Canvas key={key} {...props} />;
};
// useForegroundRemountKey.ts
export const useForegroundRemountKey = () => {
  const [key, setKey] = useState(0);
  const backgroundTimestamp = useRef<number | null>(null);

  useAppStateListener({
    onBackground: () => {
      backgroundTimestamp.current = Date.now();
    },
    onForeground: () => {
      if (Platform.OS !== "ios") {
        backgroundTimestamp.current = null;
        return;
      }
      const wasInBackgroundLongEnough =
        backgroundTimestamp.current &&
        Date.now() - backgroundTimestamp.current > 30000;

      if (wasInBackgroundLongEnough) {
        setKey((prev) => prev + 1);
      }
      backgroundTimestamp.current = null;
    },
  });

  return key;
};

This partially works — when the key increment triggers a re-render, the Canvas remounts and renders correctly. However, the re-render is not always triggered on the first foreground event after a long background. When opening the app a second time shortly after, the remount works correctly.

This is not a solution we intend to ship — it's a JS-side workaround we used to confirm that the issue lies in the native rendering layer. Ideally, Skia should automatically recover its rendering context when the app returns to foreground, without requiring a full component remount from the React side.

Screenshots / Videos

Video 1 — Canvas recovering after a second foreground (black rectangles are visible before content properly re-render):
https://github.com/user-attachments/assets/652ef9b0-5e1f-4f84-906a-8bb1e39feb90

Video 2 — Canvas NOT recovering on first foreground (stays black):
https://github.com/user-attachments/assets/d7af6665-e247-4d98-aac7-7e8fd5aa4e8b

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions