Skip to content

Keep animated PNGs out of the iOS asset catalog - #59331

Closed
janicduplessis wants to merge 3 commits into
react:mainfrom
janicduplessis:@janic/asset-catalog-skip-apng
Closed

janicduplessis wants to merge 3 commits into
react:mainfrom
janicduplessis:@janic/asset-catalog-skip-apng

Conversation

@janicduplessis

@janicduplessis janicduplessis commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

With RCTUseAssetCatalog on (#30129), every png/jpg/jpeg packager asset goes into RNAssets.xcassets, and actool keeps only the first frame of an animated PNG. A require()d APNG renders as a still once the key is on, and the animated file is gone from the app, so a library that could animate it (expo-image, FastImage) has nothing to load.

Bundler: isCatalogAsset now reports a png asset animated when any of its scales has an acTL chunk before the first IDAT, and the asset is copied loose the way gif and webp already are. All scales go loose together, since the runtime resolves by scale-stripped name and an asset has to be entirely in the catalog or entirely out.

Runtime: RCTImageFromLocalAssetURL now falls through to the loose-file lookup on a catalog miss, and logs the "not found in the asset catalog" error only if that fails too. A missing RNAssets.bundle counts as a miss as well, since asset_catalog_compile does not create the bundle when no imageset is left (an app whose only png assets are animated); its error moves to the same spot. This reverses the no-fallback rule from #30129 (comment), but only on the miss branch: RCTAssetCatalogNameForURL still returns a name for any .png under assets/, so without this the bundler change would turn the still frame into a blank image plus an error. A hit is still a single lookup.

UIImage does not animate APNGs, so React Native's own <Image> still shows the first frame, as it did before the catalog existed. The change is for the file to ship intact. One consequence for expo/expo#50723: its catalog helper gates on RCTAssetCatalogNameForURL and calls RCTImageFromLocalAssetURL, so it now gets a still UIImage for an APNG through the fallback instead of nil.

Changelog:

[IOS] [FIXED] - Keep animated PNGs out of the iOS asset catalog, where actool would flatten them to one frame

Test Plan:

RNTester has the key on and gets a 4-frame APNG as a new "Animated PNG" example next to the Animated GIF one. Release build (xcodebuild -scheme RNTester -configuration Release, iOS 27.0 simulator): RNTester.app/assets/js/assets/animated.png and the gif are the only loose images, every other png and jpg is in RNAssets.bundle/Assets.car (53 renditions, none named animated). Opening rntester://example/ImageExample/animated-png renders the first frame, and log stream for the process shows no RCTLogError, so the catalog miss fell through to the loose file.

The flattening itself, for the record: compiling that APNG into a one-imageset catalog with xcrun actool yields a single still rendition in Assets.car (assetutil --info), while ImageIO reads 4 frames from the loose file.

Unit tests cover the detector (acTL before IDAT, acTL after a 70 KB chunk, still PNG, non-PNG bytes, truncated file, missing file) and isCatalogAsset (still png, APNG, only the @2x animated, jpg/gif never read):

yarn test packages/community-cli-plugin

actool compiles an animated PNG into a single still frame, so the CLI
now copies any png asset with an acTL chunk as a loose file instead of
adding it to RNAssets.xcassets. The runtime falls through to the
loose-file lookup on a catalog miss and only reports an error when that
fails too.
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 22, 2026
@facebook-github-tools facebook-github-tools Bot added the Contributor A React Native contributor. label Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Contributor A React Native contributor.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant