빌드는 이미 TestFlight에 올라가 있었다. 심사 제출은 그 빌드를 고르고 버튼만 누르면 될 줄 알았다. 그런데 “심사에 추가”를 누르자 두 개의 필드가 비어 있다며 막혔고, 그 앞단에는 App Privacy 설문·연령등급·수출 규정 같은 “답을 정해야 하는” 질문들이 줄지어 있었다. 심사 제출은 코드 작업이 아니라 판단 작업이었다
App Privacy는 내 코드가 아니라 SDK가 수집하는 것으로 답했다
App Privacy 설문에서 처음 헷갈린 건 “무엇을 기준으로 답하느냐”였다. 내 앱 코드는 사용자 데이터를 직접 모으지 않는다. 하지만 붙여 쓴 SDK는 모은다. 그래서 google_mobile_ads가 실제로 수집·전송하는 데이터를 기준으로 답했고, Google이 공개한 iOS 데이터 공개 문서를 확인한 뒤 항목을 채웠다
shared_preferences도 쓰지만 이건 기기 로컬 저장만 한다. 외부로 전송하지 않으므로 공개 대상이 아니다. 이 구분이 핵심이었다. 라이브러리를 썼다고 무조건 신고하는 게 아니라, 그 라이브러리가 데이터를 기기 밖으로 내보내는지로 갈린다
최종 답변은 이렇게 정리됐다
| 카테고리 | 세부 유형 | 연결됨 | 추적 목적 | 수집 목적 |
|---|---|---|---|---|
| 식별자 | 기기 ID | 예 | 예 | 타사 광고 |
| 위치 | 대략적 위치(Coarse) | 예 | 예 | 타사 광고 |
| 사용 데이터 | 광고 데이터 | 예 | 예 | 타사 광고, 분석 |
| 사용 데이터 | 제품 상호 작용 | 예 | 예 | 타사 광고, 분석 |
| 진단 | 충돌 데이터 | 아니오 | 아니오 | 앱 기능 |
| 진단 | 실적(성능) 데이터 | 예 | 예 | 분석, 타사 광고 |
최상단의 “이 앱이 사용자를 추적하나요?”에는 예로 답했다. 이건 Info.plist의 NSUserTrackingUsageDescription(ATT 권한 문구)과 일치해야 한다. 설문 답변과 앱 안의 권한 설정이 어긋나면 나중에 문제가 된다
“술안주” 카테고리명 하나 때문에 연령등급을 다시 봤다
연령등급은 Apple의 신규 7단계 설문으로 진행했다. 음식 추천 앱이라 대부분 “없음/아니요”로 답했다. 문제는 앱 카테고리 중에 “술안주”가 있다는 점이었다. 실제로 음주를 묘사하거나 조장하는 내용은 없다. 하지만 카테고리명이 음주 맥락을 간접적으로 언급한다. 여기서 “없음”으로 밀어붙일지, 보수적으로 잡을지 판단이 필요했다. 나는 음주·흡연·약물 문항만 “드문(Infrequent)”으로 답했다. 나머지 폭력·성적 콘텐츠·공포·도박성 문항은 전부 “없음/아니요”로 두었다.
음주/흡연/약물 → 드문(Infrequent) ← "술안주" 카테고리명 고려 그 외 전 항목 → 없음/아니요 광고 포함 → 예 ───────────────────────────── 결과: 계산된 등급 13+
결과는 13+였다. 실제 콘텐츠보다 한 단계 보수적으로 잡은 셈이지만, 카테고리명에 음주 단어가 들어간 이상 이렇게 답하는 편이 심사에서 트집 잡힐 여지가 적다고 봤다
수출 규정 경고는 오래된 빌드가 남긴 흔적이었다
심사용으로 고른 건 CI/CD로 이미 TestFlight에 올라가 있던 빌드 14(버전 1.0.0)였다. 이 빌드를 선택하니 “수출 규정 관련 문서 누락” 경고가 떴다. 원인은 빌드 시점이었다. 빌드 14는 Info.plist에 ITSAppUsesNonExemptEncryption 키를 추가하기 이전에 만들어졌다. 그래서 Apple이 암호화 사용 여부를 물어보는 문서가 비어 있다고 판단한 것이다. 경고 옆 “관리” 링크에서 수동으로 답했다.
암호화 알고리즘 유형 → 표준 암호화만 사용(HTTPS/TLS), 자체·독점 암호화 없음 프랑스에서 배포? → 아니요
표준 HTTPS/TLS만 쓰고 자체 암호화가 없으니 면제 대상이다. 답변 후 경고가 사라졌다. 이후 빌드부터는 Info.plist에 ITSAppUsesNonExemptEncryption = false를 넣어두면 이 질문 자체가 자동으로 스킵된다. 매번 손으로 답하고 싶지 않다면 이 키를 넣어두면 된다
첫 출시라 자동 출시를 수동으로 바꿨다
버전 출시 방식은 기본값이 “자동으로 버전 출시”였다. 심사를 통과하는 즉시 스토어에 공개된다는 뜻이다. 첫 출시는 공개 타이밍을 내가 정하고 싶어 “수동으로 버전 출시”로 바꿨다. 이건 취향이 아니라 리스크 관리에 가깝다. 심사 통과 시점과 실제 공개 시점을 분리해두면, 통과 직후 마지막으로 스토어 노출을 점검할 여유가 생긴다
제출을 막은 건 코드가 아니라 두 개의 빈 필드였다
여기까지 하고 “심사에 추가”를 눌렀는데 두 곳에서 막혔다
1. 앱 정보의 콘텐츠 권한 정보 미설정 2. 저작권 필드 미입력
콘텐츠 권한은 앱 안의 음식 이미지가 전부 로열티프리 다운로드거나 AI 생성물이라, “타사 콘텐츠가 포함되어 있지 않습니다”로 답했다. 저작권 필드에는 2026 hyeok을 넣었다. 두 블로커를 해소하고 나서야 “제출 초안” 화면에서 “심사를 위해 제출”이 눌렸다. 제출이 됐는지는 화면 변화로 확인했다. 파란 “심사에 추가” 버튼이 사라지고, “심사 대기 중인 버전에서도 일부 정보를 편집할 수 있습니다”라는 안내가 뜬다. 이 문구가 곧 현재 상태가 “심사 대기 중”이라는 신호다. 별도 완료 팝업을 기다릴 게 아니라 이 문구를 확인하면 된다. 앞서 메타데이터를 한 번 저장 누락해 설명과 키워드가 빈 채로 남았던 적도 있었다. 제출 직전에 필드가 실제로 채워졌는지 재확인하는 습관이 필요했던 이유다
TestFlight 내부 테스터가 막혀 외부로 틀었다
지인 몇 명에게 테스트를 맡기고 싶어 처음엔 내부 테스터로 시도했다. 내부 테스터는 별도 심사 없이 즉시 테스트할 수 있지만, 팀원으로 등록해야 해서 계정 접근 권한(역할)이 함께 부여된다. “사용자 및 액세스”에서 지인을 신규 사용자로 초대하고 역할은 “제품 개발”(Developer)로 줬다. TestFlight 내부 테스팅에 필요한 최소 권한이다. “사용자 지원”(Customer Support) 역할은 TestFlight 접근이 안 돼 제외된다
문제는 초대 메일이 도착하지 않은 것이다. 네이버 메일함은 물론 스팸함에도 오지 않았다. 재전송하고 appstoreconnect.apple.com 직접 로그인도 시도했지만 끝내 해결되지 않았다
여기서 방향을 틀었다. 지인 테스트는 계정 권한 부여가 필요 없는 외부 테스팅(TestFlight 공개 배포)으로 가기로 했다. 외부 테스터는 이메일만으로 최대 10,000명까지 초대할 수 있고, 첫 빌드만 Apple의 “Beta App Review”(보통 1일 이내)를 한 번 거치면 된다. 지인 몇 명에게 권한까지 주면서 내부 테스터로 묶을 이유가 없었다. “테스트 정보” 페이지를 채우는 데까지 진행하고, 나머지 절차는 뒤로 미뤘다
마무리
외부 테스팅 절차는 아직 끝까지 밟지 않았다. 그래서 “외부 테스팅이 더 낫다”는 건 초대 방식과 권한 측면에서의 판단이지, 실제 배포까지 검증한 결론은 아니다. 이 부분은 절차를 완료하면 다시 정리할 생각이다.
한 줄로 요약하면, App Store 심사 제출을 막는 건 코드가 아니라 “질문에 정확히 답했는가”와 “필드를 다 채웠는가”였다.
제출을 앞두고 있다면 세 가지를 기준으로 삼길 권한다. App Privacy는 내 코드가 아니라 SDK가 데이터를 기기 밖으로 내보내는지로 답하고, 연령등급은 카테고리명에 걸리는 단어가 있으면 보수적으로 잡고, “심사에 추가”가 막히면 코드가 아니라 콘텐츠 권한·저작권 같은 빈 필드부터 확인하는 것이다