Skip to content

feat(car): match the structure of actool 26.5 output - #3

Draft
TartanLeGrand wants to merge 4 commits into
xtool-org:mainfrom
TartanLeGrand:feat/match-actool-structure
Draft

TartanLeGrand wants to merge 4 commits into
xtool-org:mainfrom
TartanLeGrand:feat/match-actool-structure

Conversation

@TartanLeGrand

@TartanLeGrand TartanLeGrand commented Oct 12, 2026 •

Copy link
Copy Markdown

Draft, stacked on #2 (its first commit is #2's commit). Opened mostly to share what was learned about App Store Connect and Assets.car; it does not fix the problem it was written for, see below.

The problem

A production Tauri app built on Linux (xtool, AssetKit for the asset catalog) uploads to App Store Connect without error: the build upload reaches COMPLETE and the signature is accepted. The build is then never created: it stays in PROCESSING with no error, no warning and no e-mail. Bisected with IPAs that differ in one thing only (same harness, same signing, same upload path):

IPA Result
Xcode 26.5 export, re-signed VALID in about 2 min
Xcode export, DT keys and SDK changed to the Linux build's VALID in about 2 min
Xcode export with the Linux-built executables VALID in about 2 min
Linux build stuck (more than 40 min)
Linux build, launch storyboard from Xcode stuck
Linux build, actool Assets.car, PNGs and icon keys VALID in about 7 min
Linux build, only Assets.car replaced by actool's VALID in about 2 min

So the Assets.car is the cause. Both catalogs hold the same set of icon renditions, 1024 store icon included. A plausible explanation is that App Store processing extracts the store icon from the catalog and silently stalls on a catalog it cannot read, instead of rejecting it.

What this PR does

Brings the output closer to actool 26.5, one switchable group at a time (OutputOptions):

  • dimension1Key: ten-attribute KEYFORMAT with Dimension1, a slot in every rendition key, and the matching BITMAPKEYS descriptor size.
  • multisizeIcons: the part=218 icon size index records, the iPhone 60pt@3x copy at subtype 1792, and the BITMAPKEYS idiom / icon index masks.
  • actoolIdentifiers: the NameIdentifier actool gives to AppIcon (6849; the hash behind it is unknown, other names keep CRC32 & 0xFFFF).
  • actoolVersionStrings: CoreUI 975 and Xcode 26.5 strings in CARHEADER and EXTENDED_METADATA. Opt-in only, since it claims a tool that did not write the file; it was only there to test whether Apple's processing looks at it. I would drop it before merging.

The default becomes actoolStructure (the first three); .legacy reproduces the previous output. Tests add a small CAR reader and check the shape against what was dumped from an Xcode-built catalog. CARHEADER, KEYFORMAT and EXTENDED_METADATA (apart from the tool strings) and the 23 AppIcon rendition keys now match the Xcode file.

Result against App Store Connect

Each candidate replaced only Assets.car in the otherwise identical Linux IPA:

Candidate Result
previous output (.legacy) stuck (more than 16 min)
dimension1Key stuck (more than 19 min)
+ actoolVersionStrings + multisizeIcons stuck (more than 26 min)
+ actoolIdentifiers (same rendition keys as actool) stuck (more than 16 min)

None of them is enough. What still differs from actool: actool stores the small icons in ZZZZPackedAsset atlas renditions (element 9, part 181) and writes layout 0x3eb link records pointing into them, where AssetKit writes plain bitmaps; the LZFSE output differs; and so does the BOM block numbering. The next step I would try is the other direction: start from actool's Assets.car (which passes) and swap one family of renditions at a time for AssetKit's (the store icon alone, then the packed small icons, then the compression), which needs a .car rewriting tool. Until then, a workaround is to ship an Assets.car compiled once by actool.

How was it tested?

  • swift test on Linux x86_64 (Podman, Swift 6.4): Test run with 48 tests in 14 suites passed.
  • Real uploads as above.

Developed with AI assistance; validated against App Store Connect as described above.

Xcode 14+ writes an appiconset with one 1024x1024 universal entry
(platform "ios", no idiom, no scale). The loader rejected it because
the entry had no scale.

Decode idiom as optional and generate the iPhone, iPad and store sizes
from the master with an area-averaging downscaler, then reuse the
multi-size path. The master must be exactly 1024x1024. Dark and tinted
entries are skipped, other platforms are rejected.

Also set the rendition key's icon index from the point size, as actool
does, so icons of the same idiom and scale no longer share a key, and
drop duplicate loose file names.
An Assets.car built by this library leaves an App Store Connect upload
in processing forever, while the one from Xcode 26.5 is accepted. Bring
the output closer to actool, one switchable group at a time
(OutputOptions, all on by default):

- dimension1Key: ten-attribute KEYFORMAT with Dimension1, a slot in
  every rendition key, and the matching BITMAPKEYS descriptor size
- actoolVersionStrings: CoreUI 975 and Xcode 26.5 strings in CARHEADER
  and EXTENDED_METADATA
- multisizeIcons: the part 218 icon size index records, the iPhone
  60pt@3x copy at subtype 1792, and BITMAPKEYS idiom / icon-index masks
- actoolIdentifiers: the NameIdentifier actool gives to AppIcon

Add a small CAR reader to the tests and check the shape against what
was dumped from an Xcode-built catalog. A test-only generator writes
one candidate per group when CAR_CANDIDATES_OUT is set.
actoolVersionStrings claims the file was written by Xcode's actool, so
it is no longer part of the default OutputOptions. The default is now
actoolStructure (Dimension1, size index records, AppIcon identifier)
and the CARHEADER and EXTENDED_METADATA tool strings name AssetKit.
It only wrote experimental Assets.car files for manual uploads and is
not a test.
@coderabbitai

coderabbitai Bot commented Oct 12, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant