radj
radj

Reputation: 4377

How to enforce Mac package installer to check version?

Based on productbuild's Distribution XML structure, pkg-ref's version attribute is auto-filled by productbuild itself. You can also specify the package version using a --version parameter to productbuild.

I made two packages: package A with version 1.0 and package B with the same binaries with version 2.0. These versions were given in three ways:

  1. As --version parameter
  2. As version of the binary being packed
  3. version values inside the Distribution.xml file

However, it seems Installer doesn't bother checking version and just installs any package being run. If you install version 2.0 first and then run the version 1.0 package next, the app is overwritten.

How do I enforce Installer to check the versions? Is there a key/attribute/parameter I need to specify somewhere to make the package version sensitive?

Upvotes: 0

Views: 3525

Answers (1)

Michael Domino
Michael Domino

Reputation: 419

In your Distribution.xml code, add this function:

function dontDowngrade(prefix) {
    if (typeof(my.result) != 'undefined') my.result.message = system.localizedString('ERROR_2');
    var bundle = system.files.bundleAtPath(prefix + '/Applications/YOURAPPNAMEHERE');
    if (!bundle) {
        return true;
    }
    var bundleKeyValue = bundle['CFBundleShortVersionString'];
    if (!bundleKeyValue) {
        return true;
    }
    if (system.compareVersions(bundleKeyValue, '$packageVersion') > 0) {
        return false;
    }
    return true;
}

The error string ERROR_2 is in Localizable.strings:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"   "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ERROR_0</key>
<string>This update requires Mac OS X version %@ or later.</string>
<key>ERROR_1</key>
<string>This software is not supported on your system.</string>
<key>ERROR_2</key>
<string>A newer version of this software is already installed.   </string>
<key>SU_TITLE</key>
<string>YOURAPPNAMEHERE</string>
</dict>
</plist>

I put all this in a bash script and use a here document to replace text with shell variables. For example, $packageVersion is the version of my app, e.g. "2.0.0.0". The string YOURAPPNAMEHERE could also be replaced with a shell variable.

cat <<EOF >"Distribution.xml"
<?xml version="1.0" encoding="utf-8"?>
...other text...
EOF

You can learn a lot by examining the iTunes installer. Download the installer, mount it, drag the .pkg file out and expand it:

$ /usr/sbin/pkgutil --expand Install\ iTunes.pkg iTunesExpanded

Then you can see the code and poke around

Upvotes: 1

Related Questions