TweetFollow Us on Twitter

Installer Plugins

Volume Number: 25
Issue Number: 06
Column Tag: Installers

Installer Plugins

Build a basic installer plug-in using Xcode

by José R.C. Cruz


Up to now, you know two ways to customize an install session. For instance, to check if the target is the right one for the payload, you use a requirements script. To prepare the target to receive the payload, you use an action or an install script. Yet, there are cases where you may find these approaches inadequate. To handle those cases, you may need an installer plug-in.

This article will give you the background you will need to write your own installer plug-in. First, it explains how the plug-in fits into the basic install session. Then, it describes the plug-in API defined by the InstallerPlugin.framework. Next, it presents the plug-in template and its constituent files. Finally, it shows how to build a basic plug-in and test it in a basic package.

As always, you can get a copy of the featured projects from the MacTech website. Just go to the following URL to download your copy.:

Enter The Plug-In

Figure 1. Sequence of panels in a basic install session.

Several panels make up a basic install session (Figure 1). The Welcome panel appears when users start the session by double-clicking the package. The second panel, ReadMe, provides users with more information about the package's payload. The third one, License, shows the manufacturer's license terms governing the use of the payload. User can either reject these terms, thus ending the session, or accept them to continue. Next, the Select Destination panel lets users choose the target volume on which to install the payload. After that, the Custom Install panel allows users to select which payload to install on the target. Then the Standard Install panel gives users one last chance to change their minds before the actual install occurs. Finally, the Conclusion panel summarizes the results of the installation.

Not all of these panels need appear in an install session. For instance, the Readme and License panels (grey) are optional. The install session skips these panels if they have no text to display. The Select Destination and Custom Install panels (orange) are controlled by the package. They appear only if users are allowed to change the target volume or choice of payloads during the session.

Now suppose your package needs extra information from the users, and none of the panels are up to the task. For this case, you need to write an installer plug-in. A plug-in can insert a custom panel at specific points of the session (Figure 2). It resides in the directory Contents/Plugins of the package. Also, a plug-in has full access to the Cocoa framework. This allows the plug-in to do a wide variety of tasks, tasks that are either difficult or impossible to do with a script.

Yet, like any software technology, an installer plug-in has its limits and issues. For one, it cannot replace any of the basic install panels. A plug-in must always provide a panel -- paneless plug-ins are not supported. Also, you cannot debug a plug-in using Xcode's source debugger. Your only recourse is to have the plug-in send debug messages to the console.log file using either NSLog() or ASL (Apple System Log). Another issue is that only meta-packages and distribution packages support installer plug-ins. The new flat-file Leopard package does not support them at this time.

Last of all, at the time of writing, the plug-in API is still poorly documented. Your only options so far are to study the header files in the InstallerPlugin framework, and the sample plug-in project from Apple.

Figure 2. A plug-in in an install session

The Plug-in Framework

The InstallerPlugin framework serves as the basis of all installer plug-ins. This framework is located in /System/Library/Frameworks of the OS X boot volume. The framework comes with four header files, one of which, InstallerPlugins.h, is the main header. The other headers define three classes your plug-in can use. Figure 3 shows how these classes relate to each other.

Figure 3. The InstallerPlugin framework

To add this framework to your Xcode project, select the Frameworks and Libraries group on the Groups & Files pane of the editor window. Choose Add to Project from the Project menu, and use the Open File dialog to select the framework. Click the Add button to include the framework to the project. Then add the following line to your header file

   #import <InstallerPlugins/InstallerPlugins.h>

Let us now examine what each class has to offer.

The InstallerPane class

The InstallerPane class (Figure 4) handles the display of the custom panel. It also manages the interactions between the panel and the users. In short, this class serves as the controller for that panel.

Figure 4. The InstallerPane class

The class has six private outlets, four of which give the views that are linked to the class. For instance, the contentView outlet is the panel itself. The initialKeyView outlet is the first control widget that gets user focus after the panel is displayed. The firstKeyView outlet points to the current widget that gets any keyboard events, while the lastKeyView outlet points to the last widget to get any events.

The nextPane outlet returns the installer panel that follows the current one. And the outlet parentSection returns the InstallerSection instance for that panel (more on this later).

The InstallerPane class also comes with a wide range of messages. In this article, we will focus only on those messages that deal with panel behavior. There are eleven of these messages, which falls under two groups. The first group consists of delegate messages that the class gets at each panel event (Figure 5).

Figure 5. Panel events and delegate messages

Before the panel appears in the install session, it sends a willEnterPane message to the InstallerPane class. This allows the class to prepare the resources it needs to support the panel. Next, the panel appears and sends a title message to the class. The class responds with a localized NSString, which the panel displays near its upper-right corner (green). Then the panel sends a didEnterPane to the class. The latter can respond either by setting the default values on the panel or by starting the desired services.

When users click the Go Back or Continue button, the panel first sends a shouldExitPane to the InstallerPane class. If the class returns a NO, the panel remains active. On the other hand, if the class returns a YES, the panel sends a willExitPane back to the class. The class uses this moment to process the user data from the panel. The panel then disappears and sends a didExitPane back to the class. This is where the class can dispose the resources it used to support the panel.

The second group of messages allows the InstallerPane class to control some panel activity. For instance, to enable the Continue button, send a setNextEnabled message with a YES argument.

   [self setNextEnabled:YES];

To read the state of the Continue button, send a nextEnabled message. If the button is enabled, the message returns a YES; otherwise, it returns a NO.

   tFlg = [self nextEnabled];

To display the next panel, use the gotoNextPane message. For the previous panel, use the gotoPreviousPane message.

   tFlg = [self gotoNextPane];

These messages have the same effect as users clicking the Continue or Go Back buttons. Both return a YES if the desired panel appears without errors. On the other hand, if the panel does not exists or if an error occurs, both messages return a NO.

The InstallerSection class

Next is the InstallerSection class (Figure 6), which works as a controller for InstallerPane. It supplies the plug-in with data on the current install session. The InstallerPane class carries an instance of InstallerSection in its parentSection outlet. To access the instance, send a section message from InstallerPane.

   tSct = [self section];

Figure 6. The InstallerSection class

The InstallerSection class has one private outlet, firstPane. This outlet stores an instance of the InstallerPane class. By default, this is the same InstallerPane whose the custom panel appears during the install session. Since this outlet exists, it implies that a plug-in can have multiple instances of InstallerPane, each one with its own custom panel. We will explore this possibility in a future article.

Next, the InstallerSection class comes with ten methods, some of which you can override. This article, however, will focus only on those methods that a basic plug-in can use. For instance, to get the current panel, use the firstPane or activePane method. Either method will return the same InstallerPane instance if the plug-in has only one custom panel.

   tPnl = [[self section] firstPane];

To get the nib that carries the custom panel, send a bundle message to InstallerSection. This returns the bundle as an NSBundle object.

   tBndl = [[self section] bundle];

To read the title string for the active panel, call the title method. InstallerSection responds by returning the panel title as an NSString.

   tTitle = [[self section] title];

And to find out the current install state, use the state accessor. This gives you an instance of the InstallerState class, which is described next.

   tState = [[self section] state];

The InstallerState class

As stated earlier, the InstallerState class (Figure 7) returns the current state of the install session. Like InstallerSection, this class is instantiated by InstallerPane once the latter displays its panel. To access the instance, use the state accessor of InstallerSection.

Figure 7. The InstallerState class

There are four sets of methods in the InstallerState class. Each set corresponds to a specific stage in the install session. The first set returns the results of the License panel. To find out if users accepted the license terms, use the licenseAgreed method. The method returns a YES if users did accept the terms; otherwise, it returns a NO.

   tAgree = [[[self section] state] licenseAgreed];

To find out which localized license is displayed, use licenseAgreedLanguage. This method returns the language as an NSString.

   tAgree = [[[self section] state] licenseAgreedLanguage];

The second set of methods return the results of the Select Destination panel. They tell the plug-in where the package will install its payloads. To get the selected target volume, use the targetVolumePath method.

   tVol = [[[self section] state] targetVolumePath];

The method returns the mount point of the selected volume as an NSString. To get the final destination for the payload, call the targetPath method.

   tPth = [[[self section] state] targetPath];

This returns the destination's absolute path as an NSString. The returned path will also have the volume's mount point as part of its string.

The next set of methods give the results of the Custom Install panel. They tell the plug-in which payloads where chosen by the users. For a list of all payloads, call the method choiceDictionaries.

   tList  = [[[self section] state] choiceDictionaries];

The method returns its list as an NSArray. For a specific payload choice, use the method choiceDictionaryForIdentifier. Then pass the payload's choice ID as input.

   tPayload  = [[[self section] state] 

This returns the choice settings as an NSDictionary. There are three entries in this dictionary, each entry with its own unique key. The choice ID, for instance, uses InstallerState_Choice_Identifier as its key, the payload's destination path InstallerState_Choice_CustomLocation. And the choice state is under the key InstallerState_Choice_Installed. Figure 8 shows which field on the choice's Configuration panel corresponds to which key.

Figure 8. The choice states and their keys

The Plug-in Template

To create an installer plug-in, use the Xcode project template, aptly named, Installer Plugin. Xcode 3.0 files this template in the directory /Developer/Library/Xcode/Project Templates/Standard Apple Plug-ins. You can, of course, write your own plug-in project from scratch. Using the template, however, reduces the amount of guesswork on your part.

Figure 9 shows the bundles and files of the project template. Note that there are two project bundles: one with a .xcode suffix, the other .xcodeproj. Use the .xcodeproj bundle if your Xcode IDE is version 2.x or newer; use the .xcode bundle for older versions of Xcode.

Figure 9. The plug-in project template

Note also that there are only three items that you should be updating. The rest of the project items have default settings that will suffice for most cases.

The InstallerSection.plist file

This file defines where your custom panel will appear in the install session. This file must be placed in the Contents/Plugins directory of your installer package. Without this file, your package will ignore your installer plug-in.

Listing 1 shows the default contents of that file. Note the file list only six of the panels that appear in the install session. The first three on the list refer to the Welcome, Readme, and License panels. The Target entry is the Select Destination panel, and PackageSelection is either the Custom or Standard Install panel. Finally, the Install entry is the progress panel, which appears when the package starts installing its payloads.

Listing 1. The InstallerSection.plist file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "">
<plist version="1.0">

Note as well that the file places the plug-in between the License and Target entries. It also lists the plug-in under the generic name of PROJECTNAME. When you create your plug-in project using this template, Xcode replaces PROJECTNAME with your plug-in's name. If you move your plug-in's entry in the list, you change the position of its panel in the install session. Also, if you delete one of the entries in the list, you prevent that panel from appearing during the session. But be careful with this last step, as it may lead to unexpected results.

The InstallerPlugin.nib bundle

This bundle defines the look and feel of your plug-in's panel. Like all nib bundles, you use the Interface Builder to make changes to this bundle. Figure 10 shows the five default objects in this bundle. Two of the objects are for your plug-in's use. For instance, the View object is, obviously, an instance of NSView. This object carries the interface of your custom panel. Double-clicking it gives you an empty panel that is 418 pixels by 330 pixels in size. Do not, however, change the size of the panel. If you do, your interface widgets will appear misaligned during the install session.

Figure 10. The InstallerPlugin.nib bundle

The <<PROJECTNAMEASIDENTIFIER>>Pane is an instance of InstallerPane. Its name is set to the project's name after you create the project. For instance, if your plug-in project is Foobar, the InstallerPane object gets the name FoobarPane.

The other three objects are the usual proxy objects you find in most nib bundles. But in this nib, the File's Owner proxy refer to the instance of InstallerSection. Its one outlet, firstPane, is linked to the nib's InstallerPane instance. The Application proxy refers to the global NSApplication object, which will be the Installer utility for the plug-in. And the First Responder proxy refer to the first object in the responder chain. This proxy is currently not attached to any object on the nib.

The Pane files

Finally, there are the two files: Pane.h and Pane.m. These files define the InstallerPane controller for your panel. Again, when Xcode creates your plug-in project, it prefixes the project name to each file. Do not, however, change the assigned file names to something else. If you do, your plug-in will be unable to display its panel correctly.

Treat these files as you would any controller class files. For instance, you can add outlets and link them to specific widgets on the custom panel. You can define actions that your panel widgets can call at runtime. You can even add code to manipulate user data or pass that same data to your own custom model class.


At the time of writing, the plug-in template has one interesting flaw. When you use it to create a project, the project's nib bundle loses all six outlets for its InstallerPane instance. Your plug-in will still work with this flaw present, but it will be unable to query the current install state.

To work around this flaw, save your nib bundle as NIB 2.x. With a text editor, open the file classes.nib that is inside your bundle. Then add the lines in Listing 2 to that file. These lines will restore the six outlets to your bundle. Save your changes when done.

Whether this flaw is fixed in Xcode 3.1 is unconfirmed.

Listing 2. Adding outlets to classes.nib


To Create A Plug-in

Let us now build a simple plug-in using the Installer Plug-in template. Our plug-in will ask users to enter their name, company, and product serial number during the install session. If the serial number is correct, the plug-in will enable the Continue button. Otherwise, it will display an alert dialog and disable the same button.

So, start up your copy of Xcode. Choose New Project from the File menu and pick Installer Plug-in from the list of project templates. Click the Continue button and set the project's name to Register. Leave the project's directory at the default location. Click the Finish button to create and open your new project.

Defining the panel

Select the entry RegisterPane.h from the Groups & Files pane. Add the following outlets to that file's @interface block.

   IBOutlet NSTextField   *oUser;
   IBOutlet NSTextField   *oComp;
   IBOutlet NSTextField   *oSerial;

Then add the following action to the same block.

   - (IBAction) registerCheck:(id)aSnd;

Next, double-click the Register.nib entry from the pane, thus opening the bundle in Interface Builder. From the Register window, select the icon «PROJECTNAMEASIDENTIFIER»Pane. Choose Identity Inspector from the Tools menu and set the Class field to RegisterPane. Scroll down to the Interface Builder Identity pane and set the Name field to RegisterPane. Save your changes by choosing Save from the File menu. To find out if your changes are correct, go to the Class Outlets pane of the palette. You should see your three outlets listed in that pane. Close the palette when you are done.

Now double-click the View icon on the Register window. Lay out the panel as shown in Figure 11. There are two sets of widgets on the panel. The first set consists of NSTextFields serving as static labels. The second set consists of NSTextFields serving as editable fields.

Figure 11. Layout of the custom panel

Select the RegisterPane icon and choose Connections Inspector from the Tools menu. With your pointing device, link each editable field to the right outlet (Figure 12, red). For this plug-in, the oUser outlet links to the User field, the oComp to the Company field, and oSerial to Serial. Then link all three editable fields to the registerCheck action (blue). Take care to leave the template's preset links alone. Save your changes and switch back to the Xcode editor.

Figure 12. Linking the panel widgets

Implementing the panel

We now enter the code-writing part of the project. Select the entry RegisterPane.m from the Groups & Files pane. Go to the delegate method didEnterPane and enter the code shown in Listing 3. This method sets each of the outlets to their default values. Then it disables the Continue button and enables the Go Back button.

Listing 3. Setting the default panel data

- (void)didEnterPane:(InstallerSectionDirection)aDir
      // initialize the following outlet fields
    [oUser setStringValue:@"your name goes here"];
    [oComp setStringValue:@"your company name"];
    [oSerial setStringValue:@"123456789"];
      // disable the Continue button
    [self setNextEnabled:NO];
      // enable the Go Back button
    [self setPreviousEnabled:YES];

Next, enter the code in Listing 4 to the delegate method shouldExitPane. First, the method reads the hash values from the oUser and oComp outlets. It then combines the two hash values and compares the results with the value from oSerial. If both values are different, the method displays a warning dialog to the users. It then disables the Continue button and returns a NO to prevent the panel change. On the other hand, if both values are the same, the method returns a YES to allow the change.

Listing 4. Checking the user data

- (BOOL)shouldExitPane:(InstallerSectionDirection)aDir
    NSUInteger tUsr, tCmp, tXor, tSN;
    NSAlert *tWrn;
   // check the direction of movement
    if (aDir == InstallerDirectionForward)
        // read the hash values of each registration
        tUsr = [[oUser stringValue] hash];
        tCmp = [[oComp stringValue] hash];
        tXor = tUsr ^ tCmp;
        // read the serial number
        tSN = [oSerial intValue];
        if (tSN != tXor)
            // create a warning dialog
            tWrn = [[NSAlert alloc] init];
            if (tWrn != nil)
                // initialize the dialog
                [tWrn addButtonWithTitle:@"OK"];
                [tWrn setMessageText:@"Invalid serial number"];
                [tWrn setInformativeText:
            @"Please check and re-enter your registration information."];
                [tWrn setAlertStyle:NSInformationalAlertStyle];
                // display the warning dialog
                [tWrn runModal];
                // dispose the warning dialog
                [tWrn release];
      // disable the Continue button
            [self setNextEnabled:NO];
            // prevent the panel movement
            return (NO);
// allow the panel movement
    return (YES);

Finally, to the registerCheck action, enter the code in Listing 5. This action checks the data in each outlet. If all outlets have a non-zero length string, the action then enables the Continue button. Otherwise, that same button remains disabled. Save your changes after you have updated these three methods.

Listing 5. Responding to the user entry

- (IBAction) registerCheck:(id)aSnd
    BOOL tChk;
    // check the registration fields
    tChk = ([[oUser stringValue] length] > 0);
    tChk &= ([[oComp stringValue] length] > 0);
    tChk &= ([[oSerial stringValue] length] > 0);
    // enable the Continue button
    [self setNextEnabled:tChk];

Now, a few words before we proceed to the next part of our project. First, note the use of the NSString hash function to generate the values for oUser and oComp. While this function is fine for our sample plug-in, it is impractical for real-world use. Future versions of NSString may behave differently. As a result, their hash functions may return a different value for the same string. A more reliable solution is for you to use your own hash algorithm.

Second, the plug-in only checks if the registration data is valid before it allows or deny product installation. This, again, is impractical because users can defeat the check by removing the plug-in. One good solution is to have the plug-in write its results to a hidden file. The installed payload can then look for this file and even read its data. If the data is correct, the payload behaves normally. If not, or if the file missing, the payload displays a reminder dialog or it runs in demo mode.

Building the plug-in

We are now ready to build our plug-in. But first, we must define where our plug-in's panel will appear in the install session. In this case, we want our panel to come after the Select Destination panel. Select the entry InstallerSection.plist from the Groups & Files pane. Locate the entry Register.bundle and move it after the entry for Target (Listing 6). Save your changs when done.

Listing 6. Modified contents of InstallerSection.plist


Now build the plug-in by clicking the Build button on the Xcode toolbar. Xcode compiles each project file and links them to create the plug-in bundle. It then places the bundle, named Register.bundle, in the in the project subdirectory build/Release/.

Installing and testing the plug-in

To test the plug-in, you will need a basic installer package. Now when you prepare your installer project, make sure to set its Minimum Target to MacOS X 10.4. This will tell PackageMaker to use the distribution bundle as the package format.

In this article, we will use Foobar_Demo as our installer project. Its payload consists of three TIFF files, which will go into the directory /Users/Pictures. Build the package by choosing Build from the Project menu. When prompted, use Foobar as the package name. Go to the Finder and control-click the package to display its contextual menu. Choose Show Package Contents to open the bundle in a separate Finder window. Go to the Contents directory and create a new subdirectory named Plugins. Then copy the plug-in Register.bundle and the file InstallerSection.plist into that subdirectory (Figure 13). Close the Finder window when done.

Figure 13. Installing the plug-in and plist

Now double-click the Foobar package to start the install session. First, you get a modal dialog (Figure 14) warning you that the package will perform a custom task. This means the package recognizes your plug-in's presence. But it can also mean that the package contains an install action or script. Click Continue to proceed.

Figure 14. Warning the user

After the package displays its Welcome panel, you will see the name Register added to the list of panels (Figure 15, orange). You will also see that same name after Destination Select. This means the package knows that the plug-in has a custom panel, and it knows when to display the panel.

Figure 15. The Welcome panel with an updated list

Click the Continue button until you reach the Register panel. For the User field, enter the name "Alan Smithee" as the user. For the Company field, enter "Foobar". Leave the Serial field unchanged. You should see the Continue button enabled at this point. Now click that button. The package will display a warning dialog (Figure 16) telling you that the registration data is wrong.

Dismiss the dialog by clicking its OK button. Carefully type 1239302760 into the Serial field and then click the Continue button. This time, the package will display the next panel, which is the Custom Install panel.

Figure 16. Incorrect registration

Concluding Remarks

An installer plug-in is another way to customize your install session. With a plug-in, you can display a custom panel for other users to interact. You can use the Cocoa framework to do tasks that are hard, if not impossible, to do with an action or script.

Xcode comes with a basic template that you can base your plug-in project. This template sets the necessary files and nibs needed for such project. Adding a plug-in is as simple as a drag and drop. But keep in mind that only a meta-package and a distribution package will use plug-ins. The new flat-file package, introduced in 10.5, will ignore any plug-ins it may carry.

Recommended References

As stated earlier, Apple has yet to document the task of writing an installer plug-in. So far, your best options, besides this article, are to study their sample plug-in project, or the header files of the InstallerPlugin framework. You can also query the Installer-dev list archives for possible answer to your questions.

Stéphane Sudre, maker of Iceberg, also wrote a couple of pieces on the topic. Listed below are his online works for your benefit.

Stéphane Sudre. "Defining Installer Plugins". Iceberg Users Guide. Copyright 2008. Accessed on 2008 Aug 14. Online:

Stéphane Sudre. "Installer Plugins". Installation - The Lost Scrolls. 2008 Apr 10. Online:

JC is a freelance engineering writer from North Vancouver, British Columbia. He spends his time writing technical articles; tinkering with Cocoa, REALbasic, and Python; and visiting his foster nephew. He can be reached at


Community Search:
MacTech Search:

Software Updates via MacUpdate

VMware Fusion 8.5.1 - Run Windows apps a...
VMware Fusion 8 and Fusion 8 Pro--the latest versions of its virtualization software for running Windows on a Mac without rebooting--include full support for Windows 10, OS X El Capitan, and the... Read more
Apple Final Cut Pro X 10.3 - Professiona...
Apple Final Cut Pro X is a professional video editing solution.Completely redesigned from the ground up, Final Cut Pro adds extraordinary speed, quality, and flexibility to every part of the post-... Read more
Civilization VI 1.0.0 - Next iteration o...
Sid Meier’s Civilization VI is the next entry in the popular Civilization franchise. Originally created by legendary game designer Sid Meier, Civilization is a strategy game in which you attempt to... Read more
Paperless 2.3.7 - $49.95
Paperless is a digital documents manager. Remember when everyone talked about how we would soon be a paperless society? Now it seems like we use paper more than ever. Let's face it - we need and we... Read more
Apple iMovie 10.1.3 - Edit personal vide...
With an all-new design, Apple iMovie lets you enjoy your videos like never before. Browse your clips more easily, instantly share your favorite moments, and create beautiful HD movies and Hollywood-... Read more
Apple Numbers 4.0.5 - Apple's sprea...
With Apple Numbers, sophisticated spreadsheets are just the start. The whole sheet is your canvas. Just add dramatic interactive charts, tables, and images that paint a revealing picture of your data... Read more
Xcode 8.1 - Integrated development envir...
Xcode includes everything developers need to create great applications for Mac, iPhone, iPad, and Apple Watch. Xcode provides developers a unified workflow for user interface design, coding, testing... Read more
iShowU Instant 1.1.0 - Full-featured scr...
iShowU Instant gives you real-time screen recording like you've never seen before! It is the fastest, most feature-filled real-time screen capture tool from shinywhitebox yet. All of the features you... Read more
RestoreMeNot 2.0.4 - Disable window rest...
RestoreMeNot provides a simple way to disable the window restoration for individual applications so that you can fine-tune this behavior to suit your needs. Please note that RestoreMeNot is designed... Read more
DEVONthink Pro 2.9.6 - Knowledge base, i...
DEVONthink Pro is your essential assistant for today's world, where almost everything is digital. From shopping receipts to important research papers, your life often fills your hard drive in the... Read more

Latest Forum Discussions

See All

Roofbot: Puzzler On The Roof (Games)
Roofbot: Puzzler On The Roof 1.0.2 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.2 (iTunes) Description: Guide Roofie through gorgeous, meditative rooftops and try to get the right color energy balls into the... | Read more »
The 4 best food delivery apps
As the temperatures continue to drop, so does the motivation to venture outside. Sometimes you still want to eat a nice meal from that sushi place down the road though. Thankfully in these trying times, there are a number of fine food delivery... | Read more »
Toca Life: Farm (Education)
Toca Life: Farm 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: Work and play the farmer's way! Milk your cow, gather eggs from your hens and raise your crops. Have a picnic, play the... | Read more »
The Lost Shield (Games)
The Lost Shield 1.0.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.0 (iTunes) Description: The Lost shield is a brick break/adventure game. You play as a hero who must return a powerful but dangerous magic shield... | Read more »
The Forgotten Room (Games)
The Forgotten Room 1.0.1 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.1 (iTunes) Description: Play as paranormal investigator John “Buster of Ghosts” Murr as he explores yet another mysteriously creepy house. This... | Read more »
5 Halloween mobile games for wimps
If you're anything like me, horror games are a great way to have nightly nightmares for the next decade or three. They're off limits, but perhaps you want to get in on the Halloween celebrations in some way. Fortunately not all Halloween themed... | Read more »
The 5 scariest mobile games
It's the most wonderful time of the year for people who enjoy scaring themselves silly with haunted houses, movies, video games, and what have you. Mobile might not be the first platform you'd turn to for quality scares, but rest assured there are... | Read more »
Lifeline: Flatline (Games)
Lifeline: Flatline 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: The Lifeline series takes a terrifying turn in this interactive horror experience. Every decision you make could help... | Read more »
Game of Dice is now available on Faceboo...
After celebrating its anniversary in style with a brand new update, there’s even more excitement in store for Game of Dice has after just being launched on Facebook Gameroom. A relatively new platform, Facebook Gameroom has been designed for PC... | Read more »
4 addictive clicker games like Best Fien...
Clickers are passive games that take advantage of basic human psychology to suck you in, and they're totally unashamed of that. As long as you're aware that this game has been created to take hold of your brain and leave you perfectly content to... | Read more »

Price Scanner via

Apple Unveils Redesigned MacBook Pro With Tou...
October 27, 2016 – Apple today introduced the thinnest and lightest MacBook Pro yet, along with a new interface innovation that replaces the traditional row of function keys with a Retina-quality... Read more
Apple Unveils New TV App for Apple TV, iPhone...
October 27, 2016 – Apple today introduced a new TV app, offering a unified experience for discovering and accessing TV shows and movies from multiple apps on Apple TV, iPhone and iPad. The TV app... Read more
Price drops on select refurbished 2015 13″ Re...
Apple dropped prices on select Certified Refurbished 2015 13″ Retina MacBook Pros by as much as $90. An Apple one-year warranty is included with each model, and shipping is free: - 13″ 2.7GHz/256GB... Read more
Apple reveals new next-generation 15″ and 13″...
Apple today revealed their next-generation 15″ and 13″ MacBook Pros. The new models are thinner and lighter than before with a new aluminum design featuring an enhanced keyboard with retina, multi-... Read more
Worldwide Smartphone Shipments Up 1.0% Year o...
According to preliminary results from the International Data Corporation (IDC) Worldwide Quarterly Mobile Phone Tracker, vendors shipped a total of 362.9 million smartphones worldwide in the third... Read more
TuneBand Arm Band For iPhone 7 and 7 Plus Rel...
Grantwood Technology has added the TuneBand for iPhone 7 and 7 Plus to its smartphone armband series. The TuneBand provides a lightweight and comfortable way to wear the iPhone while running,... Read more
1.4GHz Mac mini on sale for $449, save $50
Adorama has the 1.4GHz Mac mini on sale for $50 off MSRP including free shipping plus NY & NJ sales tax only: - 1.4GHz Mac mini (Apple sku# MGEM2LL/A): $449 $50 off MSRP To purchase a mini at... Read more
21-inch 1.6GHz iMac on sale for $999, save $1...
B&H has the 21″ 1.6GHz Apple iMac on sale for $999 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
Macs’ Superior Enterprise Deployment Cost Eco...
IBM’s debunking of conventional wisdom and popular mythology about the relative cost of using Apple Mac computers as opposed to PCs running Microsoft Windows at the sixth annual Jamf Nation User... Read more
12-inch WiFi Apple iPad Pros on sale for $50-...
B&H Photo has 12″ WiFi Apple iPad Pros on sale for $50-$70 off MSRP, each including free shipping. B&H charges sales tax in NY only: - 12″ Space Gray 32GB WiFi iPad Pro: $749 $50 off MSRP -... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Software Engineering Intern: UI Applications...
Job Summary Apple is currently seeking enthusiastic interns who can work full-time for a minimum of 12-weeks between Fall 2015 and Summer 2016. Our software Read more
Security Data Analyst - *Apple* Information...
…data sources need to be collected to allow Information Security to better protect Apple employees and customers from a wide range of threats.Act as the subject Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 52812872 Houston, Texas, United States Posted: Oct. 18, 2016 Weekly Hours: 40.00 **Job Summary** As an Apple Solutions Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.