Introducing Glitter!

Glitter is a free utility for iPhone programmers to implement easy auto-update features into their application. Glitter will check (in the background) to see if there is an update available of your software. It will then quietly download the software to the phone and when it is ready to be installed you can prompt the user to begin the installation process. Below are download and usage instructions.

Download

Download the latest version here: Glitter 0.0.2.

If you would like to look at them right away use these links:
Glitter.h
Glitter.m

Usage

The Usage is two folder. 1. You need to add the Glitter source code to your project and utilize it, and 2) you need to set up an XML (plist) file on a server that tells glitter how to update.

Step 1. Add Glitter to your project.

Add the Glitter.h and Glitter.m files to your project. I like to add them into a subdirectory called Glitter.

Make the following additions to your UIApplicaiton class. For this example we will assume the UIApplication sub class is called MyApplication. We also assume Glitter is in a subdirectory of your project named Glitter. Also note that this is just how I implemented the class, there are many ways to do this.

MyApplication.h

In MyApplication.h import the Glitter header file.

#import "Glitter/Glitter.h"

Declare some class variables.

Glitter *_glitter;
NSThread *_glitterThread;
UIAlertSheet* _glitterPopup;
The thread will ensure that glitter is running in the background and not disturbing the main process. The UIAlertSheet is to let the user know when the update is ready to be installed.

Add some method declarations to your MyApplication interface.

- (void)checkGlitterStatus:(NSTimer *)timer;
- (NSString *)version;

MyApplication.m

In applicationDidFinishLaunching: method add:

_glitter = [[Glitter alloc] initWithApplication:self 
	URL:@"http://customizeapp.com/xml/glitter"];

[_glitterThread release];
_glitterThread = [[NSThread alloc] initWithTarget:_glitter 
	selector:@selector(checkForUpdateNow) object:nil];
[_glitterThread start];

NSTimer *glitterTimer = [NSTimer scheduledTimerWithTimeInterval: 0.2
	target: self
	selector: @selector(checkGlitterStatus:)
	userInfo: nil
	repeats: YES];

The above code first initializes the Glitter object. Notice that you must pass in the URL of the XML file that tells glitter what to do. You host this XML file on your server. You can view the XML file I use for Customize here http://customizeapp.com/xml/glitter". More instructions on this file are below.

Then the code initializes a thread that the glitter update check will run on. Lastly the code sets up a timer which will call the checkGlitterStatus: method to keep track of Glitter's progress.

Add the implementation of the version method. Glitter uses this method to determine if updates needs to be performed.

- (NSString *)version
{
	return @"0.1.1";
}

Add the implementation of the checkGlitterStatus: method.

- (void)checkGlitterStatus:(NSTimer *)timer
{
	if ([_glitterThread isFinished] || [_glitterThread isCancelled]) {
		
		[timer invalidate];
		if ([_glitter updateReady])
		{
			NSArray* buttons = [NSArray arrayWithObjects:@"Install Now",@"Remind Later",nil];
			_glitterPopup = [[UIAlertSheet alloc] initWithTitle:@"Update Available" buttons:buttons defaultButtonIndex:0 delegate:self context:nil];
			[_glitterPopup setBodyText:@"An update is now available. Click Install to install this update now."];
			[_glitterPopup popupAlertAnimated: TRUE];
		}
	}
}

When checkGlitterStatus is called it checks if the Glitter thread has stopped checking and if there is an update available. If there is then it displays a notice to the user and asks them if they want to install.

You'll need to add the delegate functions for the UIAlertSheet so you can catch the user response.

- (void)alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button 
{
	if (sheet == _glitterPopup)
	{
		if (button == 1)
		{
			
			[_glitter install];
			NSArray* buttons = [NSArray arrayWithObjects:@"Close",nil];
			UIAlertSheet* popup = [[UIAlertSheet alloc] initWithTitle:@"Installation Complete" buttons:buttons defaultButtonIndex:0 delegate:self context:nil];
			[popup setBodyText:@"Update was installed.  Restart for the changes to take effect."];
			[popup popupAlertAnimated: TRUE];
		}
	}
	[sheet dismissAnimated:TRUE];
}

This then will perform the installation if the user requested it and then display a notice when it is complete. Note: that if the installation takes a long time to perform then the program will lag here.

That's it for the source code modifications. Now we will examine the XML file that goes along with it.

Step 2. Create the XML update script.

The update script is how you will tell Glitter when an update becomes available. Glitter will pull out the entry for the version number that the UIApplication returns and use that data to proceed.

Here is the simplest XML file possible. This simply says that the version 1.0.1 is the latest version and does not need an update.

<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>1.0.1</key> <dict> <key>NeedsUpdate</key> <false/> </dict> </dict> </plist>

Let's assume that version 1.0.0 is the version that the user has installed, and you need to tell Glitter that if the user has 1.0.0 installed then they need to update. First you set the NeedsUpdate flag to true. We will only show parts of the file that are different.

... <key>1.0.0</key> <dict> <key>NeedsUpdate</key> <true/> </dict> ... Next you want to tell Glitter where it can download the update and the md5 has of the file to verify the download. ... <key>1.0.0</key> <dict> <key>NeedsUpdate</key> <true/> <key>Archive</key> <string>http://youserver.com/path/to/MyApplication-1.0.1.zip</string> <key>md5</key> <string>5fdaab79b61b8bca2339ae2c55522bb3</string> </dict> ... Good, now we need to tell Glitter how to install these files. Glitter assumes that the archive file is a zip and will unarchive it automatically. Let's also assume that you have your MyApplication.app folder zipped up into the root of that archive file. You now add the key "Exec" which holds an array of Command dictionaries. ... <key>1.0.0</key> <dict> <key>NeedsUpdate</key> <true/> <key>Archive</key> <string>http://youserver.com/path/to/MyApplication-1.0.1.zip</string> <key>md5</key> <string>5fdaab79b61b8bca2339ae2c55522bb3</string> <key>Exec</key> <array> <dict> <key>Command</key> <string>Move</string> <key>From</key> <string>MyApplicaiton.app</string> <key>To</key> <string>/Applications/MyApplication.app</string> </dict> </dict> ... As you can see we told Glitter to move the MyApplication.app folder into the Applications directory. This will overwrite the files that are currently in there and update the application. That should be sufficient for most developers, however, if you need more there is one other command that Glitter can perform. The System command simply passes the Execute string into the system() function call. Here is an example: ... <key>1.0.0</key> <dict> <key>NeedsUpdate</key> <true/> <key>Archive</key> <string>http://youserver.com/path/to/MyApplication-1.0.1.zip</string> <key>md5</key> <string>5fdaab79b61b8bca2339ae2c55522bb3</string> <key>Exec</key> <array> <dict> <key>Command</key> <string>Move</string> <key>From</key> <string>MyApplicaiton.app</string> <key>To</key> <string>/Applications/MyApplication.app</string> </dict> <dict> <key>Command</key> <string>System</string> <key>Execute</key> <string>echo Hello from Glitter!</string> </dict> </dict> ... From the script you can see that all this does is echo to the standard output. However this can execute virtually any command available to the system. Be careful when using this one!

Finishing Up

Now you have implemented everything that is needed to run Glitter. Just remember to upload the XML file and release your software!

Questions

If you have any trouble or have any questions about Glitter you can email me at my gmail account, the user name is thespicychicken. You can also find me in the following IRC channels usually.

Server Room
irc.moofspeak.net #customize2
irc.osx86.hu #iphone-dev
irc.osx86.hu #iphone-uikit