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.

Comments are closed.

« Programmatically Creating an NSTableView
Getting the Airport Name and MAC Address »