아카이브 작업은 성공으로 표시되지만 파이프라인이 -exportArchive 단계에서 종료되는 경우, 마지막 줄의 “export failed” 메시지에 현혹되기 쉽습니다. 실제 원인은 내보내기 방식과 서명 자산의 불일치, 아카이브 내부 권한 변경 또는 CI가 다른 Xcode를 호출한 데 있을 수 있습니다. 효과적인 대응 방법은 파이프라인을 반복해서 다시 실행하는 것이 아니라 동일한 xcarchive를 보존하고, 아카이브·내보내기·진단 과정을 각각 독립적으로 재현할 수 있는 단계로 분리하는 것입니다.
먼저 실패 현장 보존하기
실패 직후 작업 디렉터리를 정리하거나 기존 아카이브를 덮어쓰지 마세요. 최소한 xcarchive, 실제 사용한 ExportOptions.plist, 전체 표준 출력, Xcode 경로와 버전을 보존해야 합니다. RunnerVM의 전용 물리 노드는 이러한 실패 현장을 유지하기에 적합하지만, 파이프라인에서도 진단 파일을 작업 산출물 디렉터리로 명시적으로 복사해야 합니다.
set -euo pipefail
RUN_DIR="$PWD/export-diagnostics"
ARCHIVE_PATH="$PWD/build/App.xcarchive"
mkdir -p "$RUN_DIR"
xcode-select -p > "$RUN_DIR/xcode-path.txt"
xcodebuild -version > "$RUN_DIR/xcode-version.txt"
sw_vers > "$RUN_DIR/macos-version.txt"
cp ExportOptions.plist "$RUN_DIR/ExportOptions.plist"
ditto "$ARCHIVE_PATH" "$RUN_DIR/App.xcarchive"
아카이브 파일의 체크섬도 함께 기록하세요. 이후 누군가 아카이브를 교체하면 조사 대상이 달라졌다는 사실을 즉시 확인할 수 있습니다.
ditto -c -k --keepParent "$ARCHIVE_PATH" "$RUN_DIR/App.xcarchive.zip"
shasum -a 256 "$RUN_DIR/App.xcarchive.zip" > "$RUN_DIR/checksums.txt"
내보내기 실패가 곧 아카이브 손상을 의미하지는 않습니다. 먼저 아카이브가 온전한지 확인한 다음, 문제가 아카이브 단계에 있는지 배포 단계에 있는지 판단해야 합니다.
아카이브가 내보내기 조건을 충족하는지 확인하기
xcarchive는 본질적으로 디렉터리입니다. 먼저 메타데이터, 앱 번들, 실행 파일이 모두 존재하는지 확인한 뒤 아카이브에 선언된 앱 식별자와 버전을 읽어야 합니다. 프로젝트 이름을 기준으로 경로를 조합하지 말고 Info.plist에서 가져오세요.
INFO="$ARCHIVE_PATH/Info.plist"
APP_RELATIVE=$(/usr/libexec/PlistBuddy -c \
"Print :ApplicationProperties:ApplicationPath" "$INFO")
APP_PATH="$ARCHIVE_PATH/Products/$APP_RELATIVE"
plutil -lint "$INFO"
test -d "$APP_PATH"
test -f "$APP_PATH/Info.plist"
plutil -p "$INFO"
plutil -p "$APP_PATH/Info.plist"
codesign --verify --deep --strict --verbose=2 "$APP_PATH"
ApplicationPath, CFBundleIdentifier, 버전 번호, 서명 검증 결과를 중점적으로 확인하세요. 앱 번들이 아예 없거나 codesign --verify가 이미 실패한다면 내보내기 옵션을 계속 수정할 것이 아니라 archive 명령, 빌드 단계 스크립트 또는 산출물 복사 절차를 점검해야 합니다.
앱 권한과 프로비저닝 프로파일 비교하기
내보내기 단계에서는 서명 관계가 다시 평가됩니다. 앱에 실제로 적용된 권한과 내장 프로비저닝 프로파일을 각각 추출한 뒤 구조적으로 비교할 수 있습니다.
codesign -d --entitlements "$RUN_DIR/app-entitlements.plist" "$APP_PATH"
PROFILE="$APP_PATH/embedded.mobileprovision"
security cms -D -i "$PROFILE" > "$RUN_DIR/profile.plist"
plutil -extract Entitlements xml1 \
-o "$RUN_DIR/profile-entitlements.plist" \
"$RUN_DIR/profile.plist"
plutil -p "$RUN_DIR/app-entitlements.plist"
plutil -p "$RUN_DIR/profile-entitlements.plist"
파일의 텍스트 순서만 비교해서는 안 됩니다. 앱이 사용하는 권한을 프로비저닝 프로파일이 허용하는지, 앱 식별자와 팀 식별자, 환경별 권한이 일치하는지 확인해야 합니다. 기본 앱이 검증을 통과했다고 해서 내장된 모든 구성 요소를 내보낼 수 있는 것은 아니므로 각 확장 타깃도 하나씩 점검하세요.
ExportOptions.plist 검증하기
먼저 plutil -lint ExportOptions.plist를 실행해 형식 오류를 배제한 다음, 현재 Xcode의 도움말 출력에서 사용할 수 있는 키와 값을 확인하세요. 버전에 따라 method의 허용 값이 바뀌거나 기존 표기법이 폐기될 수 있으므로 과거 작업의 설정을 복사해 바로 실행해서는 안 됩니다.
최소 설정에는 현재 배포 절차에 실제로 필요한 필드만 포함할 수 있습니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>development</string>
<key>signingStyle</key>
<string>manual</string>
<key>stripSwiftSymbols</key>
<true/>
</dict>
</plist>
여기서 사용한 method는 개발용 내보내기의 예시일 뿐이며 다른 배포 대상에 그대로 적용하면 안 됩니다. 먼저 다음 명령을 실행하고 현재 도구 체인이 제공하는 설명을 기준으로 설정하세요.
plutil -lint ExportOptions.plist
xcodebuild -help > export-help.txt
grep -A 120 "Available keys for -exportOptionsPlist" export-help.txt
수동 서명을 사용한다면 설정의 매핑이 기본 앱과 모든 확장을 포함하는지도 확인해야 합니다. 누락된 매핑, 잘못된 식별자 또는 서명 방식 혼용은 대개 내보내기 단계에서야 드러납니다.
내보내기를 별도로 재현하고 전체 로그 보존하기
아카이브가 유효하다는 사실을 확인했다면 고정된 절대 경로를 사용해 내보내기만 별도로 실행하세요. 실패 시 스크립트가 임시 디렉터리를 즉시 삭제하지 않도록 해야 합니다.
set +e
xcodebuild -exportArchive \
-archivePath "$ARCHIVE_PATH" \
-exportPath "$RUN_DIR/exported" \
-exportOptionsPlist "$RUN_DIR/ExportOptions.plist" \
2>&1 | tee "$RUN_DIR/export.log"
STATUS=${PIPESTATUS[0]}
set -e
printf '%s
' "$STATUS" > "$RUN_DIR/export-status.txt"
exit "$STATUS"
로그에서는 마지막 요약 메시지가 아니라 가장 먼저 나타난 구체적인 오류를 찾아야 합니다. 서명, 프로비저닝 프로파일, 권한, 내보내기 방식을 기준으로 다음과 같이 1차 필터링할 수 있습니다.
grep -Ein \
"error:|provision|entitlement|certificate|signing|export" \
"$RUN_DIR/export.log" > "$RUN_DIR/export-errors.txt" || true
xcodebuild가 출력에 배포 로그 번들의 경로를 표시하는 경우가 있습니다. 해당 디렉터리 전체를 아카이브하세요. 여기에는 일반적으로 IDEDistribution 절차의 단계별 판단 내용이 담겨 있어, 파이프라인이 잘라낸 몇 줄의 오류보다 근본 원인에 가까운 정보를 제공합니다.
수정 후 인수 검사 목록 만들기
수정 후에는 종료 코드만으로 성공 여부를 판단하지 마세요. 최소한 내보내기 디렉터리에 대상 파일이 존재하는지, 서명 검증을 통과하는지, 앱 식별자와 버전이 아카이브와 일치하는지 확인해야 합니다. 최종 ExportOptions.plist와 Xcode 버전도 함께 보관하세요.
다음 검사를 작업 마지막 단계의 체크리스트로 고정하는 것이 좋습니다.
- 압축한 아카이브의 체크섬이 변경되지 않았습니다.
- 현재
xcode-select -p가 예상한 도구 체인과 일치합니다. - 기본 앱과 모든 확장이 서명 검증을 통과합니다.
- 앱 권한이 프로비저닝 프로파일에서 허용한 범위를 벗어나지 않습니다.
- 내보내기 설정이
plutil검사를 통과하고, 해당 키와 값을 현재 Xcode가 지원합니다. - 내보내기 로그, 배포 로그 번들, 최종 산출물이 같은 작업 단위로 보존됩니다.
- 수정 사항은 하나의 변수만 변경하며 기존 아카이브에서 반복 검증할 수 있습니다.
이와 같이 처리하면 아카이브 내보내기는 더 이상 원인을 설명하기 어려운 일회성 블랙박스 작업이 아닙니다. 팀은 도구 체인 변경, 설정 오류, 서명 관계 이상, 아카이브 손상을 명확히 구분하고, 다시 빌드하지 않고도 대부분의 수정 사항을 검증할 수 있습니다.
자주 묻는 질문
아카이브는 성공했지만 내보내기가 실패하면 바로 다시 빌드해야 하나요?
아닙니다. 기존 xcarchive의 메타데이터, 앱 번들, 내장 프로파일과 권한을 먼저 보존하고 확인해야 합니다. 다시 빌드하면 실패 당시의 증거가 사라질 수 있습니다.
ExportOptions.plist를 여러 Xcode 버전에서 그대로 사용해도 되나요?
검증 없이 재사용하면 안 됩니다. 현재 선택된 Xcode의 xcodebuild 도움말에서 지원되는 method 값과 옵션을 확인하고 plist 문법도 함께 검사해야 합니다.
다음 빌드를 독점 물리 Mac에서 실행하세요
작업 주기에 맞는 클라우드 Mac 노드를 선택하고, 콘솔에서 주문, 연결 정보 및 지원 요청을 관리하세요.