27. OS X

## 27. OS X

### 27.1. Packaging installers as ZIP files

OS X application bundles are merely directories with some metadata specified through the Info.plist file. Because of that, to deliver your application you must pack it somehow. InstallBuilder enables packaging the Mac OS X installer as a zip archive.

In order to use this functionality, simply enable the `<createOsxBundleZip>` setting in your project - such as:

    <project>
        ...
        <createOsxBundleZip>1</createOsxBundleZip>
        ...
    </project>

This will cause the installer to build the output app bundle, followed by packaging the app bundle in a zip file, which is stored in the same location and with the `.zip` prefix.

For example if your application is created as `~/Documents/InstallBuilder/output/sample-1.0-osx-installer.app`, the archive will be created as `~/Documents/InstallBuilder/output/sample-1.0-osx-installer.app.zip`.

The output ZIP archive will also have proper permissions set for all of the files inside the archive, so it is possible to create Mac OS X installers from any platform - including Windows.

### 27.2. Using DMGs to bundle your installers

The most common way used to deliver applications on OS X is using DMG files. A DMG is simply a disk image, which is mounted as separate volumen when opened.

InstallBuilder allows automatically bundling your installer on Windows, OS X and Linux. However, it currently only allows basic customizations (setting the background image). If you need to further customize the DMGs and are building on OS X, you could follow the manual DMG creation section instead.

To enable this functionality, you just need to enable the `<createOsxBundleDmg>` setting:

    <project>
        ...
        <createOsxBundleDmg>1</createOsxBundleDmg>
        ...
    </project>

Figure 88. Builder Creating a DMG

You can see the result in Figure 75

Figure 89. Simple DMG

As previously mentioned, it is also possible to provide a background image using the `<osxDmgBackgroundImage>` tag. The OS X bundle will be centered based on the image dimensions:

    <project>
        ...
        <createOsxBundleDmg>1</createOsxBundleDmg>
        <osxDmgBackgroundImage>${build_project_directory}/images/bitnami-clouds.png</osxDmgBackgroundImage>
        ...
    </project>

Figure 90. DMG with Custom Background

#### Manual DMG creation

Although InstallBuilder built-in DMG creation is really easy to use, sometimes you will require to further customize the generated DMGs. In those case, if you are creating your installers on OS X, you could use the below code to automatically create your DMG file in the `<postBuildActionList>`:

    <project>
       ...
       <postBuildActionList>
             <createTimeStamp>
                <format>%Y%m%d%H%M%S</format>
                <variable>timestamp</variable>
            </createTimeStamp>
            <setInstallerVariable>
                <name>tempDir</name>
                <value>/tmp/.tmpDir${timestamp}</value>
            </setInstallerVariable>
            <setInstallerVariable>
                <name>dmgName</name>
                <value>${installbuilder_install_root}/output/${project.installerFilename}.dmg</value>
            </setInstallerVariable>
            <setInstallerVariable>
                <name>tempDmgFile</name>
                <value>${tempDir}/tmp.dmg</value>
            </setInstallerVariable>
            <deleteFile>
                <path>${installbuilder_install_root}/output/${project.installerFilename}.dmg</path>
            </deleteFile>
            <deleteFile>
                <path>${tempDir}</path>
            </deleteFile>
            <createDirectory>
                <path>${tempDir}/output</path>
            </createDirectory>
            <copyFile>
                <destination>${tempDir}/output</destination>
                <origin>${installbuilder_install_root}/output/${project.installerFilename}</origin>
            </copyFile>
            <runProgram>
                <program>hdiutil</program>
                <programArguments>create -srcfolder "${tempDir}/output" -volname "${project.fullName}" -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW "${tempDmgFile}"</programArguments>
            </runProgram>
            <runProgram>
                <program>hdiutil</program>
                <programArguments>convert "${tempDmgFile}" -format UDZO -imagekey zlib-level=9 -o "${dmgName}"</programArguments>
            </runProgram>
            <deleteFile>
                <path>${tempDir}</path>
            </deleteFile>
       </postBuildActionList>
       ...
    </project>

Now you can test the generated DMG file by doubleclicking on it under the output directory:

Figure 91. Installer bundled in a DMG

A new volume will appear in your desktop:

Figure 92. DMG Volume

The new volume uses the default icon. If you have seen other commercial sofware DMGs, they usually display a customized volume icon, that is also possible with InstallBuilder. You will just need to create the appropriate icns file (`dmg-icon.png` in our example, placed in the folder `images` in ur project directory) and use the updated version of the code:

    <project>
       ...
       <postBuildActionList>
            <createTimeStamp>
                <format>%Y%m%d%H%M%S</format>
                <variable>timestamp</variable>
            </createTimeStamp>
            <setInstallerVariable>
                <name>tempDir</name>
                <value>/tmp/.tmpDir${timestamp}</value>
            </setInstallerVariable>
            <setInstallerVariable>
                <name>dmgName</name>
                <value>${installbuilder_install_root}/output/${project.installerFilename}.dmg</value>
            </setInstallerVariable>
            <setInstallerVariable>
                <name>tempDmgFile</name>
                <value>${tempDir}/tmp.dmg</value>
            </setInstallerVariable>
            <deleteFile>
                <path>${installbuilder_install_root}/output/${project.installerFilename}.dmg</path>
            </deleteFile>
            <deleteFile>
                <path>${tempDir}</path>
            </deleteFile>
            <createDirectory>
                <path>${tempDir}/output</path>
            </createDirectory>
            <createDirectory>
                <path>${tempDir}/mnt</path>
            </createDirectory>
            <copyFile>
                <destination>${tempDir}/output</destination>
                <origin>${installbuilder_install_root}/output/${project.installerFilename}</origin>
            </copyFile>
            <actionGroup>
                <actionList>
                  <copyFile>
                     <destination>${tempDir}/output/.VolumeIcon.icns</destination>
                     <origin>${build_project_directory}/images/dmg-icon.png</origin>
                  </copyFile>
                  <runProgram>
                     <program>SetFile</program>
                     <programArguments>-c icnC "${tempDir}/output/.VolumeIcon.icns"</programArguments>
                  </runProgram>
                </actionList>
                <ruleList>
                     <fileExists path="${build_project_directory}/images/dmg-icon.png"/>
                </ruleList>
            </actionGroup>
            <runProgram>
                <program>hdiutil</program>
                <programArguments>create -srcfolder "${tempDir}/output" -volname "${project.fullName}" -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW "${tempDmgFile}"</programArguments>
            </runProgram>
            <actionGroup>
                <actionList>
                  <runProgram>
                     <program>hdiutil</program>
                     <programArguments>attach "${tempDmgFile}" -mountpoint "${tempDir}/mnt"</programArguments>
                  </runProgram>
                  <runProgram>
                     <program>SetFile</program>
                     <programArguments>-a C "${tempDir}/mnt"</programArguments>
                  </runProgram>
                  <runProgram>
                     <program>hdiutil</program>
                     <programArguments>detach "${tempDir}/mnt"</programArguments>
                  </runProgram>
                </actionList>
                <ruleList>
                     <fileExists path="${build_project_directory}/images/dmg-icon.png"/>
                </ruleList>
            </actionGroup>
            <runProgram>
                <program>hdiutil</program>
                <programArguments>convert "${tempDmgFile}" -format UDZO -imagekey zlib-level=9 -o "${dmgName}"</programArguments>
            </runProgram>
            <deleteFile>
                <path>${tempDir}</path>
            </deleteFile>
       </postBuildActionList>
       ...
    </project>

The new volume should now display your custom icon:

Figure 93. DMG Volume With Custom Icon

#### Creating fancy DMG

The DMG created in the previous section just included a custom volumen icon but it can be customized much further, like changing the background, the position of the icons and the size of the window. To do that, you must use AppleScript so you must have enabled the "Enable access for assistive devices" setting. You must also have access to the window server (command line builds using non-logged in users will fail). The below code uses some command-line configurable settings to create a customized DMG with a custom background (`dmg-background.png` in the `images` directory):

    <project>
        <shortName>sample</shortName>
        <fullName>Sample Project</fullName>
        <version>1.0</version>
        ...
        <postBuildActionList>
            <createTimeStamp>
                <format>%Y%m%d%H%M%S</format>
                <variable>timestamp</variable>
            </createTimeStamp>
            <setInstallerVariable>
                <name>tempDir</name>
                <value>/tmp/.tmpDir${timestamp}</value>
            </setInstallerVariable>
            <setInstallerVariable>
                <name>dmgName</name>
                <value>${installbuilder_install_root}/output/${project.installerFilename}.dmg</value>
            </setInstallerVariable>
            <setInstallerVariable>
                <name>tempDmgFile</name>
                <value>${tempDir}/tmp.dmg</value>
            </setInstallerVariable>
            <deleteFile>
                <path>${installbuilder_install_root}/output/${project.installerFilename}.dmg</path>
            </deleteFile>
            <deleteFile>
                <path>${tempDir}</path>
            </deleteFile>
            <createDirectory>
                <path>${tempDir}/output</path>
            </createDirectory>
            <createDirectory>
                <path>${tempDir}/mnt</path>
            </createDirectory>
            <copyFile>
                <destination>${tempDir}/output</destination>
                <origin>${installbuilder_install_root}/output/${project.installerFilename}</origin>
            </copyFile>
            <actionGroup>
                <actionList>
                    <copyFile>
                        <destination>${tempDir}/output/.VolumeIcon.icns</destination>
                        <origin>${build_project_directory}/images/dmg-icon.icns</origin>
                    </copyFile>
                    <runProgram>
                        <program>SetFile</program>
                        <programArguments>-c icnC "${tempDir}/output/.VolumeIcon.icns"</programArguments>
                    </runProgram>
                </actionList>
                <ruleList>
                    <fileExists path="${build_project_directory}/images/dmg-icon.icns"/>
                </ruleList>
            </actionGroup>
            <actionGroup>
                <actionList>
                    <createDirectory>
                        <path>${tempDir}/output/.background</path>
                    </createDirectory>
                    <copyFile>
                        <destination>${tempDir}/output/.background/background.png</destination>
                        <origin>${build_project_directory}/images/dmg-background.png</origin>
                    </copyFile>
                </actionList>
                <ruleList>
                    <fileExists path="${build_project_directory}/images/dmg-background.png"/>
                </ruleList>
            </actionGroup>
            <runProgram>
                <program>hdiutil</program>
                <programArguments>create -srcfolder "${tempDir}/output" -volname "${project.fullName}" -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW "${tempDmgFile}"</programArguments>
            </runProgram>
            <actionGroup>
                <actionList>
                    <runProgram>
                        <program>hdiutil</program>
                        <programArguments>attach "${tempDmgFile}" -mountpoint "${tempDir}/mnt"</programArguments>
                    </runProgram>
                    <runProgram>
                        <program>SetFile</program>
                        <programArguments>-a C "${tempDir}/mnt"</programArguments>
                    </runProgram>
                    <runProgram>
                        <program>hdiutil</program>
                        <programArguments>detach "${tempDir}/mnt"</programArguments>
                    </runProgram>
                </actionList>
                <ruleList>
                    <fileExists path="${build_project_directory}/images/dmg-icon.icns"/>
                </ruleList>
            </actionGroup>
            <actionGroup>
                <actionList>
                    <runProgram>
                        <abortOnError>0</abortOnError>
                        <program>hdiutil</program>
                        <programArguments>detach "/Volumes/${project.fullName}"</programArguments>
                        <showMessageOnError>0</showMessageOnError>
                    </runProgram>
                    <runProgram>
                        <program>hdiutil</program>
                        <programArguments>attach -readwrite -noverify -noautoopen "${tempDmgFile}"</programArguments>
                    </runProgram>
                    <runProgram>
                        <program>osascript</program>
                        <programArguments>-e 'tell application "Finder"
    tell disk "${project.fullName}"
    open
    set current view of container window to icon view
    set toolbar visible of container window to false
    set statusbar visible of container window to false
    set the bounds of container window to {${dmg_window_bounds}}
    set theViewOptions to the icon view options of container window
    set arrangement of theViewOptions to not arranged
    set icon size of theViewOptions to ${dmg_icon_size}
    set background picture of theViewOptions to file ".background:background.png"
    delay 5
    update without registering applications
    set position of item "${project.installerFilename}" of container window to {${dmg_icon_position}}
    update without registering applications
    delay 5
    end tell
    end tell'
              </programArguments>
                    </runProgram>
                    <runProgram>
                        <program>hdiutil</program>
                        <programArguments>detach "/Volumes/${project.fullName}"</programArguments>
                    </runProgram>
                </actionList>
                <ruleList>
                    <fileExists path="${build_project_directory}/images/dmg-background.png"/>
                </ruleList>
            </actionGroup>
            <runProgram>
                <program>hdiutil</program>
                <programArguments>convert "${tempDmgFile}" -format UDZO -imagekey zlib-level=9 -o "${dmgName}"</programArguments>
            </runProgram>
            <deleteFile>
                <path>${tempDir}</path>
            </deleteFile>
        </postBuildActionList>
        ...
        <parameterList>
           <stringParameter name="dmg_icon_position" value="300, 100" ask="0"/>
           <stringParameter name="dmg_window_bounds" value="400, 100, 885, 430" ask="0"/>
           <stringParameter name="dmg_icon_size" value="72" ask="0"/>
        </parameterList>
    </project>

Figure 77 shows an example with a customized background, the application centered and an increased icon size

Figure 94. Custom DMG

### 27.3. Adding support for legacy OS X versions

Versions previous to InstallBuilder included by default support for PowerPC versions of Mac OS X.

For InstallBuilder versions 9 and later you need to explicitly enable support for those platforms by setting `<osxPlatforms>` to include the required platforms.

The value for the `<osxPlatforms>` tag should contain one or more of the following values:

- `osx-intel`— include support for Intel based processors
- `osx-ppc`— include support for PowerPC based processors
- `osx-10.2`— include support that supports Mac OS X 10.2 for PowerPC based processors

To revert to behavior in previous versions of InstallBuilder and include support for all of the platforms, the project should have the following setting:

    <project>
        <osxPlatforms>osx-intel osx-ppc osx-10.2</osxPlatforms>
        ...
    </project>

In order to provide Intel and PowerPC support, but without the Mac OS X 10.2 compatibility, the setting should include both `osx-intel` and `osx-ppc` - such as:

    <project>
        <osxPlatforms>osx-intel osx-ppc</osxPlatforms>
        ...
    </project>

26. Windows |  | 28. Encryption and password protection