#!/bin/bash # Builds one Stemify IPA on a Mac. ios/scripts/build-remote.sh runs this on WHITE-M1 from DevOps. # build-ipa.sh release build/release/stemify-.ipa org.cdnutter.stemify, ad-hoc signed. Gitea releases (main) + Sideload. # build-ipa.sh dev build/dev/stemify--dev.ipa org.cdnutter.stemify-dev, "Stemify Dev", ribbon icon. # Gitea pre-releases (dev branch) + Sideload Developer. # build-ipa.sh prov build/prov/stemify--prov.ipa org.cdnutter.stemify-prov, "Stemify Prov", signed with the # personal profile (CarPlay, Siri). Never published anywhere. # prov needs prov/Stemify.mobileprovision (App ID org.cdnutter.stemify-prov), prov/key.p12 and P12_PASS. # prov/StemifyWidgets.mobileprovision (org.cdnutter.stemify-prov.widgets) is optional, without it the widgets are left out. # build/work is scratch and is wiped each run. set -euo pipefail cd "$(dirname "$0")/.." export PATH=/opt/homebrew/bin:$PATH B=build; OUT=$B/work; APP=$OUT/Payload/Stemify.app; EXT=$APP/PlugIns/StemifyWidgets.appex MODE=${1:-dev} case $MODE in release) APP_ID=org.cdnutter.stemify; APP_NAME=Stemify; APP_ICON=AppIcon; SUFFIX= ;; dev) APP_ID=org.cdnutter.stemify-dev; APP_NAME="Stemify Dev"; APP_ICON=AppIconDev; SUFFIX=-dev ;; prov) APP_ID=org.cdnutter.stemify-prov; APP_NAME="Stemify Prov"; APP_ICON=AppIcon; SUFFIX=-prov ;; *) echo "usage: $0 release|dev|prov" >&2; exit 1 ;; esac DD=$B/dd-$MODE # "1.0 RC 1" -> 1.0-rc1, used in file names and release tags. VERSION=$(sed -nE 's/^ *VERSION_LABEL: "(.*)"/\1/p' project.yml | tr 'A-Z' 'a-z' | sed -E 's/ (rc|beta) /-\1/; s/ /-/g') IPA=$B/$MODE/stemify-$VERSION$SUFFIX.ipa if [ "$MODE" = prov ]; then for f in prov/Stemify.mobileprovision prov/key.p12; do [ -f $f ] || { echo "missing $f" >&2; exit 1; }; done [ -n "${P12_PASS:-}" ] || { echo "P12_PASS not set" >&2; exit 1; } PROF_ID=$(security cms -D -i prov/Stemify.mobileprovision | plutil -extract Entitlements.application-identifier raw -) [ "${PROF_ID#*.}" = "$APP_ID" ] || { echo "prov/Stemify.mobileprovision is for ${PROF_ID#*.}, need a profile for $APP_ID" >&2; exit 1; } fi rm -rf $OUT && mkdir -p $OUT/Payload $B/$MODE # xcodebuild compiles the app, the widget extension, the asset catalog and the App Intents metadata. xcodegen generate -q xcodebuild -project Stemify.xcodeproj -scheme Stemify -configuration Release -sdk iphoneos \ -destination generic/platform=iOS -derivedDataPath $DD APP_ID=$APP_ID APP_NAME="$APP_NAME" APP_ICON=$APP_ICON CODE_SIGNING_ALLOWED=NO -quiet build cp -R $DD/Build/Products/Release-iphoneos/Stemify.app $APP [ -d $EXT ] || { echo "widget extension missing" >&2; exit 1; } if [ "$MODE" != prov ]; then # Ad-hoc signature carrying only the App Group, so Sideloadly/AltStore keep the widgets' shared data when re-signing. cat > $OUT/group.plist < com.apple.security.application-groupsgroup.$APP_ID PL codesign -f -s - --entitlements $OUT/group.plist $EXT codesign -f -s - --entitlements $OUT/group.plist $APP else KC=$PWD/$OUT/sign.keychain-db; KP=$(uuidgen) security create-keychain -p "$KP" $KC security set-keychain-settings -lut 3600 $KC security unlock-keychain -p "$KP" $KC security import prov/key.p12 -P "$P12_PASS" -A -t agg -f pkcs12 -k $KC >/dev/null # The dev cert chains to Apple's WWDR G3 intermediate, which a fresh keychain doesn't have. [ -f prov/wwdr.cer ] || curl -fsSL -o prov/wwdr.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer security import prov/wwdr.cer -A -k $KC >/dev/null 2>&1 || true security set-key-partition-list -S apple-tool:,apple: -s -k "$KP" $KC >/dev/null security list-keychains -d user -s $KC $(security list-keychains -d user | tr -d '"') ID=$(security find-identity -v -p codesigning $KC | sed -nE 's/.*"(Apple Development:.*)"/\1/p' | head -1) security cms -D -i prov/Stemify.mobileprovision > $OUT/prov.plist /usr/libexec/PlistBuddy -x -c 'Print :Entitlements' $OUT/prov.plist > $OUT/ent.plist if [ -f prov/StemifyWidgets.mobileprovision ]; then security cms -D -i prov/StemifyWidgets.mobileprovision > $OUT/wprov.plist /usr/libexec/PlistBuddy -x -c 'Print :Entitlements' $OUT/wprov.plist > $OUT/went.plist cp prov/StemifyWidgets.mobileprovision $EXT/embedded.mobileprovision codesign -f -s "$ID" --entitlements $OUT/went.plist --timestamp=none $EXT else rm -rf $APP/PlugIns fi cp prov/Stemify.mobileprovision $APP/embedded.mobileprovision codesign -f -s "$ID" --entitlements $OUT/ent.plist --timestamp=none $APP security list-keychains -d user -s $(security list-keychains -d user | tr -d "\"" | grep -v sign.keychain) security delete-keychain $KC fi rm -f $IPA (cd $OUT && zip -qry ../$MODE/$(basename $IPA) Payload) echo "$IPA"