본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 07. 22:47

RevenueCat을 사용하여 React Native 밈 봇에 구독 기능 추가하기

요약

React Native 기반의 밈 봇 앱에 RevenueCat을 사용하여 인앱 구독 기능을 효율적으로 통합하는 방법을 설명합니다. Apple과 Google의 복잡한 결제 시스템을 하나의 SDK로 관리하여 개발 비용을 절감하는 실무적인 가이드를 제공합니다.

핵심 포인트

  • RevenueCat을 통해 iOS와 Android 결제 로직 통합 관리 가능
  • 서버 측 검증, 구매 복원, 유예 기간 등 복잡한 예외 상황 해결
  • 코드 수정 없이 대시보드에서 가격 및 상품 설정 변경 가능
  • Expo 및 React Native 환경에서 react-native-purchases SDK 활용

저는 여러분에게 밈(meme)을 보내고, GIF를 찾아내며, 여러분을 놀리는(roast) 챗봇을 만들었습니다. 이름은 MemeChatAI이며, 의도적으로 아주 '브레인롯(brainrot, 뇌가 녹는 듯한 저급한 콘텐츠)' 스타일로 제작되었습니다. 여러분이 말을 걸면, 챗봇은 자신이 할 수 있는 가장 멍청하고 재미있는 방식으로 대답합니다. 그것이 이 서비스의 전부입니다.

그런데 농담 같은 앱을 만들 때 아무도 경고해주지 않는 사실이 하나 있습니다. 농담을 만드는 것은 쉽지만, 거기에 돈을 받는 것은 진짜 엔지니어링 프로젝트라는 점입니다. 봇을 만드는 것은 즐거운 주말 과제였지만, 결제 시스템은 제가 실수할 경우 실제로 사람들의 돈을 잃게 만들 수 있는 부분이었습니다. 제가 이 이야기를 하고 싶은 이유는 바로 RevenueCat이 그 작업의 대부분을 대신 처리해주었기 때문입니다.

내가 떠맡고 싶지 않았던 문제

인앱 구독(in-app subscriptions)을 출시해 본 적이 없다면, 여러분이 어떤 상황에 직면하게 될지 짧게 요약해 드리겠습니다. Apple은 자체적인 영수증과 갱신 규칙을 가지고 있습니다. Google은 또 다릅니다. 무엇인가를 신뢰하고 싶다면 두 곳 모두 서버 측 검증(server-side validation)이 필요합니다. 그 외에도 구매 복원(restoring purchases), 업그레이드, 다운그레이드, 무료 체험(free trials), 결제 카드가 거절되었을 때의 유예 기간(grace periods), 그리고 사용자가 iPhone에서 구매한 후 Android 태블릿에서 로그인했을 때 자신의 데이터가 그대로 있기를 기대하는 아주 골치 아픈 예외 상황(edge case) 등이 있습니다.

이 모든 것을 직접 구축하는 데 드는 비용을 계산해 보았고, 저는 그러지 않기로 결정했습니다. 고작 '놀리는 봇'을 위해서 말이죠. 자랑스럽지는 않지만, 후회도 없습니다.

RevenueCat은 기본적으로 앱과 양대 스토어 사이에 위치하여 이 모든 것을 하나의 SDK와 하나의 웹훅(webhook)으로 변환해 주는 계층입니다. 이것이 핵심 요약이며, 제 경우에는 대부분 그대로 유지되었습니다.

하나의 SDK로 두 스토어 모두 대응

이 앱은 Expo 기반의 React Native로 제작되었으며, react-native-purchases(v10)를 사용합니다. 동일한 코드 경로가 iOS와 Android에서 모두 실행됩니다. Apple의 StoreKit과 Google의 Billing Client가 모두 하나의 API 뒤에 숨겨져 있으므로, 시간이 지나면서 서로 달라질 수 있는 두 개의 네이티브 결제 통합(native billing integrations)을 따로 관리할 필요가 없습니다.

가격, 상품, 그리고 체험 기간은 제 코드 내에 있는 것이 아니라 RevenueCat 대시보드에 저장됩니다. 앱은 이를 "오퍼링(offerings)"로 내려받아 반환되는 결과물을 그대로 렌더링합니다:

const offerings = await Purchases.getOfferings();
const pkg = offerings.current.availablePackages[0];

...

하드코딩된 것은 아무것도 없습니다. 가격은 지역별로 자동 현지화(localize)되며, "구매 복원(Restore Purchases)"은 단 한 줄이면 충분합니다:

await Purchases.restorePurchases();

여기서 얻는 조용한 승리는, 앱 업데이트를 배포하거나 이틀 동안 심사 대기열(review queue)에서 기다릴 필요 없이 대시보드에서 가격을 변경하거나 무료 체험(trial)을 조정할 수 있다는 점입니다. 이제 가격은 코드가 아니라 설정(config)입니다. 이것만으로도 저는 이미 여러 번 위기를 넘겼습니다.

권한(Entitlements)은 유일한 진실의 원천(source of truth)입니다

이 부분이 나머지 과정을 합리적으로 만들어준 핵심입니다. 앱이 가공되지 않은 영수증(raw receipts)을 분석하려고 애쓰는 대신, 모든 것은 pro라고 불리는 단일 권한(entitlement)으로 해결됩니다. 거기서부터 저는 RevenueCat의 제품들을 free, basic, plus, power라는 네 가지 내부 티어(tier)로 매핑합니다. 이 매핑은 한 곳에 존재하며 클라이언트와 서버 간에 공유되므로,

Cloud Function이 RevenueCat 웹훅 (webhook) 이벤트(INITIAL_PURCHASE, RENEWAL, PRODUCT_CHANGE, EXPIRATION, CANCELLATION, BILLING_ISSUE, TRANSFER 및 기타 관련 이벤트)를 수신하여 사용자의 플랜을 데이터베이스에 기록합니다. RevenueCat이 단 하나의 진실 공급원 (source of truth)입니다.

결제 버그는 최악의 버그 중 하나이기에, 제가 확실히 해둔 몇 가지 사항이 있습니다:

  • 이벤트는 멱등성 (idempotent)을 가집니다. 이벤트 ID를 통해 중복을 제거하므로, 재시도(retry)가 동일한 업그레이드를 두 번 적용할 수 없습니다.
  • 쓰기 작업은 트랜잭션 (transactional) 방식으로 이루어집니다.
  • 샌드박스 (Sandbox) 및 테스트 이벤트는 운영 환경에서 차단되어 있으므로

솔직히 말씀드리고 싶습니다. 저는 "이 도구는 완벽합니다"라고 말하는 게시물들이 무익하다고 생각하기 때문입니다. 결제 정보의 단일 진실 공급원 (source-of-truth)을 제3자에게 맡기는 것은 실질적인 의존성 (dependency)을 만드는 일이며, 저 또한 이 점에 대해 깊이 고민했습니다. 만약 RevenueCat에 문제가 생긴다면, 저의 구매 내역에도 문제가 생길 것입니다. 무료 티어 (free tier)를 넘어서면 비용이 발생하며, 이 모든 편리함을 얻는 대신 어느 정도의 통제권을 맞바꾸는 셈입니다.

두 개의 스토어에 밈 봇을 출시하는 1인 개발에 가까운 프로젝트에게는, 분명 그만한 가치가 있는 거래였습니다. 하지만 구독 모델이 비즈니스의 전부이며 대규모로 운영되는 기업이라면, 적어도 더 오래 고민해 봐야 할 문제입니다. 결정은 여러분의 몫입니다.

여기서 정확한 정보 하나를 덧붙이자면, RevenueCat은 사용자의 카드를 보거나 저장하지 않습니다. 실제 트랜잭션 (transaction)은 Apple과 Google이 실행합니다. RevenueCat은 그 위에서 권한 (entitlements)을 관리할 뿐입니다. 저 또한 문서를 읽기 전까지는 이 부분이 다소 모호했기에 명확히 짚고 넘어갑니다.

결론

MemeChatAI의 멍청한 부분을 만드는 데는 주말이 걸렸습니다. 하지만 결제 시스템을 구축하는 데는 정말 세심한 주의를 기울였고, 그 주의의 대부분은 두 스토어의 영수증 검증 (receipt validation)을 다시 구현하는 것이 아니라, 위에 언급한 반 페이지 분량의 웹훅 (webhook) 로직을 짜는 데 들어갔습니다. 이것이 제가 다시 선택하더라도 똑같이 할 거래입니다.

봇에게 혹평을 듣고 싶다면 App Store에서 확인하실 수 있으며, 더 많은 정보는 meme-chat-ai.com에 있습니다. 미리 경고해 두는데, 이 봇은 예의가 없습니다. 그것 또한 하나의 기능입니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0