QR Code contains TinyURL of this article.Adding Survivability to macOS Applications

Stylised rendering of a rubber ring in the sea

There are a handful of utility programs that I have come to depend on in my day-to-day computing with macOS. These include:

  • Flycut: a simple yet effective clipboard manager (a fork of JumpCut, for those of you with memories as long as mine).1
  • Contexts: a drop-in replacement for the command+tab switcher. I use this, as opposed to macOS’ built-in switcher, as it lists all the windows for each app (even across Spaces). This is helpful when you run with multiple app windows, as I do.
  • Moom: a best-of-breed window manager. Because, again, I tend to have a lot of windows open.
  • QBlocker: prevents you from accidentally quitting applications by requiring you hold command+Q to quit (with a user-configurable delay).
  • Snappy: a screen-capture application. macOS has great screen capture tools out of the box but, Snappy has a handy feature in that a snapshot, taken with the app, will float atop all open windows (even across Spaces), for as long as needed. This reduces the amount of command+tab switching I need to perform and is a fantastic time-saver.

I want these apps to start when I login and I want them to remain active through the duration of my computing session. Guaranteed availability is important because these apps all share one common ingredient: they each make all of their principle functionality accessible to the keyboard interface. I have committed their keyboard shortcuts to muscle memory. So, if one of these apps crashes and I’m unaware of it, I have this jarring context shift when I issue a keyboard shortcut that isn’t then handled, or the system handles it differently to my expectations. One of the most consequential is that which occurs when QBlocker crashes. In which case my next hold of command+Q quits multiple applications rather than one (due to key repeat).

Sadly, applications do crash. So, in the case of essential apps, wouldn’t it be nice to have the computer restart a crashed program without any user interaction? We can have the machine do just that, with launchd — macOS’ unified service-management framework.

We start by, counter-intuitively, removing the apps from System Preferences → Users & Groups → Login Items (or by unticking their launch on login preference if they have one).

Next, we determine the path to each app’s executable by right-clicking the app’s icon and selecting Show Package Contents from the context menu. Click into Contents → MacOS to locate the name of the executable. For example: Snappy’s executable, on my machine, is at /Applications/SnappyApp.app/Contents/MacOS/SnappyApp

Open a terminal window and enter: sudo nano /LaunchAgents/com.keeprunning.snappy.plist then, paste the following into the nano editor:

<?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>KeepAlive</key>
  <dict>
    <key>SuccessfulExit</key>
    <false/>
  </dict>
  <key>Label</key>
  <string>com.keeprunning.snappy</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Applications/SnappyApp.app/Contents/MacOS/SnappyApp</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

Followed by control+O, return to save and control+X to exit.

Finally, we register and load our new plist:

launchctl bootstrap gui/`stat -f %` /Library/LaunchAgents/com.keeprunning.snappy.plist

Wash, rinse, repeat for each application that we require to be “always on” and we’re good to go.

The key commands of our plist file are:

  • KeepAlive → SuccessfulExit → false: this tells launchd to keep our application running unless it has a successful exit (that is, we intentionally quit it)
  • RunAtLoad → true: instructs launchd to ensure our application runs as soon as possible during the boot/login sequence.

Fault tolerance for the win. 😎

Via: TJ Luoma.

  1. Why, in 2017, a clipboard manager is not built-in to macOS is beyond me. ↩︎