평범해 보이던 기능 병합 이후 아카이브 결과물의 크기가 갑자기 10여 MB 늘었지만, 커밋 기록에는 대용량 이미지도 뚜렷한 신규 의존성도 없었다. 릴리스 직전에 IPA를 수동으로 확인하는 방식으로는 대개 문제가 이미 여러 브랜치에 섞인 뒤다. 더 안정적인 방법은 고정된 클라우드 Mac 빌드 환경에서 크기 기준선을 보관하고, 아카이브할 때마다 App, 메인 실행 파일, 동적 프레임워크를 자동으로 분리해 측정한 뒤 임계값을 넘으면 병합을 중단하는 것이다.
비교 가능한 측정 대상부터 정의하기
‘패키지 크기’에는 적어도 세 가지 기준이 있으며, 이를 하나의 추세선에 섞어서는 안 된다.
| 지표 | 측정 대상 | 주요 용도 |
|---|---|---|
| App 압축 해제 크기 | .xcarchive 안의 .app 디렉터리 |
리소스, 프레임워크, 현지화 파일의 증가 감지 |
| 메인 실행 파일 크기 | CFBundleExecutable이 가리키는 Mach-O 파일 |
코드, 정적 라이브러리, 심볼 변화 감지 |
| IPA 크기 | 내보낸 압축 파일 | 사용자가 실제로 다운로드하는 패키지의 추세 관찰 |
게이트는 앞의 두 항목을 중심으로 판단해야 한다. IPA 크기는 압축률과 파일 배치의 영향을 받으므로, 동일한 리소스 묶음에 작은 변화만 생겨도 압축 결과가 예상보다 커지거나 작아질 수 있다. 디버그 심볼은 아카이브의 dSYMs 디렉터리에 있으며 사용자 설치 패키지에는 포함되지 않지만, 이후 문제를 추적할 수 있도록 별도로 보관해야 한다.
빌드 조건이 동일해야 크기 차이에 의미를 부여할 수 있다. Xcode 경로, 구성, 대상 플랫폼, 내보내기 방식, 컴파일 옵션을 모두 고정해야 한다.
고정된 명령으로 아카이브 생성하기
먼저 깨끗한 작업 디렉터리에서 의존성을 해석한 다음, 실제 기기 대상을 위한 Release 아카이브를 생성한다. 작업공간 이름과 Scheme은 작업 매개변수로 전달해 프로젝트별 세부 사항이 스크립트에 하드코딩되지 않도록 한다.
set -euo pipefail
WORKSPACE="${WORKSPACE:?missing WORKSPACE}"
SCHEME="${SCHEME:?missing SCHEME}"
OUT="${OUT:-$PWD/build-size}"
ARCHIVE="$OUT/App.xcarchive"
rm -rf "$OUT"
mkdir -p "$OUT"
xcodebuild \
-workspace "$WORKSPACE" \
-scheme "$SCHEME" \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath "$ARCHIVE" \
clean archive \
CODE_SIGNING_ALLOWED=NO
프로젝트의 아카이브 단계에서 서명 관련 스크립트를 반드시 실행해야 한다면 서명을 억지로 비활성화하지 말고, 프로젝트에서 원래 사용하던 통제된 구성을 적용해야 한다. 게이트의 목적은 ‘정식 빌드와 동일한 조건’을 유지하는 것이지, 모든 저장소에 통용되는 명령 하나를 만드는 것이 아니다. 처음 도입할 때는 Release 구성에 테스트 리소스, 진단 라이브러리 또는 개발 서버 주소가 잘못 포함되지 않았는지도 확인해야 한다.
App, 실행 파일, 프레임워크 분리 측정하기
다음 스크립트는 아카이브에서 유일한 App을 찾아 메인 실행 파일 이름을 읽고, 기계가 파싱할 수 있는 TSV를 출력한다. du -sk는 디렉터리 사용량을 지속적으로 비교하는 데 적합하며, stat은 메인 실행 파일의 정확한 바이트 수를 구하는 데 사용한다.
set -euo pipefail
ARCHIVE="${1:?usage: measure.sh path/to/App.xcarchive}"
APP_ROOT="$ARCHIVE/Products/Applications"
APP_PATH="$(find "$APP_ROOT" -maxdepth 1 -type d -name '*.app' -print -quit)"
test -n "$APP_PATH"
EXECUTABLE="$(/usr/libexec/PlistBuddy \
-c 'Print :CFBundleExecutable' "$APP_PATH/Info.plist")"
printf "kind name bytes
"
APP_KB="$(du -sk "$APP_PATH" | awk '{print $1}')"
printf "app %s %s
" "$(basename "$APP_PATH")" "$((APP_KB * 1024))"
printf "executable %s %s
" "$EXECUTABLE" \
"$(stat -f '%z' "$APP_PATH/$EXECUTABLE")"
FRAMEWORKS="$APP_PATH/Frameworks"
if test -d "$FRAMEWORKS"; then
find "$FRAMEWORKS" -maxdepth 1 -type d -name '*.framework' -print0 |
while IFS= read -r -d '' item; do
kb="$(du -sk "$item" | awk '{print $1}')"
printf "framework %s %s
" "$(basename "$item")" "$((kb * 1024))"
done
fi
보고서는 총합 하나만 출력하는 데 그치지 말고 이번 빌드의 결과물로 보관해야 한다. 크기 회귀가 발생하면 검토자는 증가 원인이 메인 실행 파일인지, 특정 프레임워크인지, 아니면 App 디렉터리 전체의 리소스인지 바로 판단할 수 있다.
리소스 디렉터리 더 세분화하기
App 전체 크기는 늘었지만 메인 실행 파일과 프레임워크가 안정적이라면 Assets.car, 현지화 디렉터리, 오프라인 데이터 파일, 미디어 리소스에 각각 stat 또는 du를 실행할 수 있다. 중복으로 보이는 파일을 바로 삭제해서는 안 된다. 먼저 서로 다른 target, 온디맨드 리소스 규칙 또는 현지화 과정에서 생성된 파일인지 확인해야 한다.
이중 임계값으로 오탐 줄이기
비율만 사용하면 작은 구성 요소가 지나치게 민감해지고, 고정 바이트 수만 사용하면 대형 App의 지속적인 증가를 놓칠 수 있다. 허용 증가량은 다음과 같이 정의할 수 있다.
allowed = max(8 MiB, baseline_app_bytes × 3%)
failed = current_app_bytes - baseline_app_bytes > allowed
여기서 8 MiB와 3%는 도입 시 사용할 초기값일 뿐, 모든 프로젝트에 적용되는 기준은 아니다. 정상 아카이브의 변동 폭을 여러 차례 기록한 뒤 프로젝트에 맞게 조정해야 한다. 메인 실행 파일과 개별 프레임워크에는 더 작은 독립 임계값을 적용해야 한다. 그렇지 않으면 새로 추가된 의존성이 App 전체 크기에 가려질 수 있다.
기준선 파일은 소스 코드와 함께 검토하되, 실패한 작업이 자동으로 덮어쓰게 해서는 안 된다. 합리적인 절차는 작업이 차이를 출력하고, 개발자가 원인을 설명하며, 검토자가 변경이 요구사항에 부합하는지 확인한 뒤, 마지막으로 동일한 변경 안에서 기준선을 갱신하는 것이다. 그래야 ‘증가를 승인한 경우’와 ‘검사를 통과하려고 숫자를 초기화한 경우’를 구분할 수 있다.
비정상적인 크기 증가 원인 조사하기
메인 실행 파일이 커졌다면 정적 의존성, 제네릭 인스턴스화, 중복 링크, 컴파일 조건부터 확인한다. 프레임워크가 커졌다면 의존성 버전과 임베드 방식을 점검하고, 리소스가 늘었다면 원본 이미지, 글꼴, 오디오·비디오 파일, 중복된 현지화 콘텐츠를 확인한다.
다음 네 가지 흔한 실수도 피해야 한다.
- 서로 다른 Xcode 환경에서 생성한 결과를 직접 비교한다.
- 시뮬레이터 빌드와 실제 기기 아카이브를 섞어 사용한다.
- 전체 크기만 저장하고 구성 요소별 세부 정보와 커밋 식별자는 보관하지 않는다.
- 게이트가 실패하면 임계값을 자동으로 높이거나 기준선을 덮어쓴다.
최종 보고서에는 최소한 커밋 식별자, 아카이브 구성, App 전체 크기, 메인 실행 파일 크기, 크기가 가장 큰 프레임워크 몇 개, 기준선 대비 증가량, 판정 결과가 포함되어야 한다. 게이트를 통과한 뒤에도 보고서를 보관해야 느리지만 지속적인 증가 추세를 관찰할 수 있다. 게이트가 실패하면 아카이브와 세부 내역을 보존해 동일한 환경에서 다시 확인해야 하며, 개발자가 로컬에서 재빌드한 결과에 의존해서는 안 된다.
자주 묻는 질문
최종 IPA 파일 크기만 비교하면 안 되는 이유는 무엇인가요?
IPA는 압축 파일이므로 리소스 내용과 파일 순서에 따라 크기가 달라질 수 있습니다. 압축 전 앱 디렉터리와 주 실행 파일을 핵심 지표로 사용하고 IPA는 보조 지표로 다루는 편이 안정적입니다.
앱 크기 회귀 임계값은 어떻게 정해야 하나요?
여러 정상 빌드의 변동 폭을 먼저 기록한 뒤 절대 증가량과 상대 증가율을 함께 적용해야 합니다. 예시의 8 MiB와 3%는 시작값이며 프로젝트 기록에 맞게 조정해야 합니다.
의존성 업데이트로 크기가 증가하면 기준선을 바로 바꿔도 되나요?
먼저 추가된 코드와 리소스가 의도된 변경인지 검토해야 합니다. 증가 원인과 승인 내용을 변경 기록에 남긴 뒤 해당 변경과 함께 기준선을 갱신하는 것이 안전합니다.
다음 iOS 빌드를 MiniDebug M4에서 실행하세요.
M4, 16GB RAM, 256GB SSD를 기본으로 제공하며 일·주·월·분기 단위로 대여할 수 있습니다. 싱가포르, 일본 도쿄, 한국 서울, 홍콩, 미국 동부 등 5개 노드 중에서 선택하세요. 실제 이용 가능 여부는 콘솔에서 실시간으로 확인할 수 있습니다.