Enhance macOS provisioning profile handling in build scripts and documentation
This commit updates the check_signing_identities.sh script to search for provisioning profiles in multiple common directories, improving the detection process. Additionally, the README_MAS.md is updated to clarify where provisioning profiles are stored in newer Xcode versions and provides guidance on locating the correct profile for Mac App Store builds. This enhances the overall usability and clarity for developers working with macOS builds.
This commit is contained in:
@@ -103,9 +103,32 @@ In Apple Developer → **Profiles** → **+**:
|
||||
- Select the **Apple Distribution** certificate
|
||||
- Generate + Download
|
||||
|
||||
Install it by double-clicking it, or place it under:
|
||||
### Where the `.provisionprofile` ends up (newer Xcode/macOS)
|
||||
|
||||
`~/Library/MobileDevice/Provisioning Profiles/`
|
||||
Recent Xcode versions store “downloaded manual profiles” under:
|
||||
|
||||
- `~/Library/Developer/Xcode/UserData/Provisioning Profiles/`
|
||||
|
||||
Older tooling sometimes used:
|
||||
|
||||
- `~/Library/MobileDevice/Provisioning Profiles/`
|
||||
|
||||
This repo’s MAS build script does **not** require the profile to be in a specific folder — you can pass the path directly.
|
||||
|
||||
To locate and pick the right profile, use:
|
||||
|
||||
```bash
|
||||
./build_tools/macos/find_mas_provisioning_profile.sh --bundle-id com.dryark.strawberry
|
||||
```
|
||||
|
||||
### (Optional) Copy to the legacy folder
|
||||
|
||||
If some other tools expect the legacy folder, you can copy it there:
|
||||
|
||||
```bash
|
||||
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
|
||||
cp -f "/path/to/profile.provisionprofile" "$HOME/Library/MobileDevice/Provisioning Profiles/"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -137,10 +137,23 @@ EOF
|
||||
echo
|
||||
|
||||
echo "==> [$(ts)] Provisioning profiles (Mac App Store builds require one)"
|
||||
prof_dir="${HOME}/Library/MobileDevice/Provisioning Profiles"
|
||||
if [[ -d "${prof_dir}" ]]; then
|
||||
ls -la "${prof_dir}" | head -n 50
|
||||
else
|
||||
echo "(none found at '${prof_dir}')"
|
||||
prof_dirs=(
|
||||
"${HOME}/Library/Developer/Xcode/UserData/Provisioning Profiles"
|
||||
"${HOME}/Library/MobileDevice/Provisioning Profiles"
|
||||
)
|
||||
any_prof=0
|
||||
for prof_dir in "${prof_dirs[@]}"; do
|
||||
if [[ -d "${prof_dir}" ]]; then
|
||||
any_prof=1
|
||||
echo " ${prof_dir}"
|
||||
ls -la "${prof_dir}" | head -n 20
|
||||
echo
|
||||
fi
|
||||
done
|
||||
if [[ "$any_prof" -eq 0 ]]; then
|
||||
echo "(no provisioning profile directories found in common locations)"
|
||||
fi
|
||||
|
||||
echo "Tip: to pick the right MAS profile for a bundle id, run:"
|
||||
echo " ./build_tools/macos/find_mas_provisioning_profile.sh --bundle-id com.dryark.strawberry"
|
||||
|
||||
|
||||
167
build_tools/macos/find_mas_provisioning_profile.sh
Executable file
167
build_tools/macos/find_mas_provisioning_profile.sh
Executable file
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ts() { date +"%H:%M:%S"; }
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
./build_tools/macos/find_mas_provisioning_profile.sh --bundle-id com.dryark.strawberry
|
||||
|
||||
What it does:
|
||||
- Scans common macOS provisioning profile locations (new Xcode + legacy)
|
||||
- Decodes each *.provisionprofile (CMS) into plist
|
||||
- Prints a readable table and recommends a best match for the given bundle id
|
||||
|
||||
Notes:
|
||||
- A provisioning profile is required for Mac App Store signing.
|
||||
- This script only helps you *find* the right profile file.
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ "$(uname -s)" != "Darwin" ]]; then
|
||||
echo "Error: This script is for macOS only." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bundle_id=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--bundle-id) bundle_id="${2:-}"; shift 2 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "Unknown arg: $1" >&2; usage; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$bundle_id" ]]; then
|
||||
echo "Error: missing --bundle-id" >&2
|
||||
usage
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if ! command -v security >/dev/null 2>&1; then
|
||||
echo "Error: 'security' not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
plutil_extract() {
|
||||
local keypath="$1"
|
||||
local plist="$2"
|
||||
/usr/bin/plutil -extract "$keypath" raw -o - "$plist" 2>/dev/null || true
|
||||
}
|
||||
|
||||
find_profiles_in_dir() {
|
||||
local dir="$1"
|
||||
if [[ -d "$dir" ]]; then
|
||||
find "$dir" -maxdepth 1 -type f -name "*.provisionprofile" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
declare -a candidates
|
||||
candidates=()
|
||||
|
||||
# Newer Xcode location (as reported by user)
|
||||
while IFS= read -r f; do candidates+=("$f"); done < <(find_profiles_in_dir "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles")
|
||||
|
||||
# Legacy location
|
||||
while IFS= read -r f; do candidates+=("$f"); done < <(find_profiles_in_dir "$HOME/Library/MobileDevice/Provisioning Profiles")
|
||||
|
||||
if [[ ${#candidates[@]} -eq 0 ]]; then
|
||||
echo "==> [$(ts)] No .provisionprofile files found in common locations."
|
||||
echo "Checked:"
|
||||
echo " - $HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"
|
||||
echo " - $HOME/Library/MobileDevice/Provisioning Profiles"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> [$(ts)] Scanning ${#candidates[@]} provisioning profile(s) for bundle id: ${bundle_id}"
|
||||
echo
|
||||
|
||||
best_score=-1
|
||||
best_path=""
|
||||
best_reason=""
|
||||
|
||||
printf "%-4s %-36s %-10s %-25s %-40s %s\n" "No." "UUID" "TeamID" "Expires" "AppID" "Path"
|
||||
printf "%s\n" "---- ------------------------------------ ---------- ------------------------- ---------------------------------------- ----"
|
||||
|
||||
idx=0
|
||||
for f in "${candidates[@]}"; do
|
||||
idx=$((idx + 1))
|
||||
|
||||
tmp="$(mktemp -t strawberry-profile.XXXXXX.plist)"
|
||||
if ! security cms -D -i "$f" >"$tmp" 2>/dev/null; then
|
||||
rm -f "$tmp" >/dev/null 2>&1 || true
|
||||
continue
|
||||
fi
|
||||
|
||||
uuid="$(plutil_extract UUID "$tmp")"
|
||||
name="$(plutil_extract Name "$tmp")"
|
||||
teamid="$(plutil_extract 'TeamIdentifier.0' "$tmp")"
|
||||
exp="$(plutil_extract ExpirationDate "$tmp")"
|
||||
|
||||
# Profiles vary in which key they use for the app identifier.
|
||||
appid="$(plutil_extract 'Entitlements.application-identifier' "$tmp")"
|
||||
if [[ -z "$appid" ]]; then
|
||||
appid="$(plutil_extract 'Entitlements.com.apple.application-identifier' "$tmp")"
|
||||
fi
|
||||
|
||||
rm -f "$tmp" >/dev/null 2>&1 || true
|
||||
|
||||
# Fallbacks for display.
|
||||
[[ -z "$uuid" ]] && uuid="(unknown)"
|
||||
[[ -z "$teamid" ]] && teamid="(unknown)"
|
||||
[[ -z "$exp" ]] && exp="(unknown)"
|
||||
[[ -z "$appid" ]] && appid="(unknown)"
|
||||
|
||||
printf "%-4s %-36s %-10s %-25s %-40s %s\n" "$idx" "$uuid" "$teamid" "$exp" "$appid" "$f"
|
||||
|
||||
# Score match quality.
|
||||
score=0
|
||||
reason=""
|
||||
|
||||
# Prefer exact team+bundle match.
|
||||
if [[ "$appid" != "(unknown)" && "$teamid" != "(unknown)" ]]; then
|
||||
if [[ "$appid" == "${teamid}.${bundle_id}" ]]; then
|
||||
score=100
|
||||
reason="exact match (${appid})"
|
||||
elif [[ "$appid" == "${teamid}."* && "$appid" == *"*"* ]]; then
|
||||
# Wildcard profile like TEAMID.*
|
||||
score=60
|
||||
reason="wildcard match (${appid})"
|
||||
elif [[ "$appid" == *".${bundle_id}" ]]; then
|
||||
score=50
|
||||
reason="endswith match (${appid})"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Prefer profiles with a plausible name for MAS (heuristic).
|
||||
if [[ "$score" -gt 0 && -n "$name" ]]; then
|
||||
case "$name" in
|
||||
*Mac\ App\ Store*|*App\ Store*|*appstore*|*AppStore*)
|
||||
score=$((score + 5))
|
||||
reason="${reason}, name looks like MAS"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [[ "$score" -gt "$best_score" ]]; then
|
||||
best_score="$score"
|
||||
best_path="$f"
|
||||
best_reason="$reason"
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
if [[ "$best_score" -le 0 ]]; then
|
||||
echo "==> [$(ts)] Could not confidently auto-select a profile for ${bundle_id}."
|
||||
echo "Pick the profile whose AppID is TEAMID.${bundle_id} and is a macOS Mac App Store profile."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "==> [$(ts)] Recommended profile:"
|
||||
echo " $best_path"
|
||||
echo " reason: $best_reason"
|
||||
echo
|
||||
echo "Use it like:"
|
||||
echo " ./build_tools/macos/build_mas_pkg.sh --run ... --provisionprofile \"$best_path\""
|
||||
|
||||
Reference in New Issue
Block a user