| 1 |
|
| 2 |
set -euo pipefail |
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
cd "$(dirname "$0")/.." |
| 21 |
|
| 22 |
|
| 23 |
|
| 24 |
|
| 25 |
|
| 26 |
|
| 27 |
|
| 28 |
API_KEY_ID="${APPLE_API_KEY_ID:?set APPLE_API_KEY_ID -- source ~/.tauri/passwords.env}" |
| 29 |
API_ISSUER_ID="${APPLE_API_ISSUER_ID:?set APPLE_API_ISSUER_ID -- source ~/.tauri/passwords.env}" |
| 30 |
API_KEY_PATH="${APPLE_API_KEY_PATH:?set APPLE_API_KEY_PATH -- source ~/.tauri/passwords.env}" |
| 31 |
ARCHIVE_PATH="src-tauri/gen/apple/build/goingson-desktop_iOS.xcarchive" |
| 32 |
EXPORT_DIR="dist/ios" |
| 33 |
EXPORT_PLIST="src-tauri/gen/apple/ExportOptions.plist" |
| 34 |
PROJECT_YML="src-tauri/gen/apple/project.yml" |
| 35 |
|
| 36 |
|
| 37 |
BUILD=true |
| 38 |
UPLOAD=true |
| 39 |
for arg in "$@"; do |
| 40 |
case "$arg" in |
| 41 |
--build-only) UPLOAD=false ;; |
| 42 |
--upload-only) BUILD=false ;; |
| 43 |
-h|--help) |
| 44 |
echo "Usage: $0 [--build-only | --upload-only]" |
| 45 |
exit 0 |
| 46 |
;; |
| 47 |
esac |
| 48 |
done |
| 49 |
|
| 50 |
|
| 51 |
VERSION=$(python3 -c "import json; print(json.load(open('src-tauri/tauri.conf.json'))['version'])") |
| 52 |
echo "Version: $VERSION" |
| 53 |
|
| 54 |
|
| 55 |
if grep -q "CFBundleShortVersionString:" "$PROJECT_YML"; then |
| 56 |
sed -i '' "s/CFBundleShortVersionString: .*/CFBundleShortVersionString: $VERSION/" "$PROJECT_YML" |
| 57 |
sed -i '' "s/CFBundleVersion: .*/CFBundleVersion: \"$VERSION\"/" "$PROJECT_YML" |
| 58 |
echo "Synced version $VERSION to $PROJECT_YML" |
| 59 |
fi |
| 60 |
|
| 61 |
|
| 62 |
if [ ! -f "$API_KEY_PATH" ]; then |
| 63 |
echo "Error: API key not found at $API_KEY_PATH" |
| 64 |
echo "Set APPLE_API_KEY_PATH to the correct path" |
| 65 |
exit 1 |
| 66 |
fi |
| 67 |
|
| 68 |
|
| 69 |
|
| 70 |
|
| 71 |
|
| 72 |
|
| 73 |
|
| 74 |
ICON_SVG="media/logo-go-icon.svg" |
| 75 |
ICON_OUT="src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset" |
| 76 |
ICON_TMP="$(mktemp -t goingson-icon-XXXXXX).png" |
| 77 |
if [ "$BUILD" = true ] && [ -f "$ICON_SVG" ] && [ -d "$ICON_OUT" ]; then |
| 78 |
echo "" |
| 79 |
echo "=== Flattening app icons (no alpha) ===" |
| 80 |
magick -background white -density 600 "$ICON_SVG" \ |
| 81 |
-resize 1024x1024 -alpha remove -alpha off "$ICON_TMP" |
| 82 |
icon_pairs=( |
| 83 |
"AppIcon-20x20@1x.png:20" "AppIcon-20x20@2x.png:40" |
| 84 |
"AppIcon-20x20@2x-1.png:40" "AppIcon-20x20@3x.png:60" |
| 85 |
"AppIcon-29x29@1x.png:29" "AppIcon-29x29@2x.png:58" |
| 86 |
"AppIcon-29x29@2x-1.png:58" "AppIcon-29x29@3x.png:87" |
| 87 |
"AppIcon-40x40@1x.png:40" "AppIcon-40x40@2x.png:80" |
| 88 |
"AppIcon-40x40@2x-1.png:80" "AppIcon-40x40@3x.png:120" |
| 89 |
"AppIcon-60x60@2x.png:120" "AppIcon-60x60@3x.png:180" |
| 90 |
"AppIcon-76x76@1x.png:76" "AppIcon-76x76@2x.png:152" |
| 91 |
"AppIcon-83.5x83.5@2x.png:167" "AppIcon-512@2x.png:1024" |
| 92 |
) |
| 93 |
for p in "${icon_pairs[@]}"; do |
| 94 |
name="${p%:*}"; size="${p#*:}" |
| 95 |
magick "$ICON_TMP" -resize "${size}x${size}" \ |
| 96 |
-background white -alpha remove -alpha off "$ICON_OUT/$name" |
| 97 |
done |
| 98 |
rm -f "$ICON_TMP" |
| 99 |
echo "Flattened 18 icons from $ICON_SVG" |
| 100 |
fi |
| 101 |
|
| 102 |
|
| 103 |
if [ "$BUILD" = true ]; then |
| 104 |
echo "" |
| 105 |
echo "=== Building iOS release archive ===" |
| 106 |
APPLE_API_KEY_PATH="$API_KEY_PATH" cargo tauri ios build --export-method app-store-connect |
| 107 |
echo "Archive: $ARCHIVE_PATH" |
| 108 |
fi |
| 109 |
|
| 110 |
|
| 111 |
if [ "$UPLOAD" = true ]; then |
| 112 |
mkdir -p "$EXPORT_DIR" |
| 113 |
|
| 114 |
|
| 115 |
|
| 116 |
IPA_PATH=$(find "$EXPORT_DIR" src-tauri/gen/apple/build \ |
| 117 |
-name "*.ipa" -type f 2>/dev/null \ |
| 118 |
-exec stat -f '%m %N' {} \; \ |
| 119 |
| sort -rn | head -1 | cut -d' ' -f2- || true) |
| 120 |
|
| 121 |
|
| 122 |
|
| 123 |
if [ -z "$IPA_PATH" ] || [ "$ARCHIVE_PATH" -nt "$IPA_PATH" ]; then |
| 124 |
echo "" |
| 125 |
echo "=== Exporting IPA from archive ===" |
| 126 |
xcodebuild -exportArchive \ |
| 127 |
-archivePath "$ARCHIVE_PATH" \ |
| 128 |
-exportOptionsPlist "$EXPORT_PLIST" \ |
| 129 |
-exportPath "$EXPORT_DIR" \ |
| 130 |
-allowProvisioningUpdates \ |
| 131 |
-authenticationKeyID "$API_KEY_ID" \ |
| 132 |
-authenticationKeyPath "$API_KEY_PATH" \ |
| 133 |
-authenticationKeyIssuerID "$API_ISSUER_ID" |
| 134 |
IPA_PATH=$(find "$EXPORT_DIR" -name "*.ipa" -type f \ |
| 135 |
-exec stat -f '%m %N' {} \; \ |
| 136 |
| sort -rn | head -1 | cut -d' ' -f2- || true) |
| 137 |
fi |
| 138 |
|
| 139 |
if [ -z "$IPA_PATH" ]; then |
| 140 |
echo "Error: No IPA found after export" |
| 141 |
exit 1 |
| 142 |
fi |
| 143 |
|
| 144 |
echo "" |
| 145 |
echo "=== Uploading to TestFlight ===" |
| 146 |
echo "IPA: $IPA_PATH" |
| 147 |
|
| 148 |
|
| 149 |
set +e |
| 150 |
UPLOAD_OUTPUT=$(xcrun altool --upload-app \ |
| 151 |
--type ios \ |
| 152 |
--file "$IPA_PATH" \ |
| 153 |
--apiKey "$API_KEY_ID" \ |
| 154 |
--apiIssuer "$API_ISSUER_ID" 2>&1) |
| 155 |
UPLOAD_RC=$? |
| 156 |
set -e |
| 157 |
echo "$UPLOAD_OUTPUT" |
| 158 |
|
| 159 |
if [ $UPLOAD_RC -ne 0 ] || ! grep -q "UPLOAD SUCCEEDED" <<<"$UPLOAD_OUTPUT"; then |
| 160 |
echo "" |
| 161 |
echo "Error: altool upload failed (exit=$UPLOAD_RC). See output above." |
| 162 |
exit 1 |
| 163 |
fi |
| 164 |
|
| 165 |
echo "" |
| 166 |
echo "Upload complete! Build will appear in TestFlight within ~30 minutes." |
| 167 |
echo "https://appstoreconnect.apple.com/apps" |
| 168 |
fi |
| 169 |
|
| 170 |
echo "" |
| 171 |
echo "Done. GoingsOn iOS v$VERSION" |
| 172 |
|