GeekNews에 공유된 scottwillsey 글을 보면, 한 iOS/macOS 개발자가 Xcode GUI를 거의 열지 않고도 앱을 빌드·서명·배포한 경험을 정리한다. 핵심은 Xcode.app 안에 들어 있는 CLI 도구들(xcodebuild, notarytool, stapler, devicectl)을 셸 스크립트로 묶고, project.yml(XcodeGen 설정) 하나로 프로젝트를 재현한다는 점이다.

흥미로운 점은 이 워크플로가 단순히 "Xcode 안 열기"가 아니라, LLM 코딩 에이전트(Claude Code 등)가 그대로 반복할 수 있는 수준으로 명세화됐다는 것이다. CLAUDE.md/AGENTS.md에 명령과 키체인 규칙을 적어두면, 사람이 개입하지 않아도 아카이브 → 공증 → 스테이플링 → Gatekeeper 검증 → /Applications 설치까지 자동으로 흐른다. 이 글은 그 명령 조각들을 그대로 보여주면서, 왜 CLI 도구 체인 전체(xcode-select로 Xcode.app 지정)가 필요한지, 그리고 CODE_SIGNING_ALLOWED=NO 임시 서명 빌드가 왜 배포용으로는 못 쓰이는지를 짚는다.
Metadata
- GeekNews HTML: https://news.hada.io/topic?id=31431
- GeekNews Markdown: https://news.hada.io/topic/31431.md
- Type: GN+
- Author: neo
- Published: 2026-07-14T14:40:39+09:00
- Updated: 2026-07-14T14:40:39+09:00
- Original source: scottwillsey.com
- Points: 2
- Comments: 1
- 초기 Apple 계정·인증서 설정을 마치면 Xcode.app 내부 CLI 도구만으로 Mac과 iOS 앱의 빌드, 서명, 배포를 자동화할 수 있음
project.yml에서 XcodeGen으로.xcodeproj를 재생성하고,xcodebuild,notarytool,stapler,devicectl로 프로젝트 생성부터 Mac 공증과 iPhone 설치까지 처리함- Mac 배포는
scripts/release.sh하나로 아카이브, Developer ID 서명, 공증, 티켓 스테이플링, Gatekeeper 검증,/Applications설치를 순서대로 실행하며 실패 시 즉시 중단됨 - 빠른 컴파일과 테스트에는
CODE_SIGNING_ALLOWED=NO를 사용할 수 있지만, 이 임시 서명 빌드는 Gatekeeper를 통과하지 못하고 iCloud KVS와 App Group 권한도 실제 팀 ID에 결합되지 않음 - 서명 개인 키와 공증 암호는 로그인 키체인에 보관하고,
CLAUDE.md또는AGENTS.md에 명령과 배포 규칙을 기록하면 Claude Code 같은 에이전트가 전체 워크플로를 반복 실행할 수 있음
Xcode GUI 없이 처리할 수 있는 범위
- Xcode 자체는 설치해야 하지만 실행할 필요는 없으며,
xcodebuild,notarytool,stapler,devicectl은 모두 Xcode.app 내부의 셸 도구로 독립 실행됨 - Apple ID 로그인, Developer ID 인증서 생성, 공증 암호 저장 같은 최초 설정에는 GUI 또는 대화형 터미널이 필요함
- 초기 설정을 끝내면 프로젝트 생성, 빌드, 아카이브, 서명된 앱 내보내기, 공증, 검증, 설치, 실제 iPhone 배포까지 마우스 없이 처리 가능함
- 설정이나 스크립트 작성이 막힐 때는 Claude Code 또는 다른 LLM 코딩 도구에 작업 요구사항과 프로젝트별 값을 제공해 워크플로를 만들 수 있음
전체 Xcode 도구 체인 선택
xcode-select -p의 결과가/Applications/Xcode.app/Contents/Developer인지 먼저 확인해야 함- 독립형 Command Line Tools가 선택돼 있다면 다음 명령으로 전체 Xcode 도구 체인을 지정함
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
xcode-select --install로 설치하는 /Library/Developer/CommandLineTools에는 clang과 git이 있지만, iOS SDK, notarytool, devicectl 등 전체 앱 개발 도구는 들어 있지 않음
- Xcode가 이미 설치돼 있다면 별도의 Command Line Tools 패키지는 필요하지 않음
- 라이선스 동의와 추가 구성요소 설치도 CLI에서 처리할 수 있음
sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch
XcodeGen으로 프로젝트 재현하기
- XcodeGen은 Xcode 프로젝트 설정을 YAML로 관리하고 빌드할 때마다
.xcodeproj를 다시 생성함
- GitHub에서 다운로드하거나 Homebrew로 설치할 수 있음
brew install xcodegen
.xcodeproj는 macOS에서 파일처럼 보이는 폴더이며, Xcode가 내부 파일과 참조를 계속 바꾸기 때문에 Git 저장소에서 충돌이나 불필요한 변경이 생길 수 있음
project.yml만 Git에 커밋하고 생성된 .xcodeproj는 무시하면 프로젝트 설정을 재현 가능한 상태로 유지할 수 있음
xcodegen generate
Apple 개발자 계정과 인증서 설정
- Xcode의
Settings → Accounts에서 Apple ID를 추가해야 함
- 앱 배포와 공증에는 유료 Apple Developer 계정이 필요함
Settings → Accounts → Apple ID → Manage Certificates… → + → Developer ID Application에서 배포용 인증서를 생성함
- Apple Development와 Developer ID Application은 용도가 다름
- Apple Development는 자신의 기기에서 실행하거나 iPhone으로 전송해 로컬 디버깅할 때 사용함
- Developer ID Application은 다른 사람의 Mac에서도 Gatekeeper를 통과하는 공증된
.app을 배포할 때 필요함
- Developer ID Application 인증서를 만들면 인증서와 대응하는 개인 키가 로그인 키체인에 설치됨
- 실제 서명에는 개인 키가 사용되며 다시 다운로드할 수 없으므로, 삭제하지 말고 키체인을 백업해야 함
공증 자격 증명을 키체인에 저장하기
- Mac 앱 공증은 서명된 앱을 Apple에 업로드해 악성 코드 검사를 받는 과정임
notarytool은 키체인에 저장된 프로필로 인증하며, 프로필을 처음 만들 때 앱 전용 암호를 대화형으로 입력해야 함
xcrun notarytool store-credentials App-Name \
--apple-id "you@example.com" \
--team-id YOUR-TEAM-ID
- 공증 프로필은 다른 앱의 것을 빌려 쓰지 말고 앱 이름에 맞춰 생성해야 다른 환경에서 조용히 실패하는 상황을 피할 수 있음
- 앱 전용 암호는 Apple ID 암호와 다르며, Apple ID 사이트의
Sign-In & Security → App-Specific Passwords에서 생성함
- Apple ID 암호를 바꾸면 앱 전용 암호가 별도 경고 없이 만료될 수 있음
- 공증 중
401 invalid credentials가 발생하면 설정 전체를 의심하기 전에 앱 전용 암호 만료부터 확인해야 함
- 프로필 저장 여부는 다음 명령으로 검증함
xcrun notarytool history --keychain-profile App-Name
- 앱 전용 암호를 Claude Code가 접근할 수 있는 1Password 보관함에 저장하면 새 앱의 공증 프로필 생성도 에이전트에 맡길 수 있음
--password로 암호 입력까지 자동화할 수 있지만 셸 기록에 암호가 남을 수 있으므로, 한 번 직접 입력한 뒤 키체인이나 1Password에 보관하는 방식을 사용함
로컬 서명 설정과 비밀 정보 분리
- 실제 서명에 필요한 팀 ID와 번들 접두사는
Local.xcconfig에 저장함
cp Local.xcconfig.example Local.xcconfig
BUNDLE_PREFIX = your.real.prefix
DEVELOPMENT_TEAM = YOUR-TEAM-ID
Local.xcconfig는 .gitignore에 추가해 프로젝트별 로컬 설정이 저장소에 들어가지 않도록 함
- 서명 개인 키는 로그인 키체인에, 공증용 앱 전용 암호는
notarytool 키체인 프로필에 남으므로 비밀 정보가 Git에 기록되지 않음
release.sh로 Mac 배포 자동화하기
- 저장소의
scripts/release.sh가 Mac 앱의 전체 배포 파이프라인을 한 명령으로 실행함
./scripts/release.sh
- 스크립트는 다음 순서로 동작함
1. xcodegen과 공증 프로필이 존재하는지 사전 확인
2. xcodegen generate로 프로젝트 재생성
3. xcodebuild archive로 Release 아카이브 생성
4. ExportOptions.plist와 xcodebuild -exportArchive로 Developer ID 서명 앱 내보내기
5. 앱을 ZIP으로 묶어 notarytool submit --wait로 Apple에 제출
6. stapler staple로 공증 티켓 부착
7. spctl로 Gatekeeper 허용 여부 검증
8. 기존 프로세스를 종료하고 앱을 /Applications에 복사
9. lsregister로 설치된 앱 등록
10. 설치된 번들의 티켓과 Gatekeeper 상태 재검증
- 모델이 일반적인 배포 절차를 알고 있더라도 스킴 이름, 팀 ID, 공증 프로필 이름, 설치 위치 같은 프로젝트별 정보는 사용자가 제공해야 함
- 첫 스크립트가 실패하면 실행 결과를 바탕으로 수정하는 반복 과정이 필요하지만, 워크플로가 안정된 뒤에는 별도 수정 없이 배포 명령만 실행할 수 있음
실패와 불완전한 배포 방지
set -euo pipefail은 명령 하나라도 실패하면 스크립트를 즉시 중단해 불완전한 상태를 성공으로 처리하지 않도록 함
cd "$(dirname "$0")/.."는 스크립트를 어느 디렉터리에서 호출하더라도 저장소 루트로 이동시킴
- 사전 검사 블록은 시간이 오래 걸리는 아카이브 전에
xcodegen과 공증 프로필을 확인함
- 내보낸 앱뿐 아니라
/Applications에 복사된 앱도 다시 검사해 복사 과정에서 번들이 손상되는 경우를 잡아냄

- 다른 공증 프로필이 필요하면 환경 변수로 덮어쓸 수 있음
TZED_NOTARY_PROFILE=<name> ./scripts/release.sh
에이전트에 배포 규칙 전달하기
release.sh가 한 번의 명령으로 배포를 수행한다면, CLAUDE.md나 AGENTS.md는 에이전트가 세션마다 별도 지시 없이 그 명령을 사용하도록 만듦
- 문서에는 프로젝트 재생성, 단위 테스트, 빠른 macOS 빌드, 실제 배포 명령을 기록함
xcodegen generate
swift test
xcodebuild -project YOUR-APP-NAME.xcodeproj \
-scheme YOUR-APP-NAME-macOS \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO build
./scripts/release.sh
- 두 빌드 경로의 차이도 문서에 명시해야 함
CODE_SIGNING_ALLOWED=NO 빌드는 CI와 빠른 로컬 확인에 적합함
- 실제 메뉴 막대 앱 배포, 격리 속성 통과, iCloud 동기화에는 Developer ID 서명과 공증을 수행하는
release.sh가 필요함
- 한 앱에서 만든 방식을 다른 저장소에서 참조하도록 지시하면 Claude Code가 이후 앱에도 같은 설정을 복제할 수 있음
빠른 무서명 빌드와 테스트
- Swift Package Manager 기반 단위 테스트는 Xcode 빌드 없이 실행함
swift test
- macOS 앱의 빠른 컴파일 확인은 서명을 끈 상태로 수행함
xcodebuild -project TZed.xcodeproj \
-scheme TZed-macOS \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO build
- iOS 앱과 위젯 확장의 시뮬레이터 빌드도 같은 방식으로 실행 가능함
xcodebuild -project TZed.xcodeproj \
-scheme TZed-iOS \
-destination 'generic/platform=iOS Simulator' \
CODE_SIGNING_ALLOWED=NO build
CODE_SIGNING_ALLOWED=NO로 만든 임시 서명 빌드는 컴파일과 시뮬레이터 실행에 사용할 수 있음
- 이 빌드는 Gatekeeper가 거부하며, 팀 접두사가 없어 iCloud KVS와 App Group 같은 권한이 결합되지 않으므로 배포용으로는 사용할 수 없음
실제 iPhone에 헤드리스 배포하기
- iOS 기기 배포에는 Mac 앱과 같은 공증 단계가 없으며,
xcodebuild와 devicectl을 사용함
- 실제 기기용 앱은 Apple Development 인증서와 개발 프로비저닝 프로필로 빌드하고 서명함
xcodebuild -project TZed.xcodeproj \
-scheme TZed-iOS \
-destination 'generic/platform=iOS' \
-allowProvisioningUpdates \
-derivedDataPath build/ios \
archive -archivePath build/TZed-iOS.xcarchive
- 생성된
.app은 연결된 기기의 UDID를 지정해 설치함
xcrun devicectl device install app \
--device <DEVICE-UDID> build/ios/…/TZed.app
devicectl list devices는 연결되고 페어링된 기기와 UDID를 보여줌
-allowProvisioningUpdates를 지정하면 필요한 개발 프로비저닝 프로필을 가져옴
GUI 없이 코드 서명이 작동하는 방식
- Developer ID Application 인증서를 만들 때 Apple은 인증서를 발급하고, Mac은 대응하는 개인 키를 생성해 둘 다 로그인 키체인에 저장함
xcodebuild가 호출하는 codesign은 개인 키로 바이너리를 서명하고, Apple 루트 인증서로 이어지는 인증서를 앱에 포함해 서명자를 검증할 수 있게 함
signingStyle: automatic을 사용하면 xcodebuild가 팀 ID에 맞는 인증서를 선택하고 필요한 프로비저닝 프로필을 Apple에서 가져옴
- 따라서 프로비저닝 프로필을 저장소에 커밋할 필요가 없음
권한, 공증, 스테이플링
- 각 타깃의
.entitlements 파일에는 샌드박스, 네트워크 클라이언트, iCloud KVS, App Group 같은 권한이 들어 있음
- 권한은 실제 팀 ID로 서명할 때 결합되므로 임시 서명 빌드에서는 iCloud와 App Group이 정상 작동하지 않음
- 서명과 공증은 서로 다른 단계임
- 서명은 누가 앱을 만들었는지 증명함
- 공증은 Apple이 서명된 앱을 악성 코드 검사한 뒤 티켓을 발급하는 절차임
- 스테이플링은 그 티켓을 앱에 붙여 오프라인에서도 Gatekeeper가 신뢰하도록 함
- 숨겨진 UI를 사용하는 메뉴 막대 앱인
LSUIElement 앱에서는 공증이 XProtect의 탐지를 피하는 데 필요함
수동 검증 명령
codesign -dv --verbose=4 /Applications/TZed.app
spctl -a -vvv -t exec /Applications/TZed.app
stapler validate /Applications/TZed.app
codesign은 서명자와 인증서를 확인함
spctl은 Gatekeeper가 실행을 허용할지 검사함
stapler validate는 공증 티켓이 부착됐는지 검증함
에이전트가 실행하는 표준 도구
- 별도의 빌드용 MCP 서버나 전용 플러그인은 필요하지 않으며, Claude Code는 비대화형 셸에서 표준 CLI를 실행함
- 사용하는 도구는
xcodebuild, xcrun notarytool, xcrun stapler, spctl, codesign, devicectl, xcodegen, swift임
CLAUDE.md는 공증 프로필 명명 규칙, 빠른 빌드와 실제 배포의 차이, 배포 시 release.sh를 사용해야 한다는 규칙을 에이전트에 전달함
- 최초
notarytool store-credentials만 대화형 단계로 남기고 이후 과정은 모두 자동화할 수 있음
Xcode GUI 작업을 CLI로 대체하기
- Xcode가 관리하는
.xcodeproj 생성은 project.yml과 xcodegen generate로 대체함
⌘B 또는 Run 버튼은 xcodebuild … build에 대응함
Product → Archive는 xcodebuild … archive로 처리함
- Organizer의 앱 배포는
xcodebuild -exportArchive로 대체 가능함
- Organizer 업로드는
xcrun notarytool submit --wait로 수행함
- 자동 티켓 부착에는
xcrun stapler staple을 사용함
/Applications로 드래그 앤드 드롭하는 설치 과정은 cp -R과 lsregister로 처리함
- 실제 iPhone의 Run 동작은
xcodebuild archive와 devicectl device install로 대체함
- Xcode와 XcodeGen 설치, 최초 자격 증명 설정,
release.sh와 CLAUDE.md 작성까지 끝내면 이후 새 빌드 배포는 한 문장 또는 한 명령으로 실행할 수 있음
한국 iOS 개발자 / 1인 SaaS 빌더에의 시사점
한국 1인 개발자나 소규모 SaaS 팀에서 Mac·iOS 앱을 동시에 빌드·배포해야 하는 상황은 흔하다(공통 인증 로직, 디자인 시스템, 위젯 공유). 이 글의 워크플로가 한국 환경에서 바로 받아 쓰기 좋은 이유는 다음 5가지다.
1. xcodebuild + notarytool 조합은 이미 한국어 Xcode 문서보다 안정적이다 — Apple Developer Program에 가입된 상태라면 인증서/키체인만 미리 셋업해두면 xcodebuild archive → notarytool submit → stapler staple 체인이 GUI 없이 그대로 동작한다. 공증 노티스가 JSON으로 떨어져 CI에 그대로 흘릴 수 있다.
2. XcodeGen(project.yml)은 Git 충돌을 없앤다 — .xcodeproj/project.pbxproj는 merge conflict의 온상이다. XcodeGen은 YAML 한 파일에서 생성하므로 1인이라도 Git 이력이 깨끗해지고, 팀원이 늘어도 PR 리뷰가 의미 있게 변한다. 한국 앱팀에서도 "Xcode 프로젝트 파일이 자꾸 깨진다"는 불만이 가장 흔한데, YAML로 옮기면 그 문제가 사라진다.
3. devicectl device install app로 iPhone 설치까지 자동화 — TestFlight까지 가지 않고도 내부 테스트 장치에 설치하는 데드라인이 짧은 빌드를 바로 떨어뜨릴 수 있다. 특히 SI/스타트업에서 "QA 1시간 안에 빌드 받아야 한다"는 요구가 흔한데, 이 경로가 정답이다.
4. CODE_SIGNING_ALLOWED=NO 임시 서명의 정확한 한계 — 빠른 컴파일은 되지만, Gatekeeper를 못 통과하고 iCloud KVS / App Group 권한이 실제 팀 ID에 묶이지 않는다. 즉 개발 중 로컬 디바이스 테스트는 가능해도 TestFlight/App Store 제출 직전에는 반드시 정상 서명으로 다시 빌드해야 한다. 한국 시점에서 "왜 내 Mac에서는 됐는데 App Store Connect에선 자꾸 fail이지?"라는 문의의 상당수가 여기서 발생한다.
5. LLM 에이전트 친화적 명세는 곧 "내가 사라져도 빌드할 수 있는" 문서화 — CLAUDE.md에 xcodebuild archive ... 명령과 인증서·키체인 변수, 공증 프로파일까지 적어두면, 휴가 중에도 동료가 빌드를 돌릴 수 있다. 더 나아가 Claude Code/Cursor/Codex 같은 에이전트가 PR마다 빌드 가능성 검증을 같이 돌리게 만들 수 있다. 이건 단순 DevOps가 아니라 지식 자동화의 시작점이다.
결론적으로, 이 글은 "Xcode CLI로도 모든 게 된다"는 단순 팁이 아니다. 프로젝트 명세(YAML) + 인증서/키체인 규약(CLAUDE.md) + Apple 공증 도구 체인 세 가지를 한 줄로 묶어서 빌드를 재현 가능하게 만들었다는 점에서, 한국 1인/소규모 iOS 팀이 그대로 참고할 가치가 충분하다.
원문: scottwillsey.com — Building and Shipping Mac and iOS Apps Without Ever Opening Xcode · GeekNews: #31431
📰 원본 출처 · https://news.hada.io/topic?id=31431 (#N=31431)
이 글은 GeekNews(긱뉴스)에 게제된 글을 기반으로 작성되었습니다. 원본의 라이선스와 저작권은 원작자에게 있습니다.
'자동화&툴 리뷰' 카테고리의 다른 글
| crates.io 6개월 개선 총정리 — 코드 뷰어, GitHub 분리, Svelte 이관까지 한 번에 풀어본 운영 인프라 재정의 (1) | 2026.07.15 |
|---|---|
| Precursor — Cloudflare의 세션 단위 봇 탐지 시스템: 마우스 호와 인지 지연을 1조 요청 규모로 누적 평가하는 새로운 행동 서명 (0) | 2026.07.15 |
| Papermake - Typst 기반의 셀프 호스팅 가능한 PDF 문서 생성 서버 (0) | 2026.07.14 |
| 마담 Semver가 펼쳐본 오픈소스 maintainer의 1년 — 아카이브하지 않은 저장소의 미래 (0) | 2026.07.13 |
| 개발자들이 GitHub를 떠나 Codeberg와 셀프 호스팅 대안으로 옮기는 이유 (0) | 2026.07.12 |