The App Store only accepts a watch-only app inside an empty iOS stub (watchapp2-container), the pair Xcode's Watch-only App template makes. The stub takes org.gbrown.wristcode; the watch app, and so the APNs topic, becomes org.gbrown.wristcode.watchkitapp. Adds ITSAppUsesNonExemptEncryption = NO and scripts/testflight.sh, which archives with API key automatic signing and a timestamp build number, then exports and uploads (or exports only with --no-upload). Co-Authored-By: Claude Opus 5.5 <[email protected]>
90 lines
2.6 KiB
Bash
Executable File
90 lines
2.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# Archive WristCode and upload it to App Store Connect for TestFlight.
|
|
#
|
|
# scripts/testflight.sh archive, then export and upload
|
|
# scripts/testflight.sh --no-upload archive, then export an .ipa to build/export without uploading
|
|
#
|
|
# BUILD_NUMBER defaults to a timestamp so every upload is unique. The App Store Connect API key comes
|
|
# from ASC_KEY_PATH, ASC_KEY_ID and ASC_ISSUER_ID.
|
|
set -euo pipefail
|
|
|
|
upload=1
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--no-upload) upload=0 ;;
|
|
*) echo "usage: $0 [--no-upload]" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
TEAM_ID="${TEAM_ID:-GQJNM5YK2M}"
|
|
ASC_KEY_ID="${ASC_KEY_ID:-864GCL5SDC}"
|
|
ASC_ISSUER_ID="${ASC_ISSUER_ID:-af37ae36-1f23-4245-b220-a7dc56d1a724}"
|
|
ASC_KEY_PATH="${ASC_KEY_PATH:-$HOME/.appstoreconnect/private_keys/AuthKey_${ASC_KEY_ID}.p8}"
|
|
BUILD_NUMBER="${BUILD_NUMBER:-$(date +%Y%m%d%H%M)}"
|
|
|
|
build_dir="build"
|
|
archive_path="$build_dir/WristCode-$BUILD_NUMBER.xcarchive"
|
|
export_path="$build_dir/export-$BUILD_NUMBER"
|
|
export_options="$build_dir/ExportOptions.plist"
|
|
|
|
auth=(
|
|
-allowProvisioningUpdates
|
|
-authenticationKeyPath "$ASC_KEY_PATH"
|
|
-authenticationKeyID "$ASC_KEY_ID"
|
|
-authenticationKeyIssuerID "$ASC_ISSUER_ID"
|
|
)
|
|
|
|
if [[ ! -f "$ASC_KEY_PATH" ]]; then
|
|
echo "App Store Connect API key not found at $ASC_KEY_PATH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
xcodegen generate
|
|
mkdir -p "$build_dir"
|
|
|
|
echo "Archiving build $BUILD_NUMBER to $archive_path"
|
|
xcodebuild archive \
|
|
-project WristCode.xcodeproj \
|
|
-scheme WristCode \
|
|
-destination 'generic/platform=watchOS' \
|
|
-archivePath "$archive_path" \
|
|
"${auth[@]}" \
|
|
CURRENT_PROJECT_VERSION="$BUILD_NUMBER"
|
|
|
|
if (( upload )); then destination=upload; else destination=export; fi
|
|
cat > "$export_options" <<PLIST
|
|
<?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>method</key>
|
|
<string>app-store-connect</string>
|
|
<key>destination</key>
|
|
<string>$destination</string>
|
|
<key>teamID</key>
|
|
<string>$TEAM_ID</string>
|
|
<key>signingStyle</key>
|
|
<string>automatic</string>
|
|
<key>uploadSymbols</key>
|
|
<true/>
|
|
<key>manageAppVersionAndBuildNumber</key>
|
|
<false/>
|
|
</dict>
|
|
</plist>
|
|
PLIST
|
|
|
|
echo "Exporting ($destination) to $export_path"
|
|
xcodebuild -exportArchive \
|
|
-archivePath "$archive_path" \
|
|
-exportPath "$export_path" \
|
|
-exportOptionsPlist "$export_options" \
|
|
"${auth[@]}"
|
|
|
|
if (( upload )); then
|
|
echo "Uploaded build $BUILD_NUMBER. It appears in TestFlight once App Store Connect finishes processing."
|
|
else
|
|
echo "Exported build $BUILD_NUMBER to $export_path"
|
|
fi
|