Simple Serial Numbers in Cocoa Applications
Overview
In this post, we’ll walk through the steps of creating Simple Serial, a Cocoa application whose sole purpose in life is to tell you if it’s registered or not. When a user goes to register Simple Serial, they’re sent an email, including a link. When they click the link, OS X launches the application and passes along the correct registration information to it. The user has never had to type in a serial number.
Simple Serial registers with OS X as the handler for simpleserial:// URLs. When you register it, you recieve email with a link like simpleserial://register/warwick%40codehackers.net/Bob%20Warwick/ABCD-ABCD-ABCD-ABCD. When you get the email, you click on the link, Simple Serial is passed the URL by OS X. The application then parses out the required data, validates it, and stores it for later retrieval.
So how do we go about setting this up in our applications? There are three steps. Letting OS X know that we’re handling simpleserial:// URLs, telling our application what to do when it receives the information, and actually applying that information for something useful.
Step One – Assign simpleserial:// URLs to the application
OS X allows you to specify your application as the app to handle a given URL scheme. In other words, I can have my application register with my computer to handle all URLs in the format of foo://stuff. This lets us pass data to an application from an email easily.
To do so, open the applications Info.plist file and insert
<key>
CFBundleURLTypes
</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>simpleserial</string>
</array>
</dict>
</array>
<key>NSAppleScriptEnabled</key>
<string>YES</string>
Now when it’s added to your system, it registers simpleserial:// with the system as its type. You can find some documentation about these plist keys here.
We need to enable Applescript support because OS X passes the URLs to our application via the ‘GetURL’ command.
Step Two – Tell application how to respond when a simpleserial:// request is recieved
We use a couple of Applescript script declaration files to handle the call made to our application. Please, stop crying! For Applescript/Cocoa intergration it’s on the painless end of the spectrum.
You’ll need two files added to your applications resources directory. In our example, they look like this:
Simple Serial.scriptTerminology
<?xml version=”1.0″ encoding=”UTF-8″?>
<!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>Commands</key>
<dict>
<key>GetURL</key>
<dict>
<key>Description</key>
<string>Open a URL</string>
<key>Name</key>
<string>get URL</string>
</dict>
</dict>
<key>Description</key>
<string>Handles URLs For Serial Number Entry</string>
<key>Name</key>
<string>Simple Serial Commands</string>
</dict>
</plist>
Simple Serial.scriptSuite
<?xml version=”1.0″ encoding=”UTF-8″?><!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>AppleEventCode</key>
<string>SISE</string>
<key>Commands</key>
<dict>
<key>GetURL</key>
<dict>
<key>AppleEventClassCode</key>
<string>GURL</string>
<key>AppleEventCode</key>
<string>GURL</string>
<key>CommandClass</key>
<string>serialHandler</string>
</dict>
</dict>
<key>Name</key>
<string>Simple Serial</string>
</dict>
</plist>
You can find out more about these files by reading the Apple documentation on script suite files
Step Three – Processing the Data With Our Application
From the scriptSuite file, you might have noticed the line:
<key>CommandClass</key>
<string>serialHandler</string>
This tells our application that when we receive the request, it should pass it on to the class ’serialHandler’. In the sample project, I’ve created that class which parses out the URL and writes it to user defaults. This class should be a subclass of NSScriptCommand.
In the MainMenu.nib file I’ve created the user defaults of ‘regName’, ‘regSerial’, and ‘regEmail’. The sample project has those values bound to textfields in it’s window.
The serialHandler class looks like this:
#import “serialHandler.h”
@implementation serialHandler
- (id)performDefaultImplementation { // This method is called when any URL with the scheme simpleserial:// is called
// Retrieve the contents sent by the URL and break it into an array
NSString *urlDecodedContents = [[self directParameter] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSArray *registrationInfo = [urlDecodedContents componentsSeparatedByString:@"/"]; // We now have an array that /should/ have the registration code info in it
// The values we care about are:
// [registrationInfo objectAtIndex:2] // Verifies this is a register operation
// [registrationInfo objectAtIndex:3] // The email address of the registrant
// [registrationInfo objectAtIndex:4] // The name of the registrant
// [registrationInfo objectAtIndex:5] // The serial number
// If it’s a registration URL without six fields, we’ll assume it’s invalid
if ([[registrationInfo objectAtIndex:2] isEqualTo:@”register”] && [registrationInfo count] == 6) { // Valid URL
// Validate the information. For this example, ‘ABCD-ABCD-ABCD-ABCD’ is the only valid serial, so we’ll just compare strings
if ([[registrationInfo objectAtIndex:5] isEqualTo:@”ABCD-ABCD-ABCD-ABCD”]) {
// The serial number has been accepted
// Save it to the user defaults
[[NSUserDefaults standardUserDefaults] setValue:[registrationInfo objectAtIndex:3] forKey:@”regEmail”];
[[NSUserDefaults standardUserDefaults] setValue:[registrationInfo objectAtIndex:4] forKey:@”regName”];
[[NSUserDefaults standardUserDefaults] setValue:[registrationInfo objectAtIndex:5] forKey:@”regSerial”];
return nil; // We’re done here. You might want to run some ‘remove unregistered restrictions’.
};
};
// Something failed along the way. Hopefully you’ll include a nice button to email you.
[[NSAlert alertWithMessageText:@"Activation Error" defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"There was a problem activating your copy of Simple Serial."] runModal];
return nil;
}
@end
Downloads – Sample Application and Source Code
Simple Serial.zip – This is the sample application. Download and run it. Then you can register it by using this link: simpleserial://register/warwick%40codehackers.net/Bob%20Warwick/ABCD-ABCD-ABCD-ABCD
Simple Serial Source.zip – This is the source code. Created with XCode 2.4.1 on OS 10.4.10.
All source is released free of charge. You may incorporate it into any of your applications. I assume no liability for any action that may come from you using this source. If you do use this in your application, I’d like a mention in your about box, but I don’t require it.
Update: I should note that this isn’t an original concept from me. Other developers like Michael Tsai have been smarter than me in this area for a while.