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:
2026-01-22 20:38:28 +09:00
parent a30b4c1ac2
commit c26e09e90b
3 changed files with 210 additions and 7 deletions

View File

@@ -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 repos 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/"
```
---

View File

@@ -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"

View 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\""