Skip to content

Instantly share code, notes, and snippets.

@ggand0
Last active May 10, 2025 07:35
Show Gist options
  • Select an option

  • Save ggand0/0f6c266a999cf9b03f9ca560352c2bb0 to your computer and use it in GitHub Desktop.

Select an option

Save ggand0/0f6c266a999cf9b03f9ca560352c2bb0 to your computer and use it in GitHub Desktop.
Automates bundling, signing, packaging, and uploading a macOS .app (built with Rust) to App Store Connect using Transporter.
#!/bin/bash
set -euo pipefail
# Constants — change as needed
APP_NAME="<YOUR APP NAME>"
BINARY_NAME="<YOUR BINARY NAME>"
BUNDLE_ID="<com.yourorgname.appname>"
VERSION_SHORT="0.1.0"
TEAM_ID="<TEAM ID>"
DEV_NAME="3rd Party Mac Developer Application: <YOUR NAME> ($TEAM_ID)"
INSTALLER_NAME="3rd Party Mac Developer Installer: <YOUR NAME> ($TEAM_ID)"
PROV_PROFILE="viewskater_provision_profile.provisionprofile"
ENTITLEMENTS="entitlements.plist"
EMAIL="<YOUR EMAIL>"
APP_PASSWORD="<APP SPECIFIC PASSWORD>"
APPLE_ID="<YOUR_APPLE_ID>"
# Directories
BUILD_DIR="target/release/bundle/osx"
APP_PATH="$BUILD_DIR/$APP_NAME.app"
PKG_PATH="$BUILD_DIR/$APP_NAME.pkg"
ITMSP_DIR="$BUILD_DIR/$APP_NAME.itmsp"
INFO_PLIST_LOCAL="Info.plist"
METADATA_XML="$ITMSP_DIR/metadata.xml"
# Step 1: Bundle app
cargo bundle --release
# Step 2: Generate build number (timestamp)
BUILD_NUMBER=$(date +"%Y%m%d.%H%M%S")
# Step 3: Update Info.plist with build number
cp "$INFO_PLIST_LOCAL" "$APP_PATH/Contents/Info.plist"
plutil -replace CFBundleVersion -string "$BUILD_NUMBER" "$APP_PATH/Contents/Info.plist"
plutil -replace CFBundleShortVersionString -string "$VERSION_SHORT" "$APP_PATH/Contents/Info.plist"
# Step 4: Embed provisioning profile
cp "$PROV_PROFILE" "$APP_PATH/Contents/embedded.provisionprofile"
# Step 5: Remove quarantine attribute
xattr -cr "$APP_PATH"
# Step 6: Code sign
codesign --deep --force --options runtime \
--entitlements "$ENTITLEMENTS" \
--sign "$DEV_NAME" \
"$APP_PATH"
# Step 7: Create .pkg
productbuild --component "$APP_PATH" /Applications \
--sign "$INSTALLER_NAME" \
"$PKG_PATH"
# Step 8: Prepare .itmsp dir
mkdir -p "$ITMSP_DIR"
cp "$PKG_PATH" "$ITMSP_DIR"
# Step 9: Calculate size and md5
SIZE=$(stat -f%z "$PKG_PATH")
MD5=$(md5 -q "$PKG_PATH")
# Step 10: Update metadata.xml
cat > "$METADATA_XML" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://apple.com/itunes/importer" version="software5.10">
<software_assets apple_id="$APPLE_ID" app_platform="osx">
<asset type="product-archive">
<data_file>
<file_name>$APP_NAME.pkg</file_name>
<size>$SIZE</size>
<checksum type="md5">$MD5</checksum>
</data_file>
</asset>
</software_assets>
</package>
EOF
# Step 11: Upload to TestFlight
/Applications/Transporter.app/Contents/itms/bin/iTMSTransporter \
-m upload \
-f "$ITMSP_DIR" \
-u "$EMAIL" \
-p "$APP_PASSWORD"
echo "✅ Upload complete! Build number: $BUILD_NUMBER"
@ggand0
Copy link
Author

ggand0 commented May 10, 2025

For full context and step-by-step explanation, see the blog post: https://ggando.com/blog/rust-appstore/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment