macOS 앱의 구조
(eclecticlight.co)- macOS 애플리케이션은 명령줄 프로그램보다 복잡한 구성 요소를 가지며, 창과 메뉴 등 인터페이스 자원을 별도 구조로 관리함
- Classic Mac OS에서는 실행 코드와 리소스가 파일의 리소스 포크에 저장되었으나, Mac OS X부터는 번들(bundle) 구조로 전환됨
- 앱 번들은 Contents 디렉터리를 중심으로, MacOS·Resources·Frameworks 등의 하위 폴더와 Info.plist 같은 핵심 파일로 구성됨
- 이후 코드 서명·App Store 영수증·공증(notarization) 등이 추가되며, 보안과 무결성을 강화한 구조로 발전함
- 이러한 자급적(app bundle) 구조는 설치·업데이트·삭제를 단순화하고, 보안성과 유지관리 효율성을 높이는 핵심 기반이 됨
Classic Mac OS의 앱 구조
- 초기 Mac OS에서는 창, 메뉴 등 UI 리소스를 실행 파일과 분리해 리소스 포크(resource fork) 에 저장
- 예시로 QuarkXPress 4.11의 리소스가 ResEdit에서 표시됨
- 실행 코드는 CODE 리소스에 포함되며, Finder가 인식할 수 있도록 파일 유형(type)과 생성자(creator) 정보가 함께 저장됨
Mac OS X의 번들 구조
-
Mac OS X는 NeXTSTEP에서 유래한 번들(bundle) 구조를 도입
- 앱은
.app확장자를 가진 디렉터리 형태이며, 내부에 Contents 폴더를 포함 - MacOS 폴더에는 GUI 앱의 실행 파일과 명령줄 도구가 포함됨
- Resources 폴더에는 앱 아이콘, GUI 구성 요소 등 리소스 파일이 저장됨
- 일부 앱은 Frameworks 폴더를 포함해 dylib(동적 라이브러리) 를 내장함
- 앱은
- Info.plist 파일은 필수이며, 실행 파일 이름, 아이콘, 최소 macOS 버전, 문서 유형, 버전 번호 등을 정의
- PkgInfo 파일은 Classic Mac OS의 유형·생성자 정보를 유지하지만 필수는 아님
- 앱 실행 시 launchd가 실행 코드를 시작하며, LaunchServices와 RunningBoard가 Info.plist 정보를 기반으로 초기화 절차를 수행
macOS에서의 보안 및 확장
-
Mac OS X 10.5 Leopard(2007) 부터 코드 서명(Code Signature) 이 도입되어
_CodeSignature폴더가 추가됨- CodeResources 파일에 코드 디렉터리 해시(CDHash)가 포함되어 앱 무결성을 검증
-
App Store 배포 앱은
_MASReceipt폴더에 스토어 영수증을 포함 - 2018년 이후에는 공증(notarization) 이 도입되어, Apple이 발급한 티켓(ticket) 을 CodeResources 파일로 번들에 ‘스테이플(staple)’ 가능
- 현대 앱 번들은 과거에 시스템 폴더에 설치되던 구성 요소를 자체 포함
- Library 폴더: LaunchDaemons, LoginItems 등
- XPCServices 폴더: 앱이 사용하는 별도 실행 서비스
- Plugins / Extensions 폴더: 앱 확장 기능 및 App Intents 포함
- 일부 앱에는 version.plist 파일도 존재
앱 번들의 이점
- 모든 구성 요소를 번들 내부에 통합함으로써 설치·업데이트·삭제가 간편해짐
- 구성 요소 누락 가능성이 줄고, 서명 및 공증 보호를 통해 보안성이 강화됨
- App Store 앱은 추가적으로 영수증 및 공증 티켓을 포함해 신뢰성을 확보
-
Intel과 Arm 아키텍처 간 구조 차이는 없으며, Mach-O 실행 파일이 두 플랫폼용 코드를 모두 포함하는 유니버설(fat) 바이너리 형태로 저장됨
- 동일 파일 내에 각 아키텍처별 서명(signature) 이 함께 존재
앱 구조의 시각적 개요
- 다이어그램에서 연노란색은 필수 또는 거의 모든 앱에 존재하는 구성 요소
- 녹색은 App Store 배포 앱에서만 존재하는 항목, 파란색은 선택적 공증 티켓을 의미
- 추가적으로 Automator 워크플로우, 스크립트 등 부가 요소가 포함될 수 있음
- 전체적으로 macOS 앱은 자급적·보안 중심 구조로 진화해 왔음
Hacker News 의견
-
파란색으로 표시된 부분은 notarisation ticket(공증 티켓)인데, 사실상 선택 사항이 아님
공증되지 않은 앱은 사용자 입장에서 너무 불편해서 결국 연 $99의 Apple 개발자 등록비를 내야 함
개인용으로만 빌드하고 실행한다면 괜찮지만, 배포용이라면 macOS가 경고창을 띄워 앱이 망가진 것처럼 보임
예전엔 우클릭으로 실행할 수 있었지만, 이제는 시스템 설정까지 들어가야 허용 가능함
관련 스크린샷은 Apple 지원 문서와 개발자 뉴스에서 볼 수 있음
나는 Apple의 보안 철학은 좋아하지만, App Store 외부 앱의 공증 제도는 모든 당사자에게 손해라고 생각함
실제로 공증이 보안 문제를 막은 사례를 찾지 못했음-
macOS 공증이 귀찮다고 생각했는데, Windows 배포를 해보니 그건 더 심했음
Windows Defender의 신뢰를 얻으려면 인증서를 사야 하고, 회사와 개인 모두 깊은 신원 검증을 거쳐야 함
하드웨어 토큰으로 서명해야 해서 한 명만 릴리스를 배포할 수 있음
게다가 인증 기관이 임의로 키를 잠글 수도 있어서, 보안 패치를 내야 할 때 막히면 끔찍함
이런 점에서 macOS 생태계가 훨씬 낫다고 느낌 -
나는 여러 플랫폼으로 컴파일되는 프로그래밍 언어를 개발 중인데, 서명과 공증은 이 과정과 전혀 맞지 않음
이런 서명 제도는 통제 수단일 뿐이며, Epic 사례처럼 남용될 위험이 있음
서명되지 않은 바이너리를 합리적으로 실행할 수 없으면 그 플랫폼은 닫힌 것으로 간주하고 지원하지 않음
iOS나 Android 같은 폐쇄형 플랫폼은 PWA로 어느 정도 대체 가능함
다만 Google이 자가 서명 앱 실행을 계속 허용할지 신뢰가 약해진 상태임 -
Apple이 App Store 외부 앱의 인증서를 취소한 사례는 두 번밖에 모름
하나는 Facebook의 Research App, 다른 하나는 Google의 Screenwise Meter였음
둘 다 청소년을 대상으로 한 스파이웨어 성격의 앱이었고, 인증서 취소로 내부 도구까지 마비됨
이후 Screenwise Meter는 App Store에 다시 올라온 것으로 보임
관련 기사: Wired, EFF -
내 앱 폴더의 절반 정도는 공증되지 않았는데, 실제로는 별 문제 없음
-
공증 후 stapled ticket(첨부 티켓)은 선택 사항임
티켓을 첨부하지 않으면 사용자가 인터넷 연결로 공증 상태를 확인해야 함
-
-
AppBundler.jl을 개발하면서 macOS 앱 구조에 불만이 많음
Frameworks 폴더 구조 강제가 보기엔 깔끔하지만, 실제로는 번들링이 번거로워 Libraries 폴더로 우회 중임
가장 큰 문제는 코드 서명임 — 모든 바이너리에 서명을 붙이는 건 낭비처럼 느껴짐
파일 해시를 모아 한 번만 서명하면 될 일을 왜 이렇게 복잡하게 만드는지 이해하기 어려움
또한 entitlements가 런처 바이너리에만 붙는 것도 비효율적임
공증 기준이 시간이 지나면서 강화되기 때문에, 나중에 갑자기 앱이 통과하지 못할 수도 있음 -
Tauri 앱을 서명·공증하려고 Apple Developer Program에 가입했는데, 3주째 실패 중임
Mac이 없어 GitHub Actions로 시도했지만, 첫 공증은 오래 걸리는 게 흔하다고 함
GitHub 비용만 $100 가까이 썼는데 아직도 공증이 안 됨
Apple 지원팀은 Mac이 없고 Tauri를 쓴다는 이유로 도움을 거부함
공증 API 인증 과정도 악몽 수준임 — PKCS8로 JWT를 만들어야 하는데 문서가 거의 없어 직접 Node 프로그램을 짜야 했음
지금까지 겪은 최악의 개발자 경험(DX) 이었음- 중고 Mac mini를 $150에 사서 그걸로 서명하라는 조언을 받음
Apple 하드웨어 없이 이걸 해결하려는 건 시간 낭비라고 함
- 중고 Mac mini를 $150에 사서 그걸로 서명하라는 조언을 받음
-
첫 번째 OS 스크린샷을 보고 마음이 철렁했음
예전엔 실용적이고 깔끔한 UI였는데, 요즘은 둥근 모서리와 거품 같은 아이콘으로 공간만 낭비됨
그래도 Mac 하드웨어 품질이 좋아서 ThinkPad로 못 옮기고 있음-
둥근 모서리는 오히려 인간 시각에 유리한 기능임
각진 모서리가 시각 피로를 유발한다는 연구가 있음
관련 글: Round Rects Are Everywhere -
나도 최신 macOS는 별로지만, 그 스크린샷도 완벽하진 않음
선이 너무 많고 색이 부족해서 시선이 분산됨
개인적으로는 Leopard 시절의 Aqua UI가 정보 밀도와 시각적 깊이의 균형이 좋았음 -
픽셀 비율로 보면 예전 UI가 오히려 공간을 더 많이 차지함
5K 해상도 기준으로는 현대 MacBook Pro 쪽이 효율적임
고전 Mac도 약간의 둥근 모서리를 이미 가지고 있었음
참고: Infinite Mac -
컴퓨터는 업무용만이 아니라 즐거움을 위한 도구이기도 함
다만 요즘 UI는 실용성에서 너무 멀어진 느낌임 -
화면의 대부분이 쓸모없는 101101 같은 정보라서 실용적이라 보기 어려움
-
-
macOS에서 명령줄 도구 실행 시 launchd가 실행 주체라는 말은 틀림
실제로는 다른 UNIX 시스템처럼 쉘에서 fork/spawn으로 실행됨 -
NeXTSTEP의 번들 시스템이 Java의 JAR 파일 설계에 영감을 줬음
- 하지만 JAR은 단순히 ZIP 파일에 확장자만 바꾼 것임
-
클래식 Mac OS의 Power Mac 앱은 PPC 코드가 데이터 포크에 저장되었음
CFM-68K 바이너리도 마찬가지였고, CODE 리소스를 쓴 건 구형 68K 코드뿐이었음 -
예전 ResEdit으로 앱을 수정하던 시절이 즐거웠던 기억이 있음
-
마지막 다이어그램처럼 관료주의가 폭발하는 건 좋은 신호가 아님
macOS 26으로 “업그레이드”할 이유가 더 줄어듦- 앱 번들에 폴더가 몇 개 늘었다고 호들갑 떨 필요는 없다는 반응도 있음
-
지금 구조가 macOS의 “표준”이긴 하지만, 유일한 방법은 아님
RPATH를 잘 설정하면 임의의 하위 폴더에 라이브러리를 넣어도 공증 통과 가능함
예를 들어 AppName.App/Contents/Libraries 경로도 작동함
다만 이 방식의 실질적 이점은 거의 없고, 내 시스템의 100여 개 앱 중 /Libraries 폴더를 쓰는 건 하나도 없음- iOS는 이 부분이 훨씬 엄격하고 불명확함
.dylib 대신 반드시 .framework 형식을 써야 하고, 이건 문서화되지 않은 규칙임
제출 시 자동으로 감지되어 거절당할 수 있음
- iOS는 이 부분이 훨씬 엄격하고 불명확함