Requiring a minimum version of OS X for your application

Supporting old OS versions is always a lot of work for application developers.

Apple provides a way for the developer to specify the minimum required OS X version for an application by setting the LSMinimumSystemVersion key of the Info.plist file. The OS will then present the user with an error message if they try to run the application on an older version of the system.

Unfortunately, this feature is not very robust or user-friendly. It doesn’t work in Panther at all, and it presents a very minimal and confusing error message on other versions of OS X.

I describe a better solution, using a boot-strapping executable to check the OS version, and only load the real application if the minimum OS version is satisfied. If not, an informative alert is presented to the user. It works with Universal Binaries, Carbon and Cocoa, and all the way back to Mac OS X 10.0, and it doesn’t depend on the buggy LSMinimumSystemVersion feature from Apple.

Background

If you compile an application with gcc 4.0, it can only be run on Mac OS X 10.3.9 and later. When a user attempts to launch the application on an earlier version of OS X, it just simply refuses to launch. There’s no feedback at all about what’s going on.

Compounded with the fact that building Universal Binaries with anything other than gcc 4.0 is non-trivial, this problem is going to cause headaches for a lot of OS X developers out there.

Apple provides a solution by letting the developer specify the minimum OS X version in the LSMinimumSystemVersion key of the Info.plist file for the application. Before launching the application, LaunchServices will check the minimum system version required and give the user an error message if their system’s too old. However, after reading an entry on Dan Wood’s blog, Apple’s solution seems to fall short in several ways:

It only works on 10.2 and 10.4. Other versions of OS X completely ignore the LSMinimumSystemVersion key.

The error message presented by LaunchServices simply says, “You cannot use the application Foo with this version of Mac OS X.” There’s no mention of why the application can’t be used, or what version of Mac OS X is required (see the screenshot on Dan’s blog linked above).

My Solution

Instead of using LSMinimumSystemVersion, I use a boot-stapping mechanism (an executable called SystemVersionCheck) to launch the app’s actual executable or pop up an alert if the system version is too old. This works with both Carbon and Cocoa applications. Here’s how to do it:

Add the following text to your app’s Info.plist file to specify the minimum system version needed. If you don’t add this text, 10.3.9 is assumed to be the minimum system version required.

Build your application (Foo.app). Use gcc 4.0, make Universal Binaries, link against new frameworks, make it as OS X version-dependant as you want.

Open up the Foo.app/Contents/MacOS directory.

Add “.real” to the end of the file name of the app’s executable (“Foo” in this case, renamed to “Foo.real”).

Copy the SystemVersionCheck executable into the directory, and rename it to the original name of the app’s executable (“Foo”).

Release your app to the world. 10.0 users can now attempt to launch it (even if it requires Tiger and CoreData) and will be presented with a nice little alert telling them what version of OS X is required to use the app.

Cool Screenshots

Here’s what the SystemVersionCheck alert looks like on Mac OS X 10.0:

Here’s what it looks like on later OS X versions (10.2 is shown):

If the user simply needs to upgrade using Software Update (for example, the app requires 10.3.9 and they’re using 10.3.4), they’ll be given the option to open Software Update:

Getting the Code

The SystemVersionCheck executable is available below. A sample project that uses it (and demonstrates how to make an Xcode build phase to install it) and the source code for SystemVersionCheck is also included. This is all released under a BSD-style license: use it, change it, do whatever you want, but don’t come crying to me if it doesn’t work.

SystemVersionCheck makes options A and B much more user-friendly for the user, because your application’s executable won’t even be launched unless the minimum system version requirement is satisfied. So you only have to worry about compiling for the system version you want to support – SystemVersionCheck will handle the user-friendly alerts for users on older OS versions.