Mbtigram / 03 /

Consume last

인앱 결제에서 소비는 맨 마지막에

구글 플레이 결제에서 소비(consume)를 먼저 하면 지급이 실패했을 때 되살릴 길이 없음. 결제창부터 코인 지급까지의 순서와 콘솔에서 막혔던 것들 정리.

코인은 인앱 결제로만 판매

Mbtigram은 웹 화면을 앱 껍데기(WebView)에 띄우는 구조임. 그래서 웹에 결제를 붙이면 앱에도 그대로 따라 들어감. 그런데 앱 안에서 쓰는 디지털 재화를 외부 결제로 팔면 스토어 정책 위반이라 앱이 내려감. 그래서 코인은 구글 플레이 인앱 결제로만 팔고, 웹 결제는 아예 붙이지 않았음. 결제창은 네이티브 쪽이 열고 나머지는 서버가 처리함.

결제 순서

플레이 결제는 네 단계임. 결제창을 띄우고, 구매 토큰을 받고, 서버가 그 토큰을 구글에 확인한 뒤 코인을 주고, 마지막으로 구매를 "소비(consume)" 처리함. 소비해야 같은 상품을 다시 살 수 있음.

  1. 결제창 (네이티브)
  2. 구매 토큰 받기
  3. 서버 검증 · 코인 지급
  4. 소비

소비를 먼저 하면 안 됨. 소비하는 순간 토큰이 사라짐. 그다음 서버 지급이 실패하면 사용자는 돈을 냈는데 코인을 못 받고, 그걸 되살릴 근거도 남지 않음.

지급을 먼저 하면 지급 뒤 소비가 실패해도 괜찮음. 다음에 앱을 열 때 밀린 구매를 다시 올려 보내는 restore()가 같은 토큰을 서버로 보냄. 서버는 토큰을 기본 키로 저장해 둬서 같은 토큰에 두 번 주지 않고 "이미 줬다(already: true)"고만 답함. 몇 번을 다시 보내도 코인은 한 번만 들어감.

지급량은 서버가 정함

앱이 "1000코인 샀어요"라고 보내도 서버는 그 숫자를 안 봄. 상품 ID만 받아서 서버에 있는 표에서 지급량을 찾음. 앱 쪽 값을 믿으면 요청을 조작해서 코인을 마음대로 받을 수 있기 때문. 그래서 상품 ID는 플레이 콘솔에 등록한 것과 글자 하나까지 같아야 함.

구글에 구매를 확인할 자격 증명이 서버에 없으면 구매를 전부 거절하게 했음. 푸시 알림은 설정이 빠져 있어도 조용히 건너뛰고 나머지는 돌게 뒀는데, 돈은 반대로 잠그는 게 맞음.

ITEM_ALREADY_OWNED 오류

테스트하다 보면 이 오류를 자주 봄. 버그는 아님. 소비되지 않은 구매가 남아 있으면 플레이가 같은 상품의 재구매를 막는 것으로, 중복 결제를 막는 장치임. 대부분 서버 지급이 실패해서 소비까지 못 간 경우임.

그래서 앱은 이 오류를 실패로 끝내지 않음. 밀린 구매를 restore()로 다시 올려 보내고, 화면에는 "지난 구매를 확인하고 있어요"를 띄움.

그리고 확인되지 않은 구매는 플레이가 자동으로 취소하고 환불함. 서버 검증이 막혀 있는 동안 결제 테스트를 반복하면 결제와 취소 기록만 쌓이고 결제 취소 문자가 연달아 옴.

콘솔에서 막혔던 것

  • 권한을 줘도 한동안 401이 났음. 서버가 구매를 확인하려면 서비스 계정을 플레이 콘솔에 초대하고 재무 권한을 줘야 함. 준 직후에는 The current user has insufficient permissions가 몇 분에서 몇 시간까지 이어졌음. 토큰 발급이 된다고 권한까지 있는 건 아님. (덧붙임: 우리 경우는 기다려서 풀리는 문제가 아니었음. 후속 글 참고)
  • 가격을 안 넣으면 원인을 알 수 없는 오류가 뜸. 인앱 상품을 가격 없이 활성화하면 예기치 않은 오류 (4CA604A1)만 나옴. 국가 전체를 골라 가격을 일괄로 넣으면 풀림.
  • 직접 설치한 앱으로는 결제 테스트가 안 됨. 헷갈리는 건 막히는 위치임. 결제 연결까지는 되고, 상품 조회에서 "상품 없음"이 나옴. 플레이 콘솔의 내부 앱 공유 링크로 받아야 결제창이 뜸.
  • 결제 라이브러리는 8 이상이어야 함. 콘솔이 8 미만을 오류로 막음. 7에서 올리면 상품 조회 결과가 목록 대신 결과 객체로 와서 그 한 군데가 깨짐. 못 찾은 상품은 따로 담겨 오니 로그에 찍어 두면 상품 ID 오타를 바로 잡을 수 있음.