The beauty of Cocoa programs on the Mac is the functionality that Cocoa gives programmers “for free” in the libraries. Full typography, graphics, databases, UI widgets, file format import and export, and a slew of other things. The “no code” program is quite possible for many solutions in Tiger.
However, there are a few things that are absent. While Mac OS X has a software update functionality for itself and for all of Apple’s programs (like Final Cut Studio and iWork and so on), third-party developers have been tragically shut-out of this circle. Version Tracker and Mac Update have stepped in and written programs based on their update service that check your system’s third-party programs against their database and tell you when updates are available, but it’s a subscription and, honestly, is something the developer should have done himself.
Well, developers now have little excuse for not checking their own software versions. With the same kind of RSS feed that Podcasts use, any developer can update his ware without writing a line of code to his application.
Introducing Sparkle
This marvel is called Sparkle and was written by Andy Matuschak (who is one of the authors of Pixen, a graphics editor for Mac OS X designed for pixel artists). Sparkle can be dropped into your program, instanced in your NIB, hooked up to a menu, and then forever after provides complete self-updatability to your application including:
- Checking for updates
- Showing release notes
- Downloading the update
- Installing the update
- Restarting the program
All of that without hitting a web browser or opening a disk image (Adium contributors, are you reading this?). Sparkle works by pulling an RSS feed, checking the version of attached files, and then displaying the “there is a newer version” dialog if needed. To determine the version of the attachment without downloading it, Sparkle relies on your naming scheme to match a pattern of program-name_version.tgz, such as MyGreatApp_1.0.1.tgz. When it’s newer, you get a notice and the process begins. Very simple.
To make things even more special, it’s BSD-licensed, so you can use it in your shareware as long as you give notice and credit where it’s quite rightfully due.
I’ll go through the simple walk-through of how to do it (it’s mad simple) and then talk about changes I made to the code to fit how I will be using this in Notae in the next version.
Installing Sparkle
Appcasting
Appcasting is a lot like Podcasting in that it uses the enclosures extension of RSS 2.0 to attach a file to an entry. In this case, a developer creates an entry with the release notes for the program, attaches the update, and then posts the entry. Well, as mentioned before, with a special naming scheme you can tell Sparkle that a file is newer and should be installed. Personally, I use Drupal for my sites so this is crazy-easy since the first attached file to an entry is already included in the feed (in 4.6). I just made a category for Notae Updates and then made a human-readable alias to the taxonomy feed. Voila.
Whatever software you use to make the feed (or even if you hand-write it), you’ll need the address of the feed. It should only have application updates and only for one product. Get that URL and then hit Xcode.
Xcode
Get the package from the Sparkle page and add the folder to your project. Once that part is done, open your Info.plist file and add a key like the following:
<key>SUFeedURL</key>
<string>http://www.example.com/appcasts/myproduct</string>
This is where updates to your program will be announced.
In Xcode, you’re done, so open the NIB file that contains your menu bar in Interface Builder.
Interface Builder
On your NIB’s window, click on Classes, then go to the Classes menu and choose Read File. From here, select the SUUpdater.h file in your project and open it. You should now have SUUpdater in your class list.

Right-click on SUUpdater and choose “Instantiate SUUpdater” from the contextual menu. You’re pretty much operational now. Your app will load, Sparkle will trigger and then check for updates and all that. Yet, on the first run you’ll see a dialog that asks the user if he wants to check for updates at startup. If the user chooses to, you’re good. If not, you need a way of triggering that action, so we add a menu item for it.
In your application menu, drag in a menu item and call it something like “Check for Updates…” Note that in Mac OS X you put an ellipsis in by pressing option-semicolon. Control-drag a connection to the SUUpdate instance and pick the only action, checkForUpdates:, and click on Connect. Voila.
Build and Test
Add an entry to your feed with your RSS generator of choice, attaching a newer version of your app (in name, at least) and then build and run your application. Sparkle should pick up the update, show you the RSS entry, and then let you update.
Some Changes
This worked great for me the first time, but I do things just a little differently so I updated my copy of Sparkle to follow my workflow. The following are the changes I made, which should be helpful to others.
Filename Convention
I use a dash to separate the name from the version in my program archives, so the default underscore kind of bothered me. I feel the dash is just a more common mark than the “geekier” underscore. So, in SUUpdater.m around line 84, I changed the string in componentsSeparatedByString: to be a dash. Now I can use “Notae-1.0.2” as the name.
Compression Format
Sparkle, by default, supports tar, tgz, and tbz archives for the updated file. Why? The Finder easily creates ZIP files for the developer and a lot of software is sent around this way. So, I added the ability to unpack a Finder ZIP archive. On or about line 358 there’s an array of commands and file extensions. I expanded this out, one pair to a line, and then added a line for ZIP:
"ditto -xk - \"$DESTINATION\"", "zip",
This relies on a feature of various read calls that makes the dash character equal to standard in (which is what Sparkle does, pipes the data to the extraction command). So now ditto works for ZIP files like tar does the others and Finder archives work.
Version String
I use a script in Xcode to save the SVN revision number as the bundle version in the Info.plist file. By default, Sparkle checks this version against the version on the update file. I’m not putting build numbers on the update files, so I changed the key around like 100 from CFBundleVersion to CFBundleShortVersionString.
Spiff-e
All-in-all, this is a great little package. There are a few notes about things that need to be done, and I generally agree with them (not check on every app startup, for instance), but it is, overall, a lot of great things to get for free, and it should be a staple for Mac OSS/freeware/shareware in some form for current and future development.
If you want a feature added, add it and make it known to the author. I added ZIP, what about you? 
Post new comment