## iOS App Store 출시

**2026-09-27 갱신 · 시간의무덤 / 앱 내부 브랜드 biolem.** React Native 앱과 Kotlin 서버를 개발하고 iOS App Store에 출시했다. 아래는 출시 과정에서 수행한 작업과 다음 배포에 재사용할 절차다.

| 구간 | 수행한 작업 |
| --- | --- |
| 앱 등록 | 소개 문구·심사 메모·스크린샷 준비 |
| 배포 오류 해결 | Hermes 심볼 누락과 미사용 음악 권한 모듈 수정 |
| 빌드 검증 | 바이너리·서명·dSYM 검증과 IPA 내보내기 |
| 출시 | iOS App Store 공개 완료 |

## 식별자와 서명

앱 표시 이름, Bundle ID, 버전, 빌드는 역할이 다르다. 표시 이름은 스토어에서 보는 이름이고, Bundle ID는 앱을 식별한다. 버전은 사용자에게 보여 주는 릴리스, 빌드 번호는 같은 버전 안에서 바이너리를 구별한다.

1. Xcode에서 `ios/biolem2.xcworkspace`와 올바른 Scheme을 연다.
2. Signing & Capabilities의 개발 팀과 Bundle ID를 Apple Developer·App Store Connect의 앱과 맞춘다.
3. Apple 로그인 entitlement와 서버의 토큰 audience 검증 설정을 대조한다.
4. Git SHA, 버전·빌드 번호, Archive 경로와 생성 시간을 함께 기록한다.

빌드 성공, 실기기 설치, 앱 실행은 별도로 확인한다. 실기기 실행은 연결한 iPhone을 대상으로 Run을 사용한다. Archive를 만들거나 Apple에 업로드해도 폰에 자동 설치되는 것은 아니다.

## Archive와 업로드

배포 흐름은 **Xcode Archive → Organizer → App Store Connect 업로드 → Apple 처리 → 빌드 선택**으로 이어진다.

1. 실제 iOS 기기용 배포 대상을 선택하고 Product → Archive를 실행한다.
2. Organizer → Archives에서 생성 시간·버전·빌드·팀을 확인한다.
3. Distribute App → App Store Connect를 선택하고 검증·전송 결과를 확인한다.
4. 전송 후 TestFlight와 처리 결과 메일을 확인한다. 처리된 빌드를 버전 1.0의 Build 항목에 연결하고 저장한다.

Apple은 업로드된 바이너리를 처리한 뒤 App Store Connect에 표시한다. **Uploaded to Apple은 전송 결과**이고, TestFlight 처리 완료나 심사 제출을 뜻하지 않는다. “빌드 없음”만 보이면 처리 중인지 실패인지 추가 확인이 필요하다. [Apple 빌드 업로드 안내](https://developer.apple.com/help/app-store-connect/manage-builds/upload-builds/)

## 실제로 해결한 배포 오류

### Hermes 심볼 누락

React Native의 prebuilt Hermes 바이너리는 포함됐지만 해당 dSYM을 Archive에 넣는 단계가 빠져 있었다. dSYM은 네이티브 크래시를 함수와 소스 위치로 해석하는 데 쓰인다.

- 공식 RN 버전에 맞는 Release dSYM을 가져오고 SHA-256을 검증했다.
- Archive 단계에 `ios/scripts/copy-hermes-dsym.sh`를 추가했다.
- 앱과 Hermes 각각의 바이너리·dSYM UUID 일치, 코드 서명, 실제 복사를 검증했다.
- 다른 UUID는 실패시키고 Debug·시뮬레이터에서는 복사를 건너뛰도록 했다.

### 미사용 음악 권한 모듈

빌드 1은 `ITMS-90683`과 `NSAppleMusicUsageDescription` 누락으로 Apple 처리에 실패했다. 앱이 음악 기능을 제공하지 않는데 Podfile에 `MediaLibrary` 권한 모듈이 포함돼 있었다.

실제 기능과 맞지 않는 설명을 추가하는 대신 미사용 모듈을 제거했다. 사진 권한은 유지하고, 최종 바이너리에서 음악 API 참조가 제거된 것을 확인했다. 빌드 번호를 2로 올려 새 Archive의 서명·심볼과 App Store용 IPA 내보내기를 검증했다.

## 스토어 정보와 심사 준비

| 항목 | 준비할 내용 |
| --- | --- |
| 소개·스크린샷 | 실제 제출 빌드와 같은 기능·화면. 서버 저장과 기기 저장의 차이도 설명 |
| 지원 URL | 앱 사용 안내와 문의 연락처가 있는 공개 웹페이지 |
| 마케팅 URL | 소개 사이트가 있을 때 입력하는 선택 항목 |
| 라우팅 적용 범위 파일 | 길찾기 경로를 제공하는 라우팅 앱에 해당할 때 준비 |
| 심사 로그인·메모 | 유효한 테스트 계정, 핵심 기능을 재현하는 순서, 필요한 권한 설명 |
| 개인정보·계정 | 실제 수집 정보, 개인정보처리방침, 계정 삭제 흐름 확인 |
| 서버 가용성 | 심사 중 로그인·저장·조회가 가능하도록 API와 종료 예약 확인 |

지원 URL은 이메일 문자열을 넣는 칸이 아니다. 문의할 수 있는 실제 웹페이지가 필요하다. 출시 방식은 수동, 승인 후 자동, 지정 시점 이후 자동 중 선택한다. [Apple 버전 정보 안내](https://developer.apple.com/help/app-store-connect/reference/app-information/platform-version-information/)

현재 앱의 심사 메모는 이메일 로그인 → 장소 선택 → 사진·평점·메모 기록 → 지도·달력에서 재확인하는 흐름을 기준으로 작성했다. 심사 계정의 비밀번호와 담당자 연락처는 공개 지식 노트에 기록하지 않는다.

## 제출부터 공개까지

필수 메타데이터와 올바른 빌드를 준비한 뒤 **심사에 추가 → 제출 내용 확인 → 심사 제출** 순서로 진행한다. “심사에 추가”만으로 Apple 심사가 시작되지는 않는다. [Apple 심사 제출 안내](https://developer.apple.com/help/app-store-connect/manage-submissions-to-app-review/submit-an-app/)

| 단계 | 확인할 증거 |
| --- | --- |
| 제출 준비 | 메타데이터 저장, 처리된 빌드 연결 |
| 심사 제출 | App Review의 실제 제출 상태 |
| 심사 진행·대응 | 검토 상태와 심사팀 메시지, 수정 후 재제출 결과 |
| 승인 | 해당 버전의 승인 결과 |
| 출시 | 선택한 출시 방식과 실제 스토어 공개 페이지 |

로그인이 필요한 앱은 심사자가 접속할 수 있어야 한다. 현재 AWS 운영 기록에는 매일 10시 종료와 10시 10분 추가 점검이 있으므로, 심사 운영으로 전환할 때 **모든 종료 경로를 함께 확인**한다. 예약 하나만 바꾸면 다른 루틴이 다시 서버를 끌 수 있다. [AWS 전원 관리 노트](/about/aws-power)

## 다음 배포에 남길 기록

- 소스 Git SHA, 앱 버전·빌드, Archive 경로, 서명·심볼 검증 결과
- Apple 전송 결과와 처리 성공·실패 메시지
- 연결한 빌드, 제출 시각, 심사 대응과 승인 여부
- 자동 종료 운영 방안, API·로그인·핵심 기능 확인 결과
- 실제 스토어 공개 주소와 공개 확인 시점

이번 개발·출시 경험은 [이력서](/submit#biolem), [경력 상세](/about#biolem), [프로젝트 도표](/resume#biolem)에 함께 반영했다.
