Zum Inhalt

macos/scripts/build-app.sh

#!/usr/bin/env bash
#
# build-app.sh — package PerlinLiveWallpaper as a signed (and optionally
# notarized) .app bundle.
#
#   ./scripts/build-app.sh              build + assemble + Developer-ID sign
#   ./scripts/build-app.sh --notarize   …then notarize + staple
#
# Notarization needs a one-time keychain profile (no password is stored here):
#   xcrun notarytool store-credentials jkaindl \
#     --apple-id <you@example.com> --team-id U9X7M39R56 --password <app-specific-pw>
# Override the profile name with NOTARY_PROFILE=… if you used a different one.
#
set -euo pipefail
cd "$(dirname "$0")/.."   # -> macos/

APP_NAME="Perlin Live Wallpaper"
EXEC="PerlinLiveWallpaper"
SIGN_ID="${SIGN_ID:-Developer ID Application: Johannes Kaindl (U9X7M39R56)}"
NOTARY_PROFILE="${NOTARY_PROFILE:-jkaindl}"
BUILD_DIR=".build/release"
APP="dist/${APP_NAME}.app"

echo "==> swift build -c release"
swift build -c release

echo "==> assembling ${APP}"
rm -rf "$APP"
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources"
cp "$BUILD_DIR/$EXEC" "$APP/Contents/MacOS/$EXEC"
cp packaging/Info.plist "$APP/Contents/Info.plist"

# SwiftPM resource bundle (presets + bundled studio). -L follows the
# .build/release symlink; the bundle is required, so fail loudly if missing.
RES_BUNDLE="$(find -L "$BUILD_DIR" -maxdepth 1 -name '*.bundle' | head -1)"
if [ -z "$RES_BUNDLE" ]; then echo "ERROR: resource bundle not found in $BUILD_DIR" >&2; exit 1; fi
cp -R "$RES_BUNDLE" "$APP/Contents/Resources/"

# App icon from the studio art (best-effort; not required for notarization).
ICON_SRC="../assets/icon-512.png"
if command -v iconutil >/dev/null && [ -f "$ICON_SRC" ]; then
  ICONSET="dist/AppIcon.iconset"
  rm -rf "$ICONSET"; mkdir -p "$ICONSET"
  for n in "16:16x16" "32:16x16@2x" "32:32x32" "64:32x32@2x" "128:128x128" \
           "256:128x128@2x" "256:256x256" "512:256x256@2x" "512:512x512"; do
    px="${n%%:*}"; name="${n##*:}"
    sips -z "$px" "$px" "$ICON_SRC" --out "$ICONSET/icon_${name}.png" >/dev/null 2>&1 || true
  done
  iconutil -c icns "$ICONSET" -o "$APP/Contents/Resources/AppIcon.icns" 2>/dev/null \
    && echo "    icon: AppIcon.icns" || echo "    icon: skipped"
  rm -rf "$ICONSET"
fi

echo "==> codesign (Developer ID, hardened runtime)"
# The SwiftPM resource bundle is a plain data folder (no Info.plist, no Mach-O),
# so it is sealed as a resource by the app signature — not signed separately.
codesign --force --options runtime --timestamp --sign "$SIGN_ID" "$APP"
codesign --verify --strict --verbose=2 "$APP"

if [ "${1:-}" = "--notarize" ]; then
  echo "==> notarize (keychain profile: $NOTARY_PROFILE)"
  ZIP="dist/${EXEC}.zip"
  ditto -c -k --keepParent "$APP" "$ZIP"
  xcrun notarytool submit "$ZIP" --keychain-profile "$NOTARY_PROFILE" --wait
  echo "==> staple"
  xcrun stapler staple "$APP"
  xcrun stapler validate "$APP"
  rm -f "$ZIP"
  echo "==> notarized: $APP"
else
  echo "==> signed (not notarized): $APP"
  echo "    run with --notarize once the keychain profile exists (see header)."
fi