AppOrbit
← blog

앱인토스에 게임을 출시하기까지 — 5편: 광고 연동, 네이티브 브릿지, 그리고 심사 반려

앱인토스, 토스, WebView, 광고SDK, 배포, 앱심사, 사이드프로젝트

1. 들어가며: 만드는 것과 배포하는 것은 다른 문제다

4편까지 게임 로직, 상태 관리, 차트 렌더링, 애니메이션에 대해 이야기했습니다. 로컬에서 동작하는 게임을 만드는 것은 전체 과정의 절반에 불과했습니다. 나머지 절반은 토스 앱이라는 실제 환경에서 동작하게 만드는 것이었습니다.

앱인토스 플랫폼에 미니앱을 올리려면 단순히 빌드 파일을 업로드하는 것이 아닙니다. 토스 앱의 네이티브 기능과 연동하고, 광고 SDK를 통합하고, 플랫폼의 심사 기준을 통과해야 합니다. 이 과정에서 겪은 실전 경험들을 정리했습니다.

2. 광고 연동: 수익화의 시작

앱인토스의 광고 시스템

앱인토스는 자체 광고 SDK를 제공합니다. 미니앱 개발자가 광고를 통해 수익을 얻을 수 있도록, 전면 광고(Interstitial)와 보상형 광고(Rewarded) 두 가지 타입을 지원합니다.

이 게임에서는 두 가지 광고를 모두 활용했습니다:

[광고 배치 전략]

전면 광고 (Interstitial):
  → 게임 오버 후 재시작할 때 노출
  → 게임 플레이 흐름을 방해하지 않는 자연스러운 타이밍
  → 유저가 "다시 하기"를 누른 시점 = 잠시 쉬어가는 구간

보상형 광고 (Rewarded):
  → 하트를 모두 잃었을 때, "부활" 옵션으로 제공
  → 30~60초 광고를 시청하면 하트 1개 복구
  → 라운드당 1회만 사용 가능 (밸런스 유지)

보상형 광고의 "라운드당 1회" 제한은 게임 밸런스 때문입니다. 무제한으로 부활할 수 있으면 사실상 게임 오버가 없어지고, 그러면 하트 시스템 자체가 무의미해집니다. 1회 부활은 "한 번의 기회"라는 가치를 부여하면서, 광고 시청에 대한 보상으로서도 적절한 수준입니다.

광고 프리로딩의 중요성

광고 연동에서 가장 신경 써야 할 부분은 로딩 시간입니다. 유저가 "부활" 버튼을 눌렀는데 광고가 3~5초 동안 로딩되면, 그 사이에 이탈할 확률이 높습니다.

[광고 프리로딩 전략]

앱 시작 시:
  → 전면 광고 프리로드 시작
  → 보상형 광고 프리로드 시작
  → 각각의 로드 완료 상태를 추적

광고 노출 시:
  → 프리로드된 광고가 있으면 → 즉시 표시 (0초 대기)
  → 프리로드 실패했으면 → 로딩 스피너 표시 후 실시간 로드

광고 표시 후:
  → 다음 노출을 위해 새 광고 프리로드 시작

이 프리로딩 로직을 게임 로직 훅에서 관리했습니다. 앱이 마운트되는 시점에 광고를 미리 불러두고, 실제로 필요한 시점에는 이미 준비된 광고를 바로 보여주는 방식입니다.

개발/운영 환경 분리

광고 SDK에는 테스트용 광고 ID와 실제 서비스용 광고 ID가 있습니다. 개발 중에 실제 광고를 호출하면 정책 위반이 될 수 있고, 반대로 프로덕션에 테스트 광고가 나가면 수익이 발생하지 않습니다.

[환경별 광고 ID 관리]

개발 환경 (로컬 개발 서버):
  → 테스트 전면 광고 ID 사용
  → 테스트 보상형 광고 ID 사용
  → 실제 광고 요청 없이 모킹된 광고 표시

프로덕션 환경 (빌드 후 배포):
  → 실제 전면 광고 ID 사용
  → 실제 보상형 광고 ID 사용
  → 실제 광고 네트워크에서 광고 수신

판별 기준:
  → 앱인토스 SDK의 환경 감지 API 활용
  → 토스 앱 내부인지 외부 브라우저인지에 따라 분기

3. 네이티브 브릿지: WebView와 토스 앱의 소통

브릿지가 필요한 이유

웹앱은 브라우저(또는 WebView) 안에서 실행됩니다. 하지만 토스 앱 안에서 돌아가려면 네이티브 기능과 소통해야 할 때가 있습니다. 뒤로가기 버튼, 상단 네비게이션 바, 제스처 처리 등이 대표적입니다.

앱인토스에서는 두 가지 이벤트 브릿지를 제공합니다:

[이벤트 브릿지 구조]

1. graniteEvent (기본 네비게이션)
   → 뒤로가기 버튼 처리
   → 웹앱에서 네이티브 뒤로가기를 가로채서 커스텀 동작 가능
   → 예: 게임 중 뒤로가기 → "정말 나가시겠습니까?" 대신 게임 초기화

2. tdsEvent (상단 바 인터랙션)
   → 네비게이션 바의 액세서리 버튼 이벤트 수신
   → 예: "게임 방법" 버튼 → 게임 규칙 바텀시트 열기

네비게이션 바 커스터마이징

granite.config.ts에서 네비게이션 바를 설정할 수 있습니다. 이 게임에서는 뒤로가기 버튼과 "게임 방법" 액세서리 버튼을 배치했습니다.

[네비게이션 바 구성]

좌측: ← 뒤로가기 버튼 (네이티브 기본)
우측: ℹ️ "게임 방법" 버튼 (커스텀 액세서리)

"게임 방법" 버튼 클릭 시:
  → tdsEvent로 'game-info' ID의 이벤트 수신
  → React 상태 변경 → 바텀시트 표시
  → 바텀시트에 게임 규칙, 점수 체계, 팁 등 표시

이 과정에서 한 가지 주의할 점이 있었습니다. 이벤트 리스너를 등록할 때 해당 API가 존재하는지 먼저 확인해야 합니다. 로컬 개발 서버에서는 토스 앱의 네이티브 브릿지가 없으므로, try-catch로 감싸서 브릿지가 없는 환경에서도 앱이 크래시되지 않도록 처리해야 합니다.

[안전한 브릿지 접근 패턴]

이벤트 등록 시:
  try:
    브릿지 API에 이벤트 리스너 등록
  catch:
    조용히 실패 (로컬 개발 환경에서는 정상적인 상황)

이유:
  → 로컬 개발 서버에서는 토스 앱 브릿지가 없음
  → 외부 브라우저에서 직접 접근하는 경우에도 대비
  → 브릿지 없이도 기본 동작은 가능하도록 구현

뒤로가기 제스처 처리

토스 앱에서는 화면 좌측 가장자리를 스와이프하면 뒤로가기가 동작합니다. 게임 플레이 중에 실수로 스와이프해서 게임이 종료되는 것을 방지하기 위해, graniteEvent로 뒤로가기 이벤트를 가로채서 처리했습니다.

게임 중 뒤로가기가 감지되면, 현재 게임을 리셋하고 초기 화면으로 돌아갑니다. 앱 자체를 닫는 것이 아니라, 게임 내에서 상태를 초기화하는 방식입니다.

4. 앱 심사: 반려와 대응

첫 번째 반려

앱인토스에 미니앱을 제출하면 심사 과정을 거칩니다. 토스 앱 안에서 서비스되는 만큼, 사용자 경험과 안정성에 대한 기준이 있습니다.

첫 번째 제출에서 반려를 받았습니다. 반려 사유는 네비게이션 관련이었습니다.

[첫 번째 반려 사유]

문제:
  → 네비게이션 바의 동작이 플랫폼 가이드라인과 맞지 않음
  → 뒤로가기 버튼의 동작이 기대와 다름

대응:
  → 네비게이션 이벤트 처리 로직 수정
  → 뒤로가기 시 게임 상태에 따른 적절한 동작 분기
  → 토스 앱의 네비게이션 패턴과 일관성 확보

두 번째 반려와 해결

수정 후 재제출했지만, 또 한 번 반려를 받았습니다. 이번에는 좀 더 세부적인 네비게이션 동작에 대한 피드백이었습니다.

[두 번째 반려와 최종 해결]

문제:
  → 게임 네비게이션의 특정 엣지 케이스에서
    토스 앱의 기대 동작과 불일치

대응:
  → GameNavigation 컴포넌트 전면 재검토
  → 모든 게임 상태(idle/playing/revealing/gameover)에서
    뒤로가기 동작을 일관성 있게 처리
  → 심사 피드백의 구체적 시나리오를 재현하고 수정

심사 반려는 처음에 좌절감을 주지만, 돌이켜보면 사용자 경험을 개선하는 기회이기도 했습니다. 네비게이션 동작은 "개발자가 보기에 괜찮은" 수준과 "사용자가 기대하는" 수준 사이에 갭이 있을 수 있고, 심사 과정이 그 갭을 메워주는 역할을 합니다.

심사 통과를 위한 체크리스트

두 번의 반려를 거치면서 정리한 앱인토스 심사 대응 체크리스트입니다:

[심사 대응 체크리스트]

네비게이션:
  ✓ 뒤로가기 버튼이 모든 화면에서 적절하게 동작하는가
  ✓ 스와이프 뒤로가기 제스처가 예상대로 동작하는가
  ✓ 네비게이션 바의 액세서리 버튼이 정상 작동하는가
  ✓ 앱 진입/이탈 시 상태가 깔끔하게 관리되는가

성능:
  ✓ 초기 로딩이 합리적인 시간 내에 완료되는가
  ✓ 애니메이션이 저사양 기기에서도 부드러운가
  ✓ 메모리 누수가 없는가 (특히 차트 인스턴스)

광고:
  ✓ 광고가 적절한 타이밍에 노출되는가
  ✓ 광고 로딩 실패 시 앱이 크래시되지 않는가
  ✓ 보상형 광고 시청 후 보상이 정상 지급되는가

사용자 경험:
  ✓ 게임 규칙이 명확하게 안내되는가
  ✓ 오류 상황에서 적절한 피드백이 있는가
  ✓ 다양한 화면 크기에서 레이아웃이 정상인가

5. 배포 후 느낀 점

Granite CLI의 개발 경험

앱인토스 개발에 사용하는 Granite CLI는 전체적으로 괜찮은 개발 경험을 제공합니다. granite dev로 로컬 서버를 띄우고, 토스 앱에서 QR 코드를 스캔하면 실제 앱 환경에서 바로 테스트할 수 있습니다. 이 워크플로우 덕분에 "빌드 → 배포 → 확인" 사이클이 짧아져서 빠르게 이터레이션할 수 있었습니다.

WebView의 한계와 가능성

WebView 기반이라는 점은 장점이자 단점입니다.

장점:

  • 웹 개발 스킬만으로 네이티브 앱에 가까운 경험을 만들 수 있음
  • 배포가 빠름 (앱스토어 심사보다 훨씬 신속)
  • 웹 생태계의 모든 라이브러리 활용 가능

한계:

  • 네이티브 대비 성능 오버헤드 (특히 애니메이션)
  • 브릿지 API의 제약 (네이티브의 모든 기능에 접근할 수는 없음)
  • 디버깅이 까다로움 (WebView 내부의 에러를 추적하기 어려운 경우)

그럼에도 토스라는 대규모 플랫폼의 트래픽에 접근할 수 있다는 점은, 사이드 프로젝트 개발자에게 매우 매력적인 기회입니다.

6. 시리즈를 마치며: 전체 회고

5편에 걸쳐 차트예측게임의 기획부터 배포까지를 다뤘습니다. 전체를 돌아보면:

1편 (기획과 시작): 토스 생태계 안에서 주식 차트 게임을 만들겠다는 아이디어와 기술 스택 선정

2편 (게임 로직): 실제 주식 데이터를 게임으로 가공하는 파이프라인, 점수·콤보·하트 시스템 설계, 선형 회귀 트렌드라인과 부동소수점 정밀도 문제

3편 (상태 관리): Zustand 선택적 구독 패턴, View/Logic 분리, 4-phase 페이즈 기반 UI 관리

4편 (차트와 애니메이션): lightweight-charts 캔들스틱 렌더링, framer-motion 게임 피드백, 모바일 성능 최적화

5편 (배포): 광고 SDK 연동, WebView-네이티브 브릿지, 심사 반려 대응

숫자로 보는 프로젝트

  • 개발 기간: 약 2주 (1월 23일 ~ 2월 9일)
  • 핵심 코드: 약 1,600줄의 TypeScript/TSX
  • 외부 의존성: 10개 (프레임워크 + 라이브러리)
  • 주식 데이터: 5종목, 약 1,300 거래일
  • 가능한 시나리오: 750+ 조합
  • 심사 제출: 3회 (2회 반려 + 1회 통과)

배운 점

이 프로젝트를 통해 가장 크게 배운 것은, **"작게 만들고 빨리 배포하라"**는 교훈의 실질적 의미입니다. 2주라는 짧은 기간에 기능을 최소화하고, 핵심 게임 루프만 완성한 뒤 바로 심사에 제출했습니다. 심사 과정에서 피드백을 받고 수정하는 것이, 혼자 완벽하게 만들려고 오래 붙잡고 있는 것보다 훨씬 효율적이었습니다.

또 하나는, 플랫폼의 제약이 오히려 좋은 설계를 강제한다는 점입니다. WebView의 성능 한계 때문에 애니메이션을 최적화해야 했고, 앱인토스의 네비게이션 가이드라인 때문에 뒤로가기 처리를 꼼꼼히 해야 했습니다. 이런 제약 없이 자유롭게 만들었다면 아마 대충 넘어갔을 부분들입니다.

향후 계획

  • 종목 데이터 업데이트 (2025년 데이터 추가)
  • 난이도 시스템 도입 (쉬움/보통/어려움)
  • 랭킹 시스템 (서버 연동 필요)
  • 다양한 차트 패턴 학습 모드

사이드 프로젝트는 완성이 없습니다. 하지만 "일단 출시"까지 도달했다는 것 자체가 가장 큰 성과라고 생각합니다. 이 시리즈가 앱인토스 플랫폼에 관심 있는 개발자분들에게 조금이나마 도움이 되었으면 합니다.

👉 차트예측게임 바로가기