iOS: release/dev/prov builds, publish.sh, dev icon variants

release = org.cdnutter.<name> (main, Gitea release + Sideload)
dev     = org.cdnutter.<name>-dev (dev branch, Gitea pre-release + Sideload Developer)
prov    = org.cdnutter.<name>-prov (personal signed, never published)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-11-10 10:18:32 -08:00
1 parent fabca5d1aa
commit ec1cbdfe75
9 files changed
+133 -59

No files matched your search

+36 -38
View File
@@ -1,23 +1,37 @@
#!/bin/bash
# Builds build/public/stemify-<version>.ipa on a Mac: ad-hoc signed, for releases and re-signing with Sideloadly/AltStore.
# With prov/Stemify.mobileprovision, prov/key.p12 and P12_PASS set, it also writes a signed
# build/prov/stemify-<version>-signed.ipa (keeps CarPlay/Siri) for the owner's own device.
# Finished IPAs are kept per version; build/work is scratch and is wiped each run.
# "build-ipa.sh dev" builds only build/dev/stemify-<version>-dev.ipa: bundle id org.cdnutter.stemify-dev,
# named "Stemify Dev", ad-hoc signed, so it installs next to the release app. For internal tests, never released.
# "build-ipa.sh prov" builds only the signed prov IPA (no public one).
# ios/scripts/build-remote.sh runs this on White-M1 and copies build/public and build/prov back to DevOps.
# 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-<v>.ipa org.cdnutter.stemify, ad-hoc signed. Gitea releases (main) + Sideload.
# build-ipa.sh dev build/dev/stemify-<v>-dev.ipa org.cdnutter.stemify-dev, "Stemify Dev", ribbon icon.
# Gitea pre-releases (dev branch) + Sideload Developer.
# build-ipa.sh prov build/prov/stemify-<v>-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:-release}
if [ "$MODE" = dev ]; then APP_ID=org.cdnutter.stemify-dev; APP_NAME="Stemify Dev"; APP_ICON=AppIconDev; DD=$B/dd-dev
else APP_ID=org.cdnutter.stemify; APP_NAME=Stemify; APP_ICON=AppIcon; DD=$B/dd; fi
rm -rf $OUT && mkdir -p $OUT/Payload $B/public $B/prov $B/dev
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 /-rc/; s/ /-/g')
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 \
@@ -25,30 +39,16 @@ xcodebuild -project Stemify.xcodeproj -scheme Stemify -configuration Release -sd
cp -R $DD/Build/Products/Release-iphoneos/Stemify.app $APP
[ -d $EXT ] || { echo "widget extension missing" >&2; exit 1; }
# Ad-hoc signature carrying only the App Group, so Sideloadly/AltStore keep the widgets' shared data when re-signing.
cat > $OUT/group.plist <<PL
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 <<PL
<?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>com.apple.security.application-groups</key><array><string>group.$APP_ID</string></array></dict></plist>
PL
codesign -f -s - --entitlements $OUT/group.plist $EXT
codesign -f -s - --entitlements $OUT/group.plist $APP
if [ "$MODE" = dev ]; then
rm -f $B/dev/stemify-$VERSION-dev.ipa
(cd $OUT && zip -qry ../dev/stemify-$VERSION-dev.ipa Payload)
echo "$B/dev/stemify-$VERSION-dev.ipa"
exit 0
fi
# Public build, for the releases and AltStore/Sideloadly.
if [ "$MODE" != prov ]; then
rm -f $B/public/stemify-$VERSION.ipa
(cd $OUT && zip -qry ../public/stemify-$VERSION.ipa Payload)
echo "$B/public/stemify-$VERSION.ipa"
fi
if [ -f prov/Stemify.mobileprovision ] && [ -f prov/key.p12 ] && [ -n "${P12_PASS:-}" ]; then
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
@@ -62,7 +62,6 @@ if [ -f prov/Stemify.mobileprovision ] && [ -f prov/key.p12 ] && [ -n "${P12_PAS
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
# The widgets need their own profile (org.cdnutter.stemify.widgets with the App Group). Without one they're left out.
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
@@ -75,9 +74,8 @@ if [ -f prov/Stemify.mobileprovision ] && [ -f prov/key.p12 ] && [ -n "${P12_PAS
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
# Personal build for this device only: stays in build/prov (gitignored), never released.
rm -f $B/prov/stemify-$VERSION-signed.ipa
(cd $OUT && zip -qry ../prov/stemify-$VERSION-signed.ipa Payload)
echo "$B/prov/stemify-$VERSION-signed.ipa (signed as $ID)"
fi
rm -f $IPA
(cd $OUT && zip -qry ../$MODE/$(basename $IPA) Payload)
echo "$IPA"