CI/CD macOS Application Bundling .app Artifacts

CI/CD macOS Application Bundling .app Artifacts

1. macOS Application Bundle Structure

1.1 The .app Bundle Format

In macOS, applications are distributed as bundles, a directory structure that contains executable code and related resources. Here's the typical structure of a .app bundle:

MyApp.app/
  Contents/
    Info.plist
    MacOS/
      MyApp
    Resources/
      MyApp.icns
  • Info.plist: Metadata and configuration information.
  • MacOS/: Main executable file.
  • Resources/: Stores resource files, such as images and localized content.
1.2 Understanding the Info.plist File

A .app bundle is really just a directory. The Info.plist file is critical to the .app bundle as it is what defines how to use this folder as a launcher instead of a folder. It contains key-value pairs that macOS uses to index the application. Key elements include:

  • CFBundleExecutable: Specifies the main executable file.
  • CFBundleIconFile: Defines the icon file.

Here's an example snippet:

<dict>
    <key>CFBundleExecutable</key>
    <string>MyApp</string>
    <key>CFBundleIconFile</key>
    <string>MyApp.icns</string>
</dict>

2. ICNS Conversion

macOS uses the ICNS file format for icons. A convenient conversion tool is png-to-icns-right-click-converter. This tool allows for seamless conversion from PNG to ICNS, suitable for inclusion in the application bundle's Resources directory.

3. CI/CD Integration

3.1 YAML Configuration for Packaging macOS Application

Continuous Integration and Continuous Deployment (CI/CD) streamline the development workflow. Below is a YAML script that demonstrates how to package a macOS application binary:

pack_macos_app:
    stage: package_stage
    dependencies:
        - build_stage
    script:
        - INFO_PLIST="$APP_NAME.app/Contents/Info.plist"
        - echo "Packing self-contained build for macOS x64..."
        - mkdir -p $APP_NAME.app/Contents/MacOS
        - mkdir -p $APP_NAME.app/Contents/Resources
        - cp Resources/Icons/icon.icns $APP_NAME.app/Contents/Resources/
        - cp $BUILD_DIR/$BINARY_NAME $APP_NAME.app/Contents/MacOS/
        - chmod +x $APP_NAME.app/Contents/MacOS/$BINARY_NAME
        - echo '<?xml version="1.0" encoding="UTF-8"?>' > $INFO_PLIST
        - echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >> $INFO_PLIST
        - echo '<plist version="1.0">' >> $INFO_PLIST
        - echo '<dict>' >> $INFO_PLIST
        - echo '    <key>CFBundleExecutable</key>' >> $INFO_PLIST
        - echo "    <string>$BINARY_NAME</string>" >> $INFO_PLIST
        - echo '    <key>CFBundleIconFile</key>' >> $INFO_PLIST
        - echo '    <string>icon.icns</string>' >> $INFO_PLIST
        - echo '</dict>' >> $INFO_PLIST
        - echo '</plist>' >> $INFO_PLIST
    artifacts:
        name: "macOS x64 (self-contained)"
        paths:
            - $BUILD_DIR/$APP_NAME.app
        expire_in: 1 week

TL;DR

macOS applications rely on a bundle structure, where an application is organized as a directory with the .app extension. This structure includes executable code, resources, and metadata, all defined within specific subdirectories and files such as .plist and ICNS icon files. Understanding these aspects allows developers to create CI/CD bundling stages for any macOS app.