Creating macOS Apps for Terminal Applications

Often I found cool little terminal applications and would like to use them just like normal macOS apps—showing in the dock waiting for me to click. It turns out to be pretty easy to achieve. This blog post shows how to do it with an example of building htop.app—an app that opens the famous htop.

.app structure

Apps in macOS are just normal folders ending with .app as well as having a special folder structure with some dedicated files.

htop.app
└── Contents
    ├── Info.plist --------- main file that defines the app
    ├── MacOS
    │   └── main.sh -------- the shell script to start the terminal app
    └── Resources
        └── monitor.icns --- app icon (optional)

The Info.plist file

The Info.plist file is an XML file that defines the executable of the app, the icon and other meta information. Below is minimal example:

<?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>CFBundleExecutable</key>
    <string>main.sh</string>
    <key>CFBundleIconFile</key>
    <string>monitor</string>
    <key>CFBundleIdentifier</key>
    <string>ai.xuk.htop</string>
</dict>
</plist>

Here in fact only CFBundleExecutable is must-have and others are optional.

  • The value of CFBundleExecutable should point to the name of shell script,
  • [Optional] The value of CFBundleIconFile should point to the name of icon file.
    • Here I’m using a monitor icon available that I found here.
  • [Optional] The value of CFBundleIdentifier is a unique bundle ID for the app, in reverse-DNS notation.

See the official doc for a detailed reference.

The main.sh

This shell script can be any name as long as it’s consistent with the value of CFBundleExecutable in Info.plist. One thing we need to make sure is that this script is executable, which can be done by changing the permission using chmod +x main.sh11 +x means adding (+) the executable premission (x) to the file; see this StackExchange answer for a nice explanation with a digram..

An example of main.sh is below:

#!/usr/bin/env bash

/Applications/Alacritty.app/Contents/MacOS/alacritty -t htop -e /usr/local/bin/htop

Here I’m using Alacritty to start htop using the -e option. A few other remarks:

  • Using absolute paths makes your life easy as the app doesn’t know your PATH variable.
  • Alacritty allows you to change the app title bar via the -t option.
  • Also remember to put your shebang (#!/usr/bin/env bash) there.

Screenshot

This is how the htop.app looks like on my machine (app icon in top right):

htop-v2.png

Note that the title bar is htop instead of Alacritty!

1

+x means adding (+) the executable premission (x) to the file; see this StackExchange answer for a nice explanation with a digram.

Created via Emacs with Org mode | Styled by Nord | Updated on 19 Feb 2022