엔지니어링 아티클

클라우드 Mac에서 actool로 iOS 에셋 카탈로그 사전 검사하기

클라우드 Mac에서 actool로 iOS 에셋 카탈로그 사전 검사하기

아이콘 슬롯 하나가 빠진 문제도 전체 아카이브가 거의 끝날 때까지 드러나지 않는 경우가 많습니다. 클라우드 Mac에서 실행되는 iOS 파이프라인이라면 의존성 해석, 소스 코드 컴파일, 테스트에 이미 시간을 쓴 뒤 Assets.xcassets의 메타데이터 오류 하나 때문에 최종 실패하게 됩니다. 더 효율적인 방법은 Xcode가 내부적으로 호출하는 actool을 별도의 사전 검사 단계로 분리해 에셋 문제를 파이프라인 초반에 차단하는 것입니다.

actool 사전 검사의 범위

actool은 Asset Catalog를 읽고 플랫폼, 배포 대상, 기기 유형에 맞춰 리소스를 컴파일합니다. 이를 별도로 실행하면 잘못된 Contents.json, 파일이 누락된 이미지 슬롯, 인식할 수 없는 속성, 중복된 이름, AppIcon과 대상 플랫폼의 불일치 등을 발견할 수 있습니다.

다만 전체 빌드를 대체할 수는 없습니다. 소스 코드가 존재하지 않는 리소스 이름을 참조하는 문제, target마다 서로 다른 Asset Catalog를 사용하는 구성, 빌드 설정에서 AppIcon 이름을 재정의하는 경우 등은 여전히 xcodebuild 단계에서만 드러날 수 있습니다. 권장하는 파이프라인 순서는 다음과 같습니다.

단계 검사 항목 실패 비용
JSON 구문 검사 Contents.json 파싱 가능 여부 가장 낮음
actool 사전 검사 리소스 구조와 플랫폼 매개변수 낮음
Xcode 빌드 target, 소스 코드 참조, 링크 높음
테스트 및 아카이브 실행 동작과 배포 산출물 가장 높음

사전 검사의 목적은 Xcode 전체를 모사하는 것이 아니라, 결과가 명확하고 수정 경로가 분명한 리소스 오류를 최대한 일찍 차단하는 데 있습니다.

도구 체인과 입력 매개변수 고정하기

먼저 현재 작업이 실제로 어떤 Xcode를 호출하는지 확인합니다. 대화형 터미널과 CI 프로세스가 동일한 개발자 디렉터리를 사용한다고 가정해서는 안 됩니다.

xcode-select -p
xcodebuild -version
xcrun --find actool
xcrun actool --version

팀에서 노드 하나에 여러 Xcode 버전을 유지한다면 작업 진입점에서 DEVELOPER_DIR을 명시적으로 설정하고, xcodebuild -version 결과를 빌드 로그에 남겨야 합니다. 스크립트의 플랫폼, 최소 시스템 버전, 기기 유형, AppIcon 이름도 프로젝트 빌드 설정과 일치해야 합니다. 그렇지 않으면 사전 검사를 통과하더라도 다른 매개변수 조합에서 컴파일이 가능하다는 의미일 뿐, 실제 target이 정상이라는 근거가 되지 않습니다.

actool을 실행하기 전에 디렉터리 안의 JSON을 한 번 더 간단히 검사합니다.

find App/Assets.xcassets -name Contents.json -print0 |
while IFS= read -r -d '' file; do
  plutil -lint "$file"
done

이 단계에서는 병합 충돌 흔적, 파일 끝의 불필요한 문자, 손상된 파일을 정확한 경로 단위로 찾아낼 수 있습니다.

CI에서 바로 실행할 수 있는 스크립트 작성하기

아래 스크립트는 출력을 .ci-artifacts/actool에 고정하고, 실패 시 전체 진단 정보를 보존해 CI가 첨부 파일로 수집할 수 있게 합니다. 디렉터리, 배포 대상, AppIcon 이름은 매개변수나 프로젝트 설정을 통해 전달해야 하며, 같은 스크립트를 여러 벌 복사해 따로 관리해서는 안 됩니다.

#!/bin/bash
set -euo pipefail

CATALOG="${1:-App/Assets.xcassets}"
DEPLOYMENT_TARGET="${DEPLOYMENT_TARGET:-16.0}"
APP_ICON_NAME="${APP_ICON_NAME:-AppIcon}"
OUT=".ci-artifacts/actool"

rm -rf "$OUT"
mkdir -p "$OUT/compiled"
export LANG=en_US.UTF-8

if ! xcrun actool "$CATALOG" \
  --compile "$OUT/compiled" \
  --platform iphoneos \
  --minimum-deployment-target "$DEPLOYMENT_TARGET" \
  --target-device iphone \
  --app-icon "$APP_ICON_NAME" \
  --output-partial-info-plist "$OUT/partial-info.plist" \
  --notices --warnings --errors \
  >"$OUT/actool.log" 2>&1; then
  cat "$OUT/actool.log"
  exit 1
fi

cat "$OUT/actool.log"
plutil -lint "$OUT/partial-info.plist"

set -euo pipefail을 사용하면 명령이 실패한 뒤에도 파이프라인이 계속 실행되는 상황을 방지할 수 있습니다. 로그를 먼저 파일에 기록한 다음 출력하는 이유는 종료 코드와 진단 내용을 모두 보존하기 위해서입니다. 명령을 곧바로 복잡한 파이프에 연결하면 마지막 명령의 상태를 잘못 가져오기 쉽습니다.

경고와 일반적인 오탐 처리하기

모든 경고를 즉시 실패로 처리하지 않기

오래된 프로젝트에는 기기별 appearance가 지정되지 않은 항목, 사용하지 않는 이미지 세트, 이름 관련 안내 등이 누적돼 있을 수 있습니다. 처음 도입할 때는 로그를 저장하고 기준선을 만든 뒤, 결과가 명확한 문제부터 차단해야 합니다. warning:이 포함된 모든 줄을 곧바로 실패 처리하면 팀은 리소스를 수정하기보다 검사를 먼저 비활성화할 가능성이 큽니다.

잘못된 JSON, 누락된 리소스 파일, AppIcon의 필수 슬롯 누락, 중복된 이름은 즉시 차단하는 것이 좋습니다. 사용하지 않는 리소스 등의 안내는 우선 개수를 기록하고 정리 기한을 정한 뒤 규칙을 강화합니다.

시뮬레이터와 실제 기기 플랫폼 구분하기

iphonesimulator만 사용한 사전 검사가 통과했다고 해서 iphoneos에서도 반드시 통과하는 것은 아닙니다. 기기 요구 사항, 아이콘 규칙, 산출물 형식의 차이로 서로 다른 진단이 발생할 수 있습니다. 파이프라인에서 두 유형의 target을 모두 빌드한다면 검사를 각각 실행하고 출력 디렉터리도 분리해, 뒤의 실행 결과가 앞의 결과를 덮어쓰지 않도록 해야 합니다.

iPad target이 포함되어 있다면 해당하는 --target-device ipad도 추가해야 합니다. 검사를 통과시키기 위해 iphone만 선언해서는 안 되며, 기기 집합은 target의 실제 설정을 따라야 합니다.

파이프라인 연동 및 결과 검증

actool은 일반적으로 Xcode와 저장소 안의 리소스에만 의존하므로, 사전 검사를 의존성 설치 뒤에 배치할 필요가 없습니다. 더 적절한 위치는 코드 체크아웃이 끝난 직후이자 의존성 해석 전입니다. 이렇게 하면 패키지 관리 서비스가 일시적으로 느려도 리소스 오류를 빠르게 확인할 수 있습니다.

처음 적용할 때는 세 가지 오류 샘플을 준비할 수 있습니다. Contents.json 하나를 손상시키고, 참조 중인 아이콘 파일 하나를 임시로 옮기고, AppIcon 이름을 존재하지 않는 값으로 변경합니다. 각 작업이 0이 아닌 상태로 종료되고, 로그에 구체적인 디렉터리가 표시되며, 시스템이 .ci-artifacts/actool을 보존하는지 확인합니다. 그런 다음 파일을 복원하고 사전 검사와 전체 빌드가 모두 통과하는지 다시 검증합니다.

저장소에 여러 애플리케이션 target이 있다면 “target, 리소스 디렉터리, 플랫폼, AppIcon 이름” 목록을 관리하면서 항목별로 순회해야 합니다. 모든 디렉터리를 한 명령에 한꺼번에 전달해서는 안 됩니다. 그래야 실패 정보를 담당 모듈과 바로 연결할 수 있고, 특정 target의 매개변수가 다른 target의 문제를 가리는 상황도 방지할 수 있습니다.

최종적으로는 두 단계의 게이트를 유지합니다. actool은 리소스 디렉터리의 명확한 오류를 빠르게 찾고, 전체 Xcode 빌드는 target 통합과 최종 산출물을 검증합니다. 두 단계의 역할을 명확히 나누면 리소스 문제가 더 일찍 드러나고, 실패 로그도 실제 수정 지점에 더 가까워집니다.

자주 묻는 질문

actool 사전 검사가 전체 Xcode 빌드를 대신할 수 있나요?

아닙니다. 에셋과 실행 인자 오류는 먼저 찾을 수 있지만 최종 결과는 배포에 사용하는 스킴, SDK, 구성으로 다시 빌드해야 합니다.

모든 actool 경고를 CI 실패로 처리해야 하나요?

처음부터 모두 차단하지 않는 편이 좋습니다. 기존 경고를 분류한 뒤 잘못된 JSON, 필수 아이콘 누락, 중복 이름처럼 확정적인 오류부터 차단합니다.

OwnAMac 클라우드 Mac

다음 빌드를 독점 Apple Silicon 물리 노드에서 실행하세요

작업 규모에 따라 세 가지 구성과 다섯 개 노드 중에서 선택할 수 있으며, 컴퓨팅과 스토리지는 다른 테넌트와 공유되지 않습니다. 모든 노드는 연중 365일 정상 운영되며, 실제 사용 가능 상태는 콘솔의 실시간 응답을 기준으로 합니다.

구성 선택 및 주문