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
Steps to Reproduce
- Build and install the app on a real iOS device
- Open the app and navigate to a screen with a Skia
Canvas component rendering visual elements (e.g. a background fill, shapes, etc.)
- Confirm the Canvas renders correctly
- Put the app in the background
- Wait for an extended period (we reliably see this after leaving the app in background overnight — shorter durations may not trigger it)
- Bring the app back to the foreground (the app must resume without a full reload — i.e. no splash screen)
- 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
Description
Our app uses multiple Skia
Canvascomponents 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:
React Native Skia Version
2.4.7
React Native Version
0.81.5 (Expo SDK 54)
Using New Architecture
Steps to Reproduce
Canvascomponent rendering visual elements (e.g. a background fill, shapes, etc.)Snack, Code Example, Screenshot, or Link to Repository
Attempted workaround (exploratory)
As an exploration to understand the issue, we created a
RemountedCanvasOnForegroundwrapper that listens toAppStatechanges 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: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