Did you ever use the Sparkle framework in your Cocoa applications? It’s a great framewok that makes it easy for end-users to update your Mac OS X applications when a new version is released. We use it for Lustro, our first Cocoa application. It’s fairly easy to install and well documented. The problem is I needed it for a Cocoa bundle (also called a non-app bundle): a preference pane we want to install in the Mac OS X System Preferences.
The Sparkle documentation has some bundle installation instructions but my Cocoa level is not good enough to understand the different steps. Let’s see how we can activate Sparkle for our own bundle, step by step (I’m using version 1.5 b6 here).
Start with the first step from the Basic Setup guide. This step is the same for normal applications or non-app bundles.
Now import the Sparkle header in your own header class with:#import <Sparkle.h>
We need to instantiate the SUUpdater in our code, something that you don’t need to do for a full blown application. I added the following to my awakeFromNib method (that method will be loaded when the user opens your preference pane).
This will work but is incorrect. Sparkle will now write it’s user defaults in the com.apple.systempreferences which is a wrong practice. Sparkle will get confused as soon as 2 or more bundles use this method (the will use the same variables). You’ll need to point Sparkle to identifier specific for you bundle. Luckily we can tell Sparkle to use our bundle:
Replace the ‘com.example.yourbundle’ with your own bundle identifier.
Start your bundle and click the update button. Close the System Preferences and check the user defaults to see if it works. There is a nice command in Mac OS X called ‘defaults’ that can read these user defaults for you (be sure to close the application first as it will only write the new settings to disk when the application closes). Open Terminal and type:
Look for ‘SU-’ prefixed parameters. You can have a look in our code to see how the end result looks like.
This post is open source. Did you spot a mistake? Ideas for improvements? Contribute to this post via Github. Thank you!