iOS 디버그·실기기 테스트와 프로비저닝 프로파일 관계
작성일: 2026-07-15
목적: Xcode/Flutter 실기기 실행, Ad Hoc, TestFlight에서 어떤 인증서와 프로파일을 선택하는지 빠르게 판단하기 위한 기준
먼저 기억할 한 문장
빌드 모드(Debug/Release)와 배포 방식(Development/Ad Hoc/TestFlight)은 서로 다른 축입니다.
예를 들어 최적화된 Release 빌드를 Xcode에서 케이블로 연결한 iPhone에 직접 실행하더라도, 설치 방식이 개발 실행이면 Development 프로파일을 사용할 수 있습니다. 반대로 TestFlight는 앱 이름이나 서버 환경이 dev여도 App Store Connect 배포 프로파일을 사용합니다.
서명 구성요소의 역할
| 구성요소 | 의미 | 핵심 확인사항 |
|---|---|---|
| App ID | 어떤 앱인지 식별하고 Apple capability를 선언 | Bundle ID가 정확하고 Push Notifications 등이 활성화돼야 함 |
| Signing Certificate | 누가 앱에 서명하는지 증명 | Apple Development 또는 Apple Distribution 인증서와 개인 키 필요 |
| Device UDID | 어떤 실제 기기에 직접 설치할 수 있는지 지정 | Development/Ad Hoc 프로파일에서 사용 |
| Provisioning Profile | App ID, 인증서, 기기, entitlement를 묶은 서명 허가서 | 설치·배포 방식에 맞는 타입과 유효한 capability 필요 |
| Entitlements | 앱이 실제로 사용할 Apple 기능 | 최종 서명 앱의 값이 프로파일과 일치해야 함 |
프로파일은 단순한 설치 파일이 아닙니다. App ID + 인증서 + 허용 기기 + capability/entitlement를 하나로 묶습니다. 따라서 App ID에서 Push Notifications를 나중에 켜면 기존 프로파일은 Invalid가 될 수 있으며 재생성해야 합니다.
실행 방식별 선택표
| 실행·배포 방식 | 인증서 | 프로파일 타입 | 기기 등록 | APNs 환경 |
|---|---|---|---|---|
| Xcode/Flutter로 실제 iPhone 직접 실행 | Apple Development | iOS App Development | 필요 | development |
| Xcode에서 Release 최적화로 실제 기기 직접 실행 | 보통 Apple Development | iOS App Development | 필요 | development |
| IPA를 등록된 기기에 직접 배포 | Apple Distribution | Ad Hoc | 필요 | production |
| TestFlight 내부·외부 테스트 | Apple Distribution | App Store Connect | 불필요 | production |
| App Store 정식 배포 | Apple Distribution | App Store Connect | 불필요 | production |
| iOS Simulator | 일반적인 실기기 프로파일 불필요 | 해당 없음 | 불필요 | 실기기 검증을 대체하지 않음 |
Apple은 development 프로파일이면 aps-environment=development, production 프로파일과 TestFlight 베타라면 aps-environment=production으로 설정한다고 설명합니다.
가장 자주 헷갈리는 사례
dev 서버를 보는 TestFlight 앱
앱이 dev API와 dev Firebase를 사용하더라도 TestFlight로 설치한다면 프로파일은 App Store Connect다. 여기서 dev는 서버 환경 이름일 뿐 Apple의 Development 서명 방식이라는 뜻이 아닙니다.
Release 모드로 케이블 실행
flutter run --release 또는 Xcode Release configuration은 코드 최적화 방식을 뜻합니다. 실제 기기에 개발 실행하는 경우 프로파일은 여전히 iOS App Development일 수 있습니다. Release라는 단어만 보고 Apple Distribution 프로파일을 선택하면 안 됩니다.
같은 Bundle ID의 Debug와 TestFlight
동일한 Bundle ID를 쓰면 iPhone에서 같은 앱으로 취급됩니다. Debug 빌드를 설치하면 TestFlight 빌드를 덮어쓸 수 있고 반대도 동일합니다. APNs sandbox와 production의 device token도 서로 다를 수 있으므로 서버에는 최신 FCM token을 다시 등록해야 합니다.
자동 서명과 수동 서명
- 로컬 실기기 개발: Xcode Automatic Signing이 Xcode-managed Development 프로파일을 자동 생성할 수 있습니다.
- CI TestFlight 배포: 예시 프로젝트는 프로파일 파일을 CI 비밀 변수으로 주입하고 ExportOptions에서 이름을 지정하는 수동 서명 방식입니다.
- 자동 서명을 사용해도 App ID capability가 잘못돼 있으면 정상 entitlement를 만들 수 없습니다.
예시 프로젝트 기준 프로파일 구성
TestFlight용
| 환경 | Bundle ID | 프로파일 타입 | 프로파일 이름 |
|---|---|---|---|
| dev | com.example.app.dev |
App Store Connect | Example Dev |
| staging | com.example.app.stg |
App Store Connect | Example Stg |
| production | com.example.app |
App Store Connect | Example AppStore |
세 환경 모두 TestFlight로 배포하므로 이름이 dev/staging이어도 App Store Connect 프로파일을 사용합니다.
로컬 실기기 디버그용
필요할 때 다음 Development 프로파일을 별도로 만들거나 Xcode Automatic Signing에 맡깁니다.
| 환경 | Bundle ID | 프로파일 타입 | 권장 이름 |
|---|---|---|---|
| dev | com.example.app.dev |
iOS App Development | Example Dev Development |
| staging | com.example.app.stg |
iOS App Development | Example Stg Development |
| production | com.example.app |
iOS App Development | Example Prod Development |
로컬 테스트에 실제로 사용하지 않는 환경의 Development 프로파일은 미리 만들 필요가 없습니다.
Push Notifications와의 관계
- Bundle ID의 App ID에서 Push Notifications를 활성화합니다.
- capability 활성화 이후 프로파일을 생성하거나 재생성합니다.
- Development 프로파일에는
aps-environment=development가 있어야 합니다. - App Store Connect/TestFlight 프로파일에는
aps-environment=production이 있어야 합니다. - Firebase 프로젝트에는 해당 iOS 앱의 APNs 인증 정보가 설정돼 있어야 합니다.
- 실제 기기에서 알림 권한, APNs token, FCM token, 백엔드 등록 순으로 확인합니다.
Broadcast Capability은 ReplayKit 화면 방송용이므로 일반 APNs 푸시와 관계없습니다.
프로파일 파일 검사
다운로드한 .mobileprovision을 plist로 디코딩합니다.
security cms -D -i ExampleDev.mobileprovision > /tmp/profile.plist핵심 값을 확인합니다.
/usr/libexec/PlistBuddy -c 'Print :Name' /tmp/profile.plist
/usr/libexec/PlistBuddy -c 'Print :Entitlements:application-identifier' /tmp/profile.plist
/usr/libexec/PlistBuddy -c 'Print :Entitlements:aps-environment' /tmp/profile.plist
/usr/libexec/PlistBuddy -c 'Print :ExpirationDate' /tmp/profile.plistTestFlight용 dev 프로파일의 기대값 예시는 다음과 같습니다.
Name: Example Dev
application-identifier: ABCDE12345.com.example.app.dev
aps-environment: productionDevelopment 프로파일은 aps-environment: development여야 하며, 등록된 기기의 UDID가 ProvisionedDevices에 포함돼야 합니다.
최종 앱 서명 검사
소스의 .entitlements 파일만 보지 말고 최종 .app에 실제 서명된 entitlement를 확인합니다.
codesign -d --entitlements :- path/to/Runner.appCI에서는 프로파일 설치 직후와 archive/export 직후 두 번 검사하면 설정 누락을 TestFlight 업로드 전에 차단할 수 있습니다.
선택 체크리스트
- Xcode에서 케이블로 실행하는가? → iOS App Development 또는 Automatic Signing
- 등록된 소수 기기에 IPA를 전달하는가? → Ad Hoc
- TestFlight 또는 App Store Connect에 올리는가? → App Store Connect
- Push capability를 방금 변경했는가? → 기존 관련 프로파일 재생성
- 프로파일이 Invalid인가? → 신규 빌드에는 사용할 수 없으므로 재생성 후 교체
- 푸시가 안 오는가? → 최종
aps-environment, APNs token, FCM token 순으로 확인
공식 참고자료
함께 읽기
- Flutter 앱 배포, `flutter build` 한 줄이면 끝인 줄 알았습니다Flutter 앱의 빌드 명령은 간단합니다. Android는 flutter build appbundle, iOS는 flutter build ipa로 결과물을 만들 수 있습니다. 그러나 팀이 반복해서 사용할 수 있는 배포 체계를 만들려면 그 뒤에 있는 서명, 권한, 스토어 API, 심사와 출시 절차까지 함께 설계해야 합니…
- Expo 앱은 만들었는데 출시가 안 됩니다: `eas build`보다 먼저 준비할 것들Expo를 사용하면 네이티브 빌드 과정이 크게 단순해집니다. 하지만 앱스토어 출시까지 명령어 한두 줄로 끝나는 것은 아닙니다. 실제 자동 배포를 만들려면 앱 등록, 서명 자격 증명, 스토어 API 권한, CI/CD 승인 절차가 먼저 준비되어야 합니다.
- 같은 Expo 앱인데 배포 방식은 달랐습니다: iOS와 Android 심사 제출 비교기앞선 글에서는 이미 TestFlight에 올라간 iOS 빌드를 AI가 App Store 심사까지 제출한 과정을 다뤘습니다.
- 코드는 그대로인데 앱 심사는 제출됐습니다: AI에게 Expo 배포를 맡겨본 기록코드를 한 줄도 수정하지 않았는데 TestFlight에 올라가 있던 앱이 App Review 제출 상태로 바뀌었습니다. 얼핏 보면 AI가 앱을 새로 빌드해서 배포한 것처럼 보이지만, 실제로는 이미 준비된 빌드와 스토어 정보를 확인한 뒤 App Store Connect의 심사 절차를 진행한 것입니다.
- Flutter iOS 스플래시 간헐적 8초 지연 원인과 해결앱을 콜드 스타트하면 흰 배경과 앱 아이콘으로 구성된 iOS 스플래시가 정상보다 오래 남습니다. 같은 TestFlight 빌드에서도 빠르게 열릴 때와 약 8초 동안 멈춘 것처럼 보일 때가 섞여 간헐적으로 재현됩니다.