Skip to content

Checking whether an exported iOS IPA really carries its app icon: assetutil on Assets.car (the bundle PNGs are CgBI and won't decode)

TL;DR.

When App Store Connect shows no icon after an upload, check the IPA before blaming the asset catalog. Unzip it and run xcrun --sdk iphoneos assetutil --info Payload/App.app/Assets.car. You should see a 1024 px AppIcon (the one ASC extracts), and Info.plist should have CFBundleIcons.CFBundlePrimaryIcon.CFBundleIconName. The loose AppIcon60x60@2x.png in the bundle is Apple-optimized CgBI PNG, so ordinary image decoders fail on it; that failure doesn't mean the icon is missing.

Symptom. A Capacitor app's first build is uploaded (unsigned xcodebuild archive, then -exportArchive), and the App Store Connect Apps list shows no icon. It's tempting to assume the asset catalog never made it into the build.

Check the IPA itself, in about 10 seconds:

mkdir /tmp/ipa && cd /tmp/ipa && unzip -q /path/App.ipa
plutil -p Payload/App.app/Info.plist | grep -A6 CFBundleIcons
# expect CFBundlePrimaryIcon => { CFBundleIconFiles => [AppIcon60x60], CFBundleIconName => AppIcon }
xcrun --sdk iphoneos assetutil --info Payload/App.app/Assets.car \
  | python3 -c "import json,sys; [print(a.get('Name'),a.get('Idiom'),a.get('PixelWidth'),a.get('AssetType')) for a in json.load(sys.stdin)[1:] if 'Icon' in str(a.get('Name'))]"
# expect: AppIcon phone 1024 Icon Image  (+ a MultiSized Image entry)

assetutil also prints a harmless objc warning (Class OS_at_encoder is implemented in both ...).

The trap. The bundle also holds loose AppIcon60x60@2x.png / AppIcon76x76@2x~ipad.png. Xcode's PNG optimization rewrites them as CgBI: byte-swapped channels, premultiplied alpha, a headerless zlib stream. Most image viewers and decoders, including agent image readers, report decode failed, which looks like a broken or missing icon. sips -g pixelWidth still reads the size, though. To view the image, extract the 1024 from Assets.car, or look at the source PNG in AppIcon.appiconset.

What it ruled out. With a single-size universal 1024 entry in AppIcon.appiconset/Contents.json (Xcode 14+) and ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon, an unsigned archive plus -exportArchive keeps the icon intact. That's unlike entitlements, which that pipeline silently drops. So if the IPA passes these checks, the blank ASC tile is on Apple's side (processing), not your build. Apple's help page confirms the icon only comes from the uploaded build: https://developer.apple.com/help/app-store-connect/manage-app-information/add-an-app-icon/

No signals yet