From d996d3e236b3f52b9a2e631b3a89bbda08dc1e85 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 9 Nov 2026 13:00:54 -0800 Subject: [PATCH] iOS: dev build variant (org.cdnutter.stemify-dev) for internal tests Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + ios/Shared/WidgetShared.swift | 2 +- ios/project.yml | 17 +++++++++++------ ios/scripts/build-ipa.sh | 20 ++++++++++++++++---- ios/scripts/build-remote.sh | 4 +++- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 721ffc0..1e8fefe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,3 +30,4 @@ 2026-11-06 iOS: crossfade, Off or 1-12 s in Settings > Listening. Equal-power fade, Sweet Fades skips it between songs of the same album. Seeking during a fade finishes it. 2026-11-09 iOS: iPhone Duo unfolded uses both sides of the hinge: library on one side, Now Playing docked on the other (no mini player while split). Folded and other iPhones unchanged. 1.0 RC 3 (build 23). 2026-11-09 iOS: Duo split now engages with the phone lying flat (hinge region reports inactive then), with a screen-size fallback if no region is reported. 1.0 RC 4 (build 24). +2026-11-09 iOS: dev builds (`ios/scripts/build-remote.sh dev`): bundle id org.cdnutter.stemify-dev, "Stemify Dev", own App Group, into ios/build/dev. Internal tests only, never on Gitea or Sideload. diff --git a/ios/Shared/WidgetShared.swift b/ios/Shared/WidgetShared.swift index 24a7e19..2509663 100644 --- a/ios/Shared/WidgetShared.swift +++ b/ios/Shared/WidgetShared.swift @@ -33,7 +33,7 @@ struct WidgetSnapshot: Codable, Equatable { } enum WidgetStore { - static let group = "group.org.cdnutter.stemify" + static let group = Bundle.main.object(forInfoDictionaryKey: "StemifyAppGroup") as? String ?? "group.org.cdnutter.stemify" static let mixerKind = "org.cdnutter.stemify.mixer" static let mixKind = "org.cdnutter.stemify.mix" static let controlKind = "org.cdnutter.stemify.mix-control" diff --git a/ios/project.yml b/ios/project.yml index 583c7bf..11c54ca 100644 --- a/ios/project.yml +++ b/ios/project.yml @@ -10,6 +10,9 @@ settings: MARKETING_VERSION: "1.0" VERSION_LABEL: "1.0 RC 4" CURRENT_PROJECT_VERSION: "24" + # Dev builds override these (build-ipa.sh dev) so they install next to the release app. + APP_ID: org.cdnutter.stemify + APP_NAME: Stemify targets: Stemify: type: application @@ -19,7 +22,7 @@ targets: - target: StemifyWidgets settings: base: - PRODUCT_BUNDLE_IDENTIFIER: org.cdnutter.stemify + PRODUCT_BUNDLE_IDENTIFIER: $(APP_ID) TARGETED_DEVICE_FAMILY: "1" ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon CODE_SIGN_ENTITLEMENTS: Stemify/Stemify.entitlements @@ -28,11 +31,12 @@ targets: properties: com.apple.developer.carplay-audio: true com.apple.developer.siri: true - com.apple.security.application-groups: [group.org.cdnutter.stemify] + com.apple.security.application-groups: [group.$(APP_ID)] info: path: Stemify/Info.plist properties: - CFBundleDisplayName: Stemify + CFBundleDisplayName: $(APP_NAME) + StemifyAppGroup: group.$(APP_ID) CFBundleShortVersionString: $(MARKETING_VERSION) CFBundleVersion: $(CURRENT_PROJECT_VERSION) StemifyVersionLabel: $(VERSION_LABEL) @@ -63,17 +67,18 @@ targets: sources: [Widgets, Shared] settings: base: - PRODUCT_BUNDLE_IDENTIFIER: org.cdnutter.stemify.widgets + PRODUCT_BUNDLE_IDENTIFIER: $(APP_ID).widgets TARGETED_DEVICE_FAMILY: "1" CODE_SIGN_ENTITLEMENTS: Widgets/StemifyWidgets.entitlements entitlements: path: Widgets/StemifyWidgets.entitlements properties: - com.apple.security.application-groups: [group.org.cdnutter.stemify] + com.apple.security.application-groups: [group.$(APP_ID)] info: path: Widgets/Info.plist properties: - CFBundleDisplayName: Stemify + CFBundleDisplayName: $(APP_NAME) + StemifyAppGroup: group.$(APP_ID) CFBundleShortVersionString: $(MARKETING_VERSION) CFBundleVersion: $(CURRENT_PROJECT_VERSION) NSExtension: diff --git a/ios/scripts/build-ipa.sh b/ios/scripts/build-ipa.sh index acaa617..a9b6170 100755 --- a/ios/scripts/build-ipa.sh +++ b/ios/scripts/build-ipa.sh @@ -3,31 +3,43 @@ # With prov/Stemify.mobileprovision, prov/key.p12 and P12_PASS set, it also writes a signed # build/prov/stemify--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--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. # ios/scripts/build-remote.sh runs this on White-M1 and copies build/public and build/prov back to DevOps. 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 -rm -rf $OUT && mkdir -p $OUT/Payload $B/public $B/prov +MODE=${1:-release} +if [ "$MODE" = dev ]; then APP_ID=org.cdnutter.stemify-dev; APP_NAME="Stemify Dev"; DD=$B/dd-dev +else APP_ID=org.cdnutter.stemify; APP_NAME=Stemify; DD=$B/dd; fi +rm -rf $OUT && mkdir -p $OUT/Payload $B/public $B/prov $B/dev # "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') # 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 $B/dd CODE_SIGNING_ALLOWED=NO -quiet build -cp -R $B/dd/Build/Products/Release-iphoneos/Stemify.app $APP + -destination generic/platform=iOS -derivedDataPath $DD APP_ID=$APP_ID APP_NAME="$APP_NAME" 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; } # 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.org.cdnutter.stemify +com.apple.security.application-groupsgroup.$APP_ID 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. rm -f $B/public/stemify-$VERSION.ipa (cd $OUT && zip -qry ../public/stemify-$VERSION.ipa Payload) diff --git a/ios/scripts/build-remote.sh b/ios/scripts/build-remote.sh index 1597d2a..67e3916 100755 --- a/ios/scripts/build-remote.sh +++ b/ios/scripts/build-remote.sh @@ -1,10 +1,12 @@ #!/bin/bash # Run from DevOps: syncs ios/ to White-M1, builds there, and pulls the IPAs back into ios/build/{public,prov}. +# "build-remote.sh dev" builds only the internal test IPA into ios/build/dev. set -euo pipefail cd "$(dirname "$0")/.." H=${BUILD_HOST:-white-m1}; R=stemify-build/ios rsync -a --exclude build --exclude prov --exclude Stemify.xcodeproj ./ $H:$R/ -ssh $H "cd $R && P12_PASS=\$(cat prov/cert_pass.txt 2>/dev/null) bash scripts/build-ipa.sh" +ssh $H "cd $R && P12_PASS=\$(cat prov/cert_pass.txt 2>/dev/null) bash scripts/build-ipa.sh ${1:-}" +if [ "${1:-}" = dev ]; then mkdir -p build/dev; rsync -a $H:$R/build/dev/ build/dev/; ls build/dev; exit 0; fi mkdir -p build/public build/prov rsync -a $H:$R/build/public/ build/public/ rsync -a $H:$R/build/prov/ build/prov/