Mac OS X Software  
  Packaging     Sequoias     Misc.    


PackageMaker How-to

This document is targeted towards Mac OS X Developers with a minimum background on Mac OS X and notions like file paths, bundles, Developer tools.


A few words regarding this document

This document was written with PackageMaker 1.x in mind.

PackageMaker is available in version 3.0.4 at the time of the writing of this note. All the pieces of information in this document still apply when you select the target to be Mac OS X 10.3 in PackageMaker.

What is PackageMaker?

PackageMaker is the installing solution provided by Apple with its developer tools.

Contrary to other installers' solution, PackageMaker does not create self-running installer (i.e. it does not build an application). Instead, PackageMaker is creating a package:

A package is a bundle (with a .pkg extension) which contains an archive of files to install and information on where to install them. It can also includes Read Me, License documents and scripts to run before or after the installation.

To install a package, all you have to do is to double-click on its icon in the Finder and the Installer.app application will be launched and will guide your through the necessary steps of the installation.

Packages are the solution used by Apple to install Mac OS X and to provide System or Applications upgrades via the Software Update solution.

In which cases may I use an installer?

The first question you must ask yourself is:

"Do I need an installer to install my applications or documents?"

For instance, if you're distributing an application without any other files to install (Frameworks, StartupItems, Drivers, etc.), you don't need to use an installer in 99.99% of cases.

The 0.01% left is made of unusual cases like for instance if you want your application to be installed in the Applications folder of the root home directory (but this is just an example). For the other 99.99%, just distribute your application inside a Disk Image and inform the user in the Read Me file he/she just needs to move the file into the Applications folder to install it. You can also use the background image of the Disk Image to provide instructions to the user.

If you're distributing a solution that needs to put a driver in /SystemLlibrary/Extensions, an application in /Applications, a framework in /Library/Frameworks, then you seriously need an installer.

What are the pro and cons of using PackageMaker as my installing solution?

Pro
  • Apple uses installation packages in the format that PackageMaker can produce.
  • It's free.
  • This allows you to make remote installation using Apple Remote Desktop (1.1 or later).
  • Packages can be installed via the Terminal (Mac OS X Server and Mac OS X client)
  • It's a quite complete solution.
Cons
  • If you're screwing something when building your installer this may lead to unwanted results on the end-user's machine - do you hear the sound of the iTunes updater? But you can ruin a system using other installers too (if you don't know how, just ask).
  • There is no uninstall solution provided by Apple.
  • It's not available on another platform.
There used to be two interesting articles on this topic on the Stepwise web site but this website has disappeared.

What are the other available installing solutions?

The following list is not exhaustive, it's just including the 3 major commercial solutions.

NameDeveloperVersionPriceSupports UninstallEase of useScriptable
Install AnywhereZeroG Software5.0.7$1,995YES??
Installer VISEMindVision8.2.1Free to $1,500 a yearYES?AppleScript
PackageMaker1.1a10FreeNO2/5Command line
StuffIt InstallerMakerAladdinSys7.1.2Free to $1,000+ a yearYES??

Where can I find PackageMaker?

PackageMaker is installed with the Developer Tools. So if you don't have installed the Developer Tools, you won't find it.

If you have installed the Developer Tools, you can find PackageMaker inside the /Developer/Applications folder.

What version of PackageMaker should I use?

This may sound like a strange question but it's not that strange.

When Apple released Mac OS X 10.2 (Jaguar), a new PackageMaker application was released with the Jaguar Developer Tools.

This version of PackageMaker introduced new features but also a backward incompatibility.

The backward incompatibility is that packages built with the Jaguar version of PackageMaker can't be installed on Mac OS X system prior to 10.2 (i.e. 10.0.x and 10.1.x). I don't know why the "official" documentation is stated the contrary.

So if you want to allow users to install your package on Mac OS X 10.1 or prior, you will have to use the version of PackageMaker provided with the Mac OS X 10.1 Developer Tools.

This document will mainly deal with the 10.2 version of PackageMaker.

How do I create a package with PackageMaker?

Pre-requisite:

1st step:

This is the most important step. If you make mistake during this step, the consequences might be disastrous. So don't hesitate to check what you're doing.

To indicate to PackageMaker where the files of a package should be installed, you need to create a relative file hierarchy describing where each file should be installed. For instance, if a package needs to contain an application which has to be installed in the Applications folder, you need to create an Applications folder and put the application in this folder. If you need to install a driver in the Extensions folder, you need to create a System folder, then create a Library folder within the System folder, an Extensions folder within the Library folder and finally put your driver in the Extensions folder.

As stated, the file hierarchy is a relative one. This means that you first need to create a folder which will be the starting point of the file hierarchy. The final location of this starting point will be selected during the installation process. Usually, the final starting point is the root of a volume. If you need to install a driver or an application shared by every user, then the final starting point will be the root of a volume (the boot one or another).

To illustrate what you need to do, we will take the example of a package which needs to contain an Application and a driver used by this application. In this case, this is what the file hierarchy should look like:

The MyRoot folder can be located in your home folder for instance.

When this is done, you ABSOLUTELY MUST set the right owners and permissions of the files. If you don't set the appropriate permissions, you may end up creating a security hole or make the OS work incorrectly. A legend is saying that this may slow down the whole OS and this can only be solved later by using Disk Utility.app.

In our case, we need to set the following owners and permissions:

OwnerGroupPermissions
Applicationsrootadminrwxrwxr-x
Systemrootadminrwxrwxr-x
Libraryrootadminrwxrwxr-x
Extensionsrootadminrwxrwxr-x

As for our own files (bundles), we need to set all the files composing the bundles have the following attributes:

OwnerGroupPermissions
MyApplication.approotadminrwxrwxr-x
MyDriver.kextrootwheelrwxr-xr-x

You can of course set the permissions to be more restrictive but not less.

Once this is done, you then need to check that you don't have any useless files in this hierarchy.

One example of useless file is the .DS_Store file created by the Finder. While including this file in your package won't probably cause a security flaw on the system where the package will be installed, this may lead to some unwanted behavior.

For instance, if you have a .DS_Store file within the Applications folder, this file will overwrite the .DS_Store file in the Applications folder of the system where the package is installed. Since the .DS_Store file contains information on the way the Finder should display the content of a folder, when the user will display the content of the /Applications folder in the Finder, he/she may get a view with icons not located as they were before the package was installed.

Note:

You can easily remove all the .DS_Store in the relative file hierarchy using the Terminal and a command like:

find $HOME/MyRoot/ -name ".DS_Store" -exec rm -f {} \;

2nd step:

Once, the file hierarchy is done, you can now use PackageMaker to create the package. To do this, you need to logout and login under the root account (maybe it can be done directly from an admin account, but I haven't tested that yet).

Depending on the version of PackageMaker you're using, the User Interface might be different.

You can now enter the information for your package:

Now, we can build our package using the "Create Package" in the "File" menu. Let's give it the following name: "MyPackage.pkg".

Before quiting PackageMaker, don't forget to save your package settings via the "Save" command in the "File" menu. This will avoid re-entering the same data later if the package information is changed or updated with new versions of the files to install.

To be able to find this package quickly, copy it into the /Users/Shared folder and logout. Login under your account and go to the /Users/Shared folder.

Double-click on the MyPackage.pkg file to test the package installation.

Additional steps

Now that you know how to build a basic package, we can see how to add additional information to the package.

As we said before, a package can contain Read Me and License documents. In fact, it can contains 3 types of documents: Each of the 3 documents can be in one the following formats: They should be named as follow: To add these documents to the package, you need to create a folder and put the documents inside it. It's a good idea to create this folder at the same level that your "MyRoot" folder.

This will look something like this:
In PackageMaker, you can now set the location for the Resources folder and when you're building your package, the documents will be added into the package and they will be displayed when the package is being installed.

What about scripts?

When installing your package, you may want or have to do some additional things.

For instance, if you're installing a Kernel Extension, you have to do the following additional operation: set the correct file owner and group. Starting with Mac OS X 10.2, Kernel Extension must be owned by the pair root/wheel. Yet even if you set the files to be owned by root/wheel in your Starting Point file hierarchy, they won't be installed with root/wheel but with root/admin. This sucks, yes. One solution to fix this is to set the correct owner/group just after the package has been installed. This can be done via a script embedded in the package that will be launched by the Installer.

Another example: your package needs to remove files from a previous version before being installed. Again this can be done via a script embedded in the package that will be launched by the Installer.

Finally, another possible case where a script can be used is when you want to prevent the user from installing your package on a Mac OS X system prior to Mac OS 10.1.3. This can be done via a script embedded in the package that will be launched by the Installer.

There are 7 types of scripts than can be launched during the Installation Process:

Note: If you're building a package with the 10.1 version of PackageMaker, the names of the scripts are a bit different.

The scripts are launched in the following order:


These scripts can be written in different languages. The common ones are: Some information is passed by the installer to these scripts when they are launched:

LanguageParameterInstallationCheckVolumeCheckpreflightpreinstall/upgradepostinstall/upgradepostflight
Shell$0Script pathScript pathScript pathScript pathScript pathScript path
$1Package pathVolume path [1]Package pathPackage pathPackage pathPackage path
$2Default locationTarget locationTarget locationTarget locationTarget location
$3Target volumeTarget volumeTarget volumeTarget volumeTarget volume
Perl$0Script pathScript pathScript pathScript pathScript pathScript path
$ARGV[0]Package pathVolume path [1]Package pathPackage pathPackage pathPackage path
$ARGV[1]Default locationTarget locationTarget locationTarget locationTarget location
$ARGV[2]Target volumeTarget volumeTarget volumeTarget volumeTarget volume
Returned value 0: Success
32: Warning
48-63: Warning: Detailed reason [2]
64: Stop Install
112-127: Stop Install: Detailed reason [3]
0: Success
32: Failure: Unknow reason
48-63: Failure: Detailed reason [4]
0: Success
!=0:Failure
0: Success !=0:Failure
0: Success !=0:Failure
0: Success !=0:Failure

[1]
The VolumeCheck script is called for every volume.
[2]
The detailed reason is an index which is computed from the Returned value like this: index = ReturnedValue - 32
Installer.app then looks for a file named InstallationCheck.strings which associated a message to the index.
The InstallationCheck.strings will be used if you're building a localized package.
[3]
The detailed reason is an index which is computed from the Returned value like this: index = ReturnedValue - 96
Installer.app then looks for a file named InstallationCheck.strings which associated a message to the index.
The InstallationCheck.strings will be used if you're building a localized package.
[4]
The detailed reason is an index which is computed from the Returned value like this: index = ReturnedValue - 32
Installer.app then looks for a file named VolumeCheck.strings which associated a message to the index.
The VolumeCheck.strings will be used if you're building a localized package.
Tip: The scripts must have an Unix line ending. If they don't, this may crash the installation.

The scripts are run under the following user account:

Authorization ActionInstallationCheckVolumeCheckpreflightpreinstall/upgradepostinstall/upgradepostflight
No Authorization requiredLogin userLogin userLogin userLogin userLogin userLogin user
Admin AuthorizationLogin userLogin userrootrootrootroot
Root AuthorizationLogin userLogin userrootrootrootroot


Once you have written your scripts, add them into the Resources folder. In our virtual example, we're adding a VolumeCheck script to prevent the user from installing the application on a system prior to Mac OS X 10.2 and we're adding a postFlight script to fix the file permissions of our Driver.



You can then re-build your package: the scripts will be embedded in it and run during the Installation.

Finally, what about the flags?

Some of these flags are useful, some are useless.

How can I create a package with optional installs? (also How can I build a metapackage?)

For some installers, you may want to allow the user to select where he/she wants to install some optional files or not. For instance, the Mac OS X installation lets you decide whether you wan to install some localizations of the System or not.

This can be done via a metapackage. A metapackage is basically a package which does not contain any files but just points to a list of packages. A metapackage can contain Welcome, Read Me, and License documents. It can also contain InstallationCheck and VolumeCheck scripts. T he others scripts are not supported.

Building a metapackage with PackageMaker is easy as long as you know some information.


You can also select a metapackage to be a sub-package of a metapackage thus creating a nested hierarchy. This will result in something looking like this in the custom phase:

When a metapackage is being installed, scripts are run in almost the same sequence as with a package. The difference is with the preflight and postflight scripts.


Can I build an updater/upgrader with PackageMaker?

This is absolutely possible. Since there are pre/postupgrade scripts, it means that updating/upgrading is possible.

Basically, an updater/upgrader is just an installer which just contains the files that have been modified or added.

Some suggestions to use a package as an updater/upgrader:

How can I force the installation to be made on specific volumes?

Depending on your needs, there are 2 solutions:

How can I add a custom background picture for my package or metapackage?

Beginning with Mac OS X 10.2, the background picture displayed in the Installer.app window can be customized by the package.

To set this background image, you just have to add a file to your package Resources folder called background.suffix where 'suffix' may be:

The ideal size for the picture is: 620 x 418. If the size is different, the picture will be scaled.


Tip: If you're building a package using the 10.1 version of PackageMaker, you can use this background picture too. It won't be displayed when the installation is made on a Mac OS X version prior to 10.2, but it will for 10.2 and later.

How can I do a multiple localization installer?

Description forthcoming

How can I distribute my packages?

First thing to note is that since a package is a bundle, you can't distribute it "as is".

Some solutions that can be used:

Caution
Avoid using Stuffit to archive/compress your package

Previous versions of Stuffit had issues with filenames bigger than 31 characters. If the name of the package is a bit long and you have some scripts in it, the name of one script might be bigger than 31 characters. So when it will get unarchived by Stuffit, the name will be screwed and the package won't install properly.

Yet, if all the names of the files in the package are less than 31 characters, you can use Stuffit.

Don't change the name of your package

It's really a good idea to avoid changing the name of your package once it has been built. Because on Mac OS X 10.1, Installer.app is using the name of the package to find the file archive and scripts. If the name is not the original one, the installation is going to fail.

Can I call an external application from an installer?

Yes, you can call an external application from an installer. You can do this with one of the installation scripts. For instance the following postflight script will launch Preview.app:

#!/bin/sh

# Launch Preview.app

open /Applications/Preview.app

exit 0


Does PackageMaker support files with Resource fork?

Yes, it does. If some files in your file archive contains both a Data Fork and a Resource Fork, the following alert will be displayed:

If you select the Split Forks option, files with Data and Resource Fork are going to be splitted in 2 files. The 2 forks will be re-united during the Installation process.

Is it possible to write a script to build a package?

Yes, depending on the version of the OS you're using, the tool is not the same:

And if you're a real thrill seeker, you may also want to build a package without these tools and just by using command line tools. Here is an example: packaging script

Is there any tool to inspect packages once they have been built?

If you want to know which files are archived in a package, you have 3 solutions:

Is there any other tool to create packages and metapackages?

Yes, if you don't want to use PackageMaker, check alternative solutions such as Iceberg or Packages here: Packaging.





Site Map
Copyright 2004-2014 Stéphane Sudre.