|
| 1 | +# Create Universal Installer |
| 2 | + |
| 3 | +## ABOUT |
| 4 | +- `ZSH` program will create a combined Universal macOS Installer component package (`.pkg`) |
| 5 | +- Builds from separate Apple silicon and Intel `.app` bundles for the same title |
| 6 | +- Program supports download URLs for either two `.zip` files or two `.dmg` files, both containing `.app` bundles |
| 7 | +- Code will validate Apple silicon executable type is `arm64` and Intel `x86_64` prior to build |
| 8 | +- Package contains logic to place the native `.app` in `/Applications` for the proper Mac architecture |
| 9 | +- Includes required security validation of the Developer ID authority and the Team Identifier for the `.app` |
| 10 | +- Includes optional checks to confirm versions and bundle IDs match between the two `.app` bundles (default) |
| 11 | + - Can be disabled for titles with differing versions between architectures |
| 12 | + |
| 13 | +### Background |
| 14 | +- With Apple's hardware transition from Intel processors to Apple silicon in Mac computers, most vendors have rewritten their software to run natively on this new architecture |
| 15 | +- Numerous vendors have rewritten their apps to be **Universal**, capable of running on either Intel or Apple silicon chips |
| 16 | + - These Universal titles are straightforward to deploy, since the app will run on any modern Mac, regardless of processor type |
| 17 | +- Others have opted to release architecture-specific installs, either capable of running on a Mac with Apple silicon, or an Intel-based Mac, *but not both* |
| 18 | + - This introduces added complexity for MacAdmins with mixed fleets |
| 19 | + - They must scope the correct architecture type to be delivered to the proper chipset for their Mac computers |
| 20 | + - Alternatively, they can install the Intel `.app` on all Macs in their environment |
| 21 | + - With translation of the `.app` via Rosetta 2, it will typically run on Apple silicon, but deliver subpar performance and extra power consumption relative to the native `.app` |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +- In short, this project aims to: |
| 26 | + - Enable users of any technical ability to easily create a deployable Universal package for apps that do not publish Universal binaries |
| 27 | + - Given download URLs for two `.zip` or `.dmg` files both containing a `.app` |
| 28 | + - Using tools that ship with any version of macOS |
| 29 | + - That can be deployed en masse via any macOS software distribution tool |
| 30 | + - Providing an easy method to bundle and distribute separate architecture installs with reduced complexity |
| 31 | + |
| 32 | +## USAGE |
| 33 | +`/bin/zsh /path/to/create_universal_package.zsh` |
| 34 | + |
| 35 | +- Can be run with the following flags |
| 36 | + - `--help`: displays help with usage instructions and exits |
| 37 | + - `--nomatch`: disables the requirement that version + bundle IDs must match across the `.app` bundles |
| 38 | + - If flag is set, the version associated with the built `.pkg` will be that of the Apple silicon `.app` |
| 39 | + - `--verbose`: runs the script with `set -x`, delivering very verbose output during execution |
| 40 | + |
| 41 | +- Values can be hardcoded prior to script execution, or entered interactively if left blank |
| 42 | + - See [Required Values](#Required-Values) below for more information |
| 43 | + |
| 44 | +### Required Values |
| 45 | +- `application_name` |
| 46 | + - Name of the app |
| 47 | + - Used to name the constructed Universal PKG |
| 48 | + - Used to name the (optionally created) dedicated script, directly invocable in the future to build a Universal package for the desired title |
| 49 | +- `apple_download` |
| 50 | + - URL download location to a `.zip` or `.dmg` containing a `.app` built for Apple silicon (`arm64`) |
| 51 | + - Code will validate application bundle sourced from `apple_download` will run natively on Apple silicon hardware |
| 52 | +- `intel_download` |
| 53 | + - URL download location to a `.zip` or `.dmg` containing a `.app` built for Intel arch (`x86_64`) |
| 54 | + - Code will validate application bundle sourced from `intel_download` will run natively on Intel-based hardware |
| 55 | +- `dev_id_authority` |
| 56 | + - Used to validate security of the Developer ID Authority matches the downloaded `.app` bundles |
| 57 | + - Can be identified/populated by running the below against the desired .app |
| 58 | + - `/usr/bin/codesign -dvv "/Applications/EXAMPLE.app" 2>&1 | /usr/bin/grep "Developer ID Application" | /usr/bin/cut -d ':' -f2 | /usr/bin/xargs` |
| 59 | +- `team_identifier` |
| 60 | + - Used to validate security of the Team Identifier matches the downloaded `.app` bundles |
| 61 | + - Can be identified/populated by running the below against the desired .app |
| 62 | + - `/usr/bin/codesign -dvv "/Applications/EXAMPLE.app" 2>&1 | /usr/bin/grep "TeamIdentifier" | /usr/bin/cut -d '=' -f2` |
| 63 | +- `match_versions` |
| 64 | + - By default, package will only build if both Intel + Apple silicon `.app` bundles have identical versions and bundle identifiers |
| 65 | + - To disable this functionality, (e.g. for apps with differing version #s between archs), set this `false` |
| 66 | + - If set to `false`, the version associated with the built `.pkg` will be that of the Apple silicon `.app` |
| 67 | + |
| 68 | +### NOTE |
| 69 | +**Any or all of these values can be left blank and populated interactively when the script is run** |
| 70 | +- If either security variable is undefined, the script will run and report the `codesign` output from the downloaded `.app` bundles |
| 71 | + - If the source is trusted for the provided download, that value can be copied/pasted into the input prompt for Dev ID and/or Team ID |
| 72 | +- If at least one value is populated interactively, the program will offer to create a new script named with |
| 73 | + - `application_name_` as a prefix (e.g. `EXAMPLE_create_universal_package.zsh`) |
| 74 | + - The CLI inputted values written as hardcoded variable definitions in the new script |
| 75 | +- If a script prefixed with `application_name_` already exists in the same directory, the program will prompt to update any values provided interactively |
| 76 | +- This is to facilitate faster testing/construction of Universal packages for dedicated apps |
| 77 | + |
| 78 | +## PERMISSIONS |
| 79 | +- Group permissions for the `.app` copied into `/Applications` should not be modified from how they were originally set by the vendor |
| 80 | +- Owner permissions will be `root` due to package installation occurring with elevated permissions |
| 81 | + |
| 82 | +## CHANGELOG |
| 83 | +- (1.0.0) |
| 84 | + - Initial publication |
| 85 | + |
| 86 | +## CREDITS |
| 87 | +- This project takes inspiration from [AutoPkg](https://github.com/autopkg/autopkg) |
0 commit comments