Building an Installer — Part 6

The Guts of the C4 Installer

C4
The C4 Dev

--

The actual structure of the C4 Template Installer is built off the exact techniques we have seen in previous posts. For reference, you can have a look at the installer repo on Github.

There are a six files / folders:

  • buildInstaller.sh (manages the build)
  • buildPackageComponents.sh (creates sub-packages to be installed)
  • updateDistributionXML.sh (updates xml for formatting the installer)
  • docs (contains the docset)
  • resources (contains images / text files for formatting the installer)
  • templates (contains the template files to be installed)

buildInstaller.sh

This is the main file that coordinates the build of the installer. It contains the following code:

VERSION="0_01"

… sets the version number for the current template.

sh buildPackageComponents.sh $VERSION 

… runs the buildPackageComponents.sh file, passing the version (see below).

TEMPLATES_PKG="INSTALL_TEMPLATES_$VERSION.pkg"
DOCSET_PKG="INSTALL_DOCSET_$VERSION.pkg"

… sets two variable for naming intermediate installer files.

productbuild --synthesize --package $TEMPLATES_PKG --package $DOCSET_PKG distribution.xml

… generates a distribution XML file, using the two templates.

sh updateDistributionXML.sh

… runs a script that updates the XML file (see below).

productbuild --distribution distribution.xml --resources ./resources C4Installer_$VERSION.pkg

… builds the installer from distribution.xml, including resources (see below).

rm -Rf $TEMPLATES_PKG
rm -Rf $DOCSET_PKG

… removes intermediate files.

buildPackageComponents.sh

This is the script that builds two independent installers. Each installer does a specific thing: one installs the templates, the other installs the docset.

INSTALLER_VERSION="$1"

… sets the installer version variable.

TEMPLATES_VERSION="$1"
TEMPLATES_LOCATION="./templates"
TEMPLATES_NAME="INSTALL_TEMPLATES_$TEMPLATES_VERSION.pkg"

… sets variables for the template file installer.

pkgbuild --root $TEMPLATES_LOCATION --identifier com.c4ios.installer.templates --version $INSTALLER_VERSION --install-location /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project\ Templates/Application $TEMPLATES_NAME

… builds the templates installer package.

DOCSET_VERSION="$1"
DOCSET_LOCATION="./docs"
DOCSET_NAME="INSTALL_DOCSET_$DOCSET_VERSION.pkg"

… sets variables for building the docset installer.

pkgbuild —root "$DOCSET_LOCATION" —identifier com.c4ios.installer.docset —version $INSTALLER_VERSION —install-location /Users/$USER/Library/Developer/Shared/Documentation/DocSets/ $DOCSET_NAME

… builds the docset installer package.

updateDistributionXML.sh

The installer’s user interface is customizable. There are a bunch of different things you can do to it, like specifying messages, build options, etc… Adding customized elements means you have to edit the distribution.xml file.

The update script uses XMLStarlet to edit a pre-generated file (this file is generated in buildInstaller.sh) and then save it before moving on to the final stage of producing the overall installer package.

The code is nasty, so we won’t get into it, but it adds three specific tags:

<title>C4 Xcode Templates</title>

… sets the title of the Installer window.

<background file=”C4InstallerBackground.png” mime-type=”image/png”/>

… sets the background image for the installer window.

<welcome file=”welcome.rtf” mime-type=”text/rtf”/>

… sets the main welcome text using the contents of an rtf file.

Fin.

I don’t often work with scripts, and prior to today I’d never used the command line to build installers, nor edit XML files. I started working at about noon, and by 6:45 had the structure of the installer scripts, files and product outputs all put together. I spent the rest of the evening writing up all the articles in this series.

Building an installer system this way is really good, for the following reasons:

  1. The structure is modern. Prior to today, I had built previous versions of the installer using PackageMaker. I found it daunting to not use a GUI, but after pushing through this build today I realize that this approach is far better and “easier” to understand once I figured out what I needed to understand.
  2. The structure is flexible. If I ever want to add new files to the template, I simply drop them into the templates folder. If I want to add new and separate docsets I can do the same by dropping them into the docsets folder. I can create small installers that focus on simple tasks rather than messing around with a GUI that tries to organize many different things.

I think we’ll be using this process for a long time, so I thought it was worth it to document it as much as possible.

--

--

C4
The C4 Dev

Code, Creatively. An open-source API for iOS.