publish-ios.sh (4687B)
1 #!/bin/bash 2 set -euo pipefail 3 4 REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" 5 SECRETS="$REPO_ROOT/.asc/secrets.sh" 6 7 if [[ ! -f "$SECRETS" ]]; then 8 echo "Error: $SECRETS not found. See Scripts/secrets.sh.example for the required format." 9 exit 1 10 fi 11 12 source "$SECRETS" 13 14 SCHEME="Crossmate" 15 # Archive into the Xcode Archives library at a unique per-build path so 16 # Organizer indexes every build and TestFlight crashes symbolicate 17 # automatically. A fixed/volatile path (e.g. /tmp) makes each publish 18 # overwrite the previous build's dSYM, leaving superseded builds' crashes 19 # permanently unsymbolicatable. One timestamp drives both the date dir 20 # and the archive name so they can't disagree across a midnight boundary. 21 ARCHIVE_STAMP="$(date '+%Y-%m-%d %H.%M.%S')" 22 ARCHIVE_DIR="$HOME/Library/Developer/Xcode/Archives/${ARCHIVE_STAMP%% *}" 23 ARCHIVE_PATH="$ARCHIVE_DIR/$SCHEME $ARCHIVE_STAMP.xcarchive" 24 EXPORT_PATH="/tmp/Crossmate-export" 25 EXPORT_PLIST="/tmp/Crossmate-ExportOptions.plist" 26 IPA_PATH="$EXPORT_PATH/Crossmate.ipa" 27 DEV_P12="$REPO_ROOT/.asc/dev.p12" 28 DIST_P12="$REPO_ROOT/.asc/ios-signing/dist-headless.p12" 29 TMP_KEYCHAIN="$REPO_ROOT/.asc/build.keychain-db" 30 31 CHECK_ONLY=false 32 if [[ "${1:-}" == "--check" ]]; then 33 CHECK_ONLY=true 34 fi 35 36 cd "$REPO_ROOT" 37 38 if ! git diff --quiet || ! git diff --cached --quiet; then 39 echo "Error: Git repository is dirty. Commit or stash changes before publishing." 40 exit 1 41 fi 42 43 echo "==> Setting up temporary keychain..." 44 security delete-keychain "$TMP_KEYCHAIN" 2>/dev/null || true 45 security create-keychain -p "$TMP_KEYCHAIN_PASS" "$TMP_KEYCHAIN" 46 security unlock-keychain -p "$TMP_KEYCHAIN_PASS" "$TMP_KEYCHAIN" 47 security set-keychain-settings -lut 21600 "$TMP_KEYCHAIN" 48 security import "$DEV_P12" -k "$TMP_KEYCHAIN" -P "$DEV_P12_PASS" \ 49 -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild 50 security import "$DIST_P12" -k "$TMP_KEYCHAIN" -P "$DIST_P12_PASS" \ 51 -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild 52 security set-key-partition-list -S apple-tool:,apple:,codesign:,productbuild: \ 53 -s -k "$TMP_KEYCHAIN_PASS" "$TMP_KEYCHAIN" 54 security list-keychains -d user -s "$TMP_KEYCHAIN" ~/Library/Keychains/login.keychain-db 55 56 cleanup_keychain() { 57 echo "==> Restoring keychain search list..." 58 security list-keychains -d user -s ~/Library/Keychains/login.keychain-db 59 security default-keychain -d user -s ~/Library/Keychains/login.keychain-db 60 security delete-keychain "$TMP_KEYCHAIN" 2>/dev/null || true 61 rm -f "$REPO_ROOT/private_keys/AuthKey_${KEY_ID}.p8" 62 rmdir "$REPO_ROOT/private_keys" 2>/dev/null || true 63 } 64 trap cleanup_keychain EXIT 65 66 mkdir -p "$ARCHIVE_DIR" 67 echo "==> Archiving $SCHEME to $ARCHIVE_PATH..." 68 xcodebuild \ 69 -scheme "$SCHEME" \ 70 -project Crossmate.xcodeproj \ 71 -configuration Release \ 72 -destination 'generic/platform=iOS' \ 73 -archivePath "$ARCHIVE_PATH" \ 74 archive 75 76 echo "==> Writing export options..." 77 cat > "$EXPORT_PLIST" <<PLIST 78 <?xml version="1.0" encoding="UTF-8"?> 79 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 80 "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 81 <plist version="1.0"> 82 <dict> 83 <key>method</key> 84 <string>app-store-connect</string> 85 <key>signingStyle</key> 86 <string>manual</string> 87 <key>teamID</key> 88 <string>$TEAM_ID</string> 89 <key>signingCertificate</key> 90 <string>iPhone Distribution</string> 91 <key>provisioningProfiles</key> 92 <dict> 93 <key>net.inqk.crossmate</key> 94 <string>Crossmate iOS Distribution</string> 95 <key>net.inqk.crossmate.notificationservice</key> 96 <string>Crossmate Notification Service iOS Distribution</string> 97 </dict> 98 <key>destination</key> 99 <string>export</string> 100 <key>stripSwiftSymbols</key> 101 <true/> 102 <key>manageAppVersionAndBuildNumber</key> 103 <false/> 104 </dict> 105 </plist> 106 PLIST 107 108 echo "==> Exporting IPA..." 109 xcodebuild \ 110 -exportArchive \ 111 -archivePath "$ARCHIVE_PATH" \ 112 -exportPath "$EXPORT_PATH" \ 113 -exportOptionsPlist "$EXPORT_PLIST" 114 115 echo "==> Checking entitlements in exported IPA..." 116 CHECK_DIR="/tmp/Crossmate-ipa-check" 117 rm -rf "$CHECK_DIR" 118 unzip -q "$IPA_PATH" -d "$CHECK_DIR" 119 echo "--- iOS app entitlements ---" 120 codesign -d --entitlements - "$CHECK_DIR/Payload/Crossmate.app" 121 rm -rf "$CHECK_DIR" 122 123 if $CHECK_ONLY; then 124 echo "==> Check complete. Skipping upload." 125 exit 0 126 fi 127 128 echo "==> Uploading to App Store Connect..." 129 mkdir -p "$REPO_ROOT/private_keys" 130 cp "$REPO_ROOT/.asc/AuthKey_${KEY_ID}.p8" "$REPO_ROOT/private_keys/" 131 xcrun iTMSTransporter \ 132 -m upload \ 133 -assetFile "$IPA_PATH" \ 134 -apiKey "$KEY_ID" \ 135 -apiIssuer "$ISSUER_ID" \ 136 -v informational 137 138 echo "==> Done!"