Mettā

decentralized internets

Replace app icon automatically

Want to have your own custom app icon in the dock, but it always gets replaced by an app update?

Inspired by the talks to replace Warp.app icon (in multiple issues on GH), I've made a simple tool to automatically replace the icon after the app update.

Using this helpful article by Mayeu one can make a very simple agent watching for changes in the app icon file and replace it back.

The agent article above gives all the necessary background, here I'll just provide the actual script and agent configuration.

You will need one additional tool to reliably change the app icon, install it with brew install fileicon. (Recommended by this post and it works flawlessly).

To allow watching multiple apps separately, split the functionality into the setter script and one or more watcher scripts.

Create a script ~/Tools/app-icon-replace.sh:

#!/bin/sh
APP=$1
ICON=$2
FILE_ORIG=/Applications/${APP}.app/Contents/Resources/${APP}.icns
FILE_REPL=~/Tools/icons/${ICON}.icns

ORIG=$(shasum $FILE_ORIG | cut -d ' ' -f 1)
REPL=$(shasum $FILE_REPL | cut -d ' ' -f 1)

if [[ "$ORIG" != "$REPL" ]]; then
    sleep 5
    fileicon set /Applications/${APP}.app $FILE_REPL
    killall Dock

    echo "$(date): ${APP} icon changed, updated" >> ~/Tools/${APP}-watcher.log
fi

Create a script ~/Tools/warp-watcher.sh:

#!/bin/sh
sh ~/Tools/app-icon-replace.sh Warp classic_1984_mac

Don't forget to chmod +x ~/Tools/warp-watcher.sh!

We perform a check for an actual file change in this script, because otherwise fsevents will be signaling file change every time we copy the file over, resulting in an infinite loop, even if the file didn't actually change.

And make a plist file configuring the agent in ~/Library/LaunchAgents/org.myuser.warp-watcher.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>org.myuser.warp-watcher</string>
        <key>ProgramArguments</key>
        <array>
                <string>/Users/you/Tools/warp-watcher.sh</string>
        </array>
        <key>WatchPaths</key>
        <array>
                <string>/Applications/Warp.app/Contents/Resources/Warp.icns</string>
        </array>
</dict>
</plist>

We set up watcher to monitor for changes in the Warp's icon file - when it changes, the script will replace the icon back. This usually happens when the app updates itself, so before it launches again, the script will have a chance to fix the icon.

You can adopt it for any other application, just replace the paths in the script and plist file.

Launch the agent using launchctl load ~/Library/LaunchAgents/org.myuser.warp-watcher.plist and you're done.

PS. You can find some really nice terminal icons here.

Prototyping in Rust home Learning JTAG