Link Tool Copies and Verifies App Icons
-
Status: Approved (2026-09-21) by: @clsource
Problem
task icons generates the app icons into the committed lib/<platform>/assets
directories, but nothing copies them into the assembled trees. The Xcode
Assets.xcassets/AppIcon.appiconset in build/xcode/sources/ only holds a
modern Contents.json with no image files, and the Android tree has no res/
directory at all and its AndroidManifest.xml has no android:icon
attribute, so apps built from build/<platform>/sources/ show no custom icon.
Design
After copying app artifacts, link mirrors the icon output from
lib/<platform>/assets into the assembled Application tree and verifies it
landed:
-
Xcode:
lib/xcode/assets/AppIcon.appiconset/→build/xcode/sources/Application/Application/Assets.xcassets/AppIcon.appiconset/. The pbxproj already setsASSETCATALOG_COMPILER_APPICON_NAME = AppIcon, so a populated appiconset is all the project needs. -
Android:
lib/android/assets/icon/res/→build/android/sources/Application/src/main/res/(the lib-internalicon/grouping drops, somipmap-*land straight undersrc/main/res/). TheAndroidManifest.xml<application>tag gainsandroid:icon="@mipmap/ic_launcher"andandroid:roundIcon="@mipmap/ic_launcher_round", being replaced when already present and inserted when missing.
Two new flags (--xcode-assets, --android-assets) default to those lib
paths, mirroring how --<platform>-sources defaults to the build paths.
Behavior
-
The copy is a mirror: files in the destination that no longer exist in the source are removed, so the stale modern-format
Contents.jsonis replaced. -
A destination file that already matches is left untouched; a rerun is a byte-stable no-op.
-
After the mirror, every source file is re-read from the destination and compared byte-for-byte; any gap or mismatch fails the run by name.
-
Missing
lib/<platform>/assetsor a missing<application>tag fails loudly.
Implementation
-
linkIconsXcode(sources, assets)andlinkIconsAndroid(sources, assets)wrap a sharedsyncIconDir(src, dst)that mirrors (mirrorDir) and then verifies (verifyIcons) the two trees. -
ensureManifestIcons(content)rewrites only the<application>opening tag;rewriteFileskips the write when the tag already matches. -
run()calls both icon steps after the existing artifact copies.
Tests
-
TestMirrorDircovers copy, byte-stable rerun, stale-file removal and the missing-source error. -
TestVerifyIconscovers matching, mismatched and missing destinations. -
TestEnsureManifestIconscovers insertion, replacement, byte-stable rerun and the missing-tag error. -
TestRunIntegrationseeds temp icon asset trees, asserts the icons land inAssets.xcassetsandsrc/main/res, asserts the manifest attributes, and adds them to the rerun-stability snapshot.