Skip to content

Add support for iOS 18 layered icons and Xcode 14+ single-size format#126

Merged
HazAT merged 1 commit into
HazAT:masterfrom
freshaengineering:master
Apr 24, 2026
Merged

Add support for iOS 18 layered icons and Xcode 14+ single-size format#126
HazAT merged 1 commit into
HazAT:masterfrom
freshaengineering:master

Conversation

@radu-ciobanu-fresha

@radu-ciobanu-fresha radu-ciobanu-fresha commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Add support for iOS 18 layered icons and Xcode 14+ single-size format

Problem

The badge gem currently uses a simple glob pattern (/**/*.appiconset/*.{png,PNG}) to find app icons, which doesn't understand modern iOS icon formats:

  • iOS 18 layered icons: Separate files for light mode (all.png), dark mode (dark.png), and tinted variant (tint.png)
  • Xcode 14+ single-size: Single 1024x1024 icon instead of multiple sizes

This causes issues where either icons aren't badged correctly or the tool doesn't recognize the new format.

Solution

Added intelligent icon detection by parsing Contents.json from asset catalogs:

New IconCatalog class

  • Parses Contents.json to understand icon structure
  • Detects three icon format types:
    • Layered (iOS 18+): Badges all variants (all.png, dark.png, tint.png)
    • Single-size (Xcode 14+): Badges the single 1024x1024 icon
    • Legacy: Badges all size variants (existing behavior)
  • Falls back to original glob behavior when Contents.json is missing

Backward Compatibility

✅ Fully backward compatible:

  • Legacy multi-size icons work exactly as before
  • Custom --glob option still works (bypasses new logic)
  • Falls back to glob if Contents.json parsing fails

Changes

  • Added lib/badge/icon_catalog.rb - Contents.json parser
  • Modified lib/badge/runner.rb - Uses IconCatalog when no custom glob
  • Modified lib/badge.rb - Requires icon_catalog module
  • Bumped version to 0.13.1

Testing

Tested with:

  • ✅ iOS 18 layered icons (all.png, dark.png, tint.png)
  • ✅ Xcode 14+ single-size format
  • ✅ Legacy multi-size format (backward compatibility)

Backward Compatibility

  • ✅ Custom --glob option preserved (uses original code path, unchanged)
  • ✅ Falls back to glob when Contents.json missing or malformed

Related Issues

Fixes iOS 18 layered icon support (mentioned in #122)

- Create IconCatalog class to parse Contents.json intelligently
- Detect icon format types: legacy multi-size, single-size, or layered
- For layered icons (all.png, dark.png, tint.png), badge all variants
- Maintain backward compatibility with custom glob option
- Bump version to 0.13.1 to satisfy fastlane-plugin-badge constraint (~> 0.13.0)

Fixes issues with iOS 17/18 layered app icons that were breaking
the badge overlay functionality.
@radu-ciobanu-fresha radu-ciobanu-fresha marked this pull request as ready for review February 2, 2026 13:35
@mhyassin

Copy link
Copy Markdown

Hello @HazAT, would be great if we can get this merged 🙌

@HazAT

HazAT commented Apr 24, 2026

Copy link
Copy Markdown
Owner

thx, will try to do a release today

@HazAT HazAT merged commit b2eb59e into HazAT:master Apr 24, 2026
HazAT added a commit that referenced this pull request Apr 24, 2026
Adds `test/smoke.sh`, a bash-based integration harness that exercises
every CLI flag combo against real fixtures in an isolated tmp dir. This
is now the de-facto test suite for the project — there is still no CI,
but `make smoke` gives a deterministic pre-release/pre-merge signal in
~12 seconds.

Coverage (20 cases):
  A. CLI flag matrix — 13 existing combinations from create-assets:
     default / --dark / --alpha / --alpha --dark / --grayscale,
     shield aspect-fill / --shield_no_resize / + dark / + geometry + scale /
     + grayscale, same against the fitrack fixture.
  B. Input format preservation — webp + shield, webp + default badge,
     webp + dark, jpg + shield (exercises the #121 fix).
  C. Shield URL construction — `shield_base_url` override produces
     the correct URL; default URL is unchanged when option omitted
     (exercises the #111 fix).
  D. IconCatalog single-size auto-detection — exercises the #126 path.

Design notes:
- Pure bash + the project's normal gem deps. No additional test framework.
- Isolated `$(mktemp -d)` workdir, cleaned on exit; pass
  `KEEP_ARTIFACTS=1` to retain output images for inspection.
- Exit codes: 0 = all pass, 1 = failures, 2 = missing system dependency.
- Fixtures read from `assets/`; nothing tracked is ever mutated.
- Dependency check fails loudly with an actionable message when
  imagemagick, ruby, bundler, or rsvg-convert is missing, or when
  `bundle install` hasn't been run.

Also:
- Makefile: new `make smoke` target + `.PHONY` declarations.
- .gitignore: ignore `/vendor/` so `bundle install --path vendor/bundle`
  (what smoke.sh implicitly uses when bundler is configured that way)
  doesn't accidentally stage gem contents.
- AGENTS.md: point at `make smoke` as the primary verification path,
  downgrade `make create-assets` to an asset-regen tool.
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.

3 participants