혼자 만든 Flutter 앱을 구글 플레이에 올리기까지, “코드 완성”과 “출시 가능”은 완전히 다른 단계였다. 실제 출시 준비에서 걸린 항목들을 체크리스트로 남긴다. 특히 시뮬레이터에선 안 드러나고 실기기에서만 터진 것들이 핵심이다.
1. 광고: 테스트 유닛 → 실 유닛 교체
개발 내내 애드몹은 테스트 광고 유닛(placeholder)으로 붙여둔다. 실 유닛에 테스트 클릭을 하면 계정 정지 위험이 있기 때문이다. 출시 직전 실 유닛으로 교체해야 하는데, 배너·전면은 챙기면서 App Open 유닛 발급은 깜빡하기 쉽다. 나도 하마터면 App Open만 테스트 ID인 채로 낼 뻔했다. 교체 후엔 실기기에서 실제로 광고가 뜨는지 확인해야 한다.
2. 결제(IAP) 상품 등록
앱 안에 “광고 제거” 같은 인앱결제가 있으면, 코드의 상품 ID와 플레이 콘솔의 인앱 상품이 일치하게 등록돼야 실제로 구매가 뜬다. 코드에 추상 서비스만 있고 콘솔 상품이 없으면 결제 화면 자체가 안 나온다. 등록 후 상품이 “활성” 상태인지도 확인해야 한다.
3. 개인정보처리방침 — 앱 내 링크와 스토어 URL 일치
정책 페이지를 웹에 게시하고, 앱 내부 링크와 플레이 콘솔에 등록하는 URL이 같아야 한다. 광고·데이터 수집이 있으면 필수이며, 데이터 안전 섹션의 신고 내용과도 어긋나면 안 된다.
4. 건강 관련 선언(Health declaration)
건강·피트니스 성격의 앱(내 경우 단식)은 플레이 콘솔에서 건강 관련 선언을 요구한다. 데이터 취급 방식을 정확히 신고해야 심사를 통과한다. 애매하게 넘기면 반려된다.
5. 상표 조회(KIPRIS)
앱 이름을 확정하기 전 특허정보넷 KIPRIS에서 상표를 조회했다. 남의 등록 상표와 겹치면 나중에 앱 이름을 통째로 바꿔야 할 수 있다. 출시 후가 아니라 출시 전에 확인하는 게 압도적으로 싸다.
6. 서명키 관리
업로드 키(.jks)는 분실하면 같은 앱으로 업데이트를 못 올린다. 반드시 앱 코드와 분리된 안전한 곳에 백업한다. 나는 이 키를 버전관리에서 제외하고 별도 백업으로 관리한다.
7. 그리고 — 반드시 ‘릴리스 빌드를 실기기에’ 설치해 검증
이게 가장 중요하다. 다음 버그들은 전부 debug/시뮬에서 멀쩡했고 릴리스 실기기에서만 터졌다.
- R8/코드 축소(minify)·desugaring 관련 릴리스 전용 크래시
- 광고 빈도 캡이 실기기에서만 무력화(백그라운드 DB 반영 문제)
- 보상형 광고 보상 미지급 등 SDK 실동작 이슈
“코드 짜고 테스트 통과 = 출시 준비 완료”가 아니다. 릴리스로 빌드해서 진짜 폰에 깔고, 광고까지 눌러보는 것까지가 출시 준비다. 재배포할 땐 pubspec 빌드번호(+1) 올리는 것도 잊지 말자.
재배포 때도 반복되는 것들
출시는 한 번이 아니다. 업데이트마다 몇 가지가 반복된다. pubspec 빌드번호를 +1 올려야 새 버전으로 인식되고, 데이터 안전 섹션의 신고 내용이 실제 수집과 어긋나지 않게 유지해야 하며, 광고 SDK·플러그인을 올릴 때마다 릴리스 실기기 재검증을 다시 돌려야 한다. “지난번에 됐으니 이번에도 되겠지”가 가장 위험하다 — R8 최적화는 의존성이 바뀌면 다른 곳에서 터진다. 나는 재배포 체크리스트를 문서로 만들어, 매번 같은 실수를 반복하지 않게 했다.