ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 구글 구독시 3일 후 자동 환불 케이스 분석
    장애대응 2023. 3. 23. 00:01
    728x90

    개요 및 영향범위 분석

    사용자가 구독상품을 결제한 뒤 3일 뒤에 자동으로 환불되는 경우가 발생하였습니다.

    서버로직에서는 사용자가 결제한 구독상품에 대한 정보를 저장하고, 해당 상품의 구독 정보를 제3의 외부 저장시스템에 저장합니다.

    이때 무료상품에 대한 만기일은 1 달이지만 유료상품에 대한 만기일은 무기한입니다.

     

    이런 경우 사용자는 구독중이라고 뜨지만 실제로 구독을 해지하러 가는 경우 구글 플레이스토어에서는 구독 중인 상품이 보이지 않습니다.

    (이미 자동으로 환불되었기 때문)

     

    사용자에게는 실제로 돈은 청구되지 않지만 구독중이며 N월 N일부터 매월 N원 자동 결제 예정이라는 문구가 표기됩니다.

    이로 인해 사용자는 혼란에 빠질 수 있으며 VOC가 발생합니다. (문구를 보고 구독을 취소하러 갔지만 구독 중인 상품이 보이지 않음)

     

    하지만 서버는 어떠한 이벤트도 받지 못했기 때문에 fallback 로직을 처리할 수 없습니다.

    비즈니스적으로 문제는 사용자는 무료로 서비스를 계속 이용할 수 있는 문제가 존재합니다.

     

    원인

    aos의 경우에는 구매를 확인하기 위해 acknowlege를 전송하는도중 네트워크 connection이 끊어지게 되고 이로 인해 3일 뒤에 환불 발생

    ios의 경우에는 구독성공 acknowledge 전송하는 부분이 없어서 결제 시도 시 무조건 완료로 처리

     

    구글의 구독 결제 프로세스 이해하기

    Google Play의 결제 시스템을 사용하면 콘텐츠나 서비스 요금을 사용자에게 정기적으로 청구하는 인앱 상품을 제공할 수 있으며, 이를 정기 결제라고 합니다.

     

    자동 갱신 및 선불 요금제를 사용하여 정기 결제 수명 주기동안 사용자가 액세스 할 수 있도록 만들 수 있습니다.

     

    다음과 같은 기본 요금제를 만들 수 있습니다.

    • 월간 자동 갱신 기본 요금제(결제 기간이 끝날 때마다 자동 청구를 통해 사용 권한이 연장됨)
    • 월간 선불 기본 요금제(사용자가 직접 종료일을 연장)
    • 연간 자동 갱신 기본 요금제

     

    구매 진행 과정

    • 사용자에게 구입할 수 있는 항목을 보여줍니다.
    • 사용자가 구매를 수락할 수 있도록 구매 흐름을 시작합니다.
    • 서버에서 구매를 인증합니다.
    • 사용자에게 콘텐츠를 제공합니다.

    정기 결제의 상태

    • 활성 : 사용자가 콘텐츠 사용에 문제가 없으며 정기 결제에 액세스 할 수 있습니다
    • 취소 : 사용자가 정기 결제를 취소했지만 만료 시까지 계속 액세스할 수 있습니다
    • 유예기간 : 사용자에게 결제 문제가 발생했지만 Google에서 결제 수단을 다시 시도하는 동안 사용자가 계속 액세스 할 수 있습니다
    • 보류 : 유예기간과 달리 결제 수단을 다시 시도하는 동안 사용자가 액세스 할 수 없습니다
    • 일시중지 : 액세스를 일중지했으며 다시 시작할 때까지 액세스할 수 없습니다
    • 만료 : 사용자가 정기 결제를 취소했으며 정기 결제 액세스 권한을 잃었습니다, 사용자가 이탈한 것으로 간주합니다

     

    Google Play 연결 초기화

    앱에서 Bilingclient를 활용하여 여러 일반적인 결제 작업을 처리하는 메서드를 지원합니다.

    BilingResult 형식으로 오류를 반환하며 어떤 오류 코드의 경우에는 Google Play와 연결을 다시 초기화해야 합니다.

     

    BilingClient의 startConnectiond을 통해 비동기적으로 연결을 수행하고 BilingClientStatelistener를 구현하여 콜백을 수신합니다.

    만약 연결이 끊어진 경우 onBilingServiceDisconnected 콜백 메서드를 재정의하여 재시도 로직을 구현할 수 있습니다.

     

    구입 가능한 제품 표시

    연결이 완료되면 구매 가능한 제품을 쿼리하여 사용자에게 표시할 수 있습니다.

     

    구매 흐름 시작

    launchBuilingFlow 메서드를 통해 구매 요청을 시작합니다.

    이때 BuilingResponseCode가 OK라면 성공적으로 시작되었음을 나타냅니다.

     

    사용자는 다음과 같은 화면을 볼 수 있습니다.

    그림 1. Google Play 구매 화면에 구매할 수 있는 정기 결제가 표시됨

    이후 onPrucasesUpdate를 호출하여 사용자의 응답상태에 따라 로직을 처리하고 구매 성공 시 Google Play 구매 성공 화면이 생성됩니다.

    그림 2. Google Play의 구매 성공 화면

    구매 성공 시 인앱 상품의 사용자 및 제품 ID를 나타내는 고유 식별자인 구매 토큰이 생성됩니다.구매를 인증하고 사기로부터 보호할 수 있는 보안 백엔드 서버로 해당 토큰을 전달하는 것이 좋습니다.

     

    또한 사용자는 주문 ID 또는 거래의 고유 ID가 포함된 거래 영수증을 이메일로 받습니다.최초 정기 결제 구매 및 후속 구매가 자동 갱신될 때마다 주문 ID가 포함된 이메일을 받습니다.

     

    Google Play Console에서 주문 ID를 사용하여 환불을 관리할 수 있습니다.

     

    구매 처리

    사용자가 구매를 완료하면 앱에서 구매를 처리해야 합니다.해당 영역은 백엔드에서 처리하는 것이 좋습니다.앱은 다음과 같은 방식으로 구매를 처리해야 합니다.

    • 구매를 인증합니다. (구매 상태가 PURCHASED인지 확인 + 구매를 추가로 인증)
      • 구매 상태가 PENDING인 경우 자격을 부여하면 안 됩니다.
      • 모든 구매에서 orderId가 생성되지 않으므로 데이터베이스의 기본키로 사용하면 안 됩니다(프로모션 코드로 구매하면 orderId가 생성되지 않습니다) 
      • purchaseToken을 백엔드로 전송하여 이전의 purchaseToken값과 일치하는지 확인하며, Purchases.products:get 또는 Purchases.subscriptionv2:get 엔드포인트를 사용하여 구매가 합법적인지 Google로 확인할 수 있습니다.
      • 만약 구매가 합법적이고 과거에 사용되지 않았다면 인앱 상품 또는 정기 결제에 안전하게 자격을 부여할 수 있습니다.
      • 정기 결제의 경우 Purchases.subscritionsv2:get에 linkedLurchaseToken이 설정될 때 데이터베이스에서 linkedPurchaseToken을 삭제하고 부여된 자격을 취소하여 여러 사용자에게 동일한 구매 자격이 부여되지 않도록 해야 합니다.
    • 사용자에게 콘텐츠를 제공하고 콘텐츠 전송을 확인합니다.

    이제 앱에서 사용자에게 자격을 부여할 준비가 완료되었습니다.

    앱에서 구매를 확인하여 Google Play에게 알려주어야 합니다.

     

    *주의 : 3일 이내에 구매를 확인하지 않으면 사용자에게 자동으로 환불되고 Google Play에서 구매를 취소합니다.

    (저희가 겪고 있는 사항입니다)

     

    자격을 부여하고 구매를 확인하는 프로세스는 구매가 소비성, 비소비성, 정기결제에 따라 다릅니다.

    정기 결제의 경우에는 Builingclient의 acknowlegePurchase 또는 Purcases.Subscritions.Acknowlege를 사용하여 정기 결제 확인을 할 수 있습니다.

     

    최초 정기 결제 구매를 모두 확인해야 하며, 정기 결제 갱신은 확인하지 않아도 됩니다.

     

    Purchases.subscriptions.acknowlege(관련 문서로 이동)

     

    정기 결제 구매를 확인합니다.

     

     

    필요한 경로 매개변수

    • packagedName : 이 구독을 구매한 애플리케이션의 패키지 이름 (예 : 'com.somg.thing')
    • subscriptionId : 구매한 구독 ID (예: 'month001')
    • token : 구독을 구매할 때 사용자 기기에 제공되는 토큰

    요청 본문

    {
      "developerPayload": string
    }

    developerPaylod는 구매에 연결할 페이로드를 의미합니다.

     

    응답 본문

    • 성공한 경우 응답 본문은 비어 있습니다.

     

    승인 범위(필요한 OAuth 범위)

    purchase.subscrptionv2:get (관련 문서로 이동)

     

    필요한 경로 매개변수

    • packagedName : 이 구독을 구매한 애플리케이션의 패키지 이름 (예 : 'com.somg.thing')
    • token : 구독을 구매할 때 사용자 기기에 제공되는 토큰

    응답 본문

    {
      "kind": string,
      "regionCode": string,
      "latestOrderId": string,
      "lineItems": [
        {
          object (SubscriptionPurchaseLineItem)
        }
      ],
      "startTime": string,
      "subscriptionState": enum (SubscriptionState),
      "linkedPurchaseToken": string,
      "pausedStateContext": {
        object (PausedStateContext)
      },
      "canceledStateContext": {
        object (CanceledStateContext)
      },
      "testPurchase": {
        object (TestPurchase)
      },
      "acknowledgementState": enum (AcknowledgementState),
      "externalAccountIdentifiers": {
        object (ExternalAccountIdentifiers)
      },
      "subscribeWithGoogleInfo": {
        object (SubscribeWithGoogleInfo)
      }
    }

    subscriptionState는 정기 결제의 현재 상태를 나타냅니다.

    acknowledgementState는 정기 결제의 확인 상태를 나타냅니다

     

     

    subscriptionState(Enum)

    SUBSCRIPTION_STATE_UNSPECIFIED 구독 상태가 지정되지 않았습니다.
    SUBSCRIPTION_STATE_PENDING 가입이 생성되었지만 가입 과정에서 결제를 기다리는 중입니다. 이 상태에서는 모든 항목이 결제 대기 중입니다.
    SUBSCRIPTION_STATE_ACTIVE 구독이 활성 상태입니다. - (1) 정기 결제가 자동 갱신 요금제인 경우 하나 이상의 항목이 autoRenewEnabled이며 만료되지 않았습니다. - (2) 정기 결제가 선불 요금제라면 하나 이상의 항목이 만료되지 않습니다.
    SUBSCRIPTION_STATE_PAUSED 정기 결제가 일시중지되었습니다. 이 상태는 구독이 자동 갱신 요금제인 경우에만 사용할 수 있습니다. 이 상태에서 모든 항목은 일시중지 상태입니다.
    SUBSCRIPTION_STATE_IN_GRACE_PERIOD 구독은 유예 기간입니다. 이 상태는 구독이 자동 갱신 요금제인 경우에만 사용할 수 있습니다. 이 상태에서는 모든 항목이 유예 기간 상태가 됩니다.
    SUBSCRIPTION_STATE_ON_HOLD 구독이 보류 중입니다 (정지됨). 이 상태는 구독이 자동 갱신 요금제인 경우에만 사용할 수 있습니다. 이 상태에서는 모든 항목이 보존 조치됩니다.
    SUBSCRIPTION_STATE_CANCELED 정기 결제가 취소되었지만 아직 만료되지 않았습니다. 이 상태는 구독이 자동 갱신 요금제인 경우에만 사용할 수 있습니다. 모든 항목의 autoRenewEnabled가 false로 설정되었습니다.
    SUBSCRIPTION_STATE_EXPIRED 구독이 만료되었습니다. 모든 항목의 만료 시간이 과거입니다.

     

     

    acknowledgementState(Enum)


    ACKNOWLEDGEMENT_STATE_UNSPECIFIED
    확인 상태가 지정되지 않았습니다.
    ACKNOWLEDGEMENT_STATE_PENDING 구독이 아직 확인되지 않았습니다.
    ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED 구독이 확인되었습니다.

    승인 범위 (필요한 OAuth 범위)

    purchase.products.get (관련 문서로 이동)

    필요한 경로 매개변수

    • packagedName : 인앱 제품이 판매된 애플리케이션의 패키지 이름 (예 : 'com.somg.thing')
    • productId : 인앱 상품 SKU (예 : 'com.some.thing.inapp1')
    • token : 인앱 상품을 구매할 때 사용자 기기에 제공되는 토큰

    응답 본문

    {
      "kind": string,
      "purchaseTimeMillis": string,
      "purchaseState": integer,
      "consumptionState": integer,
      "developerPayload": string,
      "orderId": string,
      "purchaseType": integer,
      "acknowledgementState": integer,
      "purchaseToken": string,
      "productId": string,
      "quantity": integer,
      "obfuscatedExternalAccountId": string,
      "obfuscatedExternalProfileId": string,
      "regionCode": string
    }

    purchaseState의 경우 주문의 구매 상태를 나타냅니다.

    0 : 구매, 1 : 취소됨 2: 대기 중

     

    승인 범위 (필요한 OAuth 범위)

     

     

     

    구매 가져오기

    앱이 구매 업데이트를 수신 대기하는 것만으로 모든 구매를 처리한다고 보장할 수 없습니다.

     

    다음과 같은 경우 구매 추적을 놓치거나 인식하지 못할 수 있습니다.

    • 구매 중 네트워크 문제 : 구매가 성공적으로 완료되고 Google의 확인을 받지만 기기가 구매 알림을 받기 전 네트워크 연결이 끊어짐
    • 여러 기기 : 한 기기에서 항목을 구매 후 기기를 전환할 때 이 항목이 표시되기를 기대
    • 앱 외부에서 이루어진 구매 : 프로모션 사용과 같은 일부 구매를 앱 외부에서 이루어짐

     

     

     

     

     

    참고자료

    https://support.google.com/googleplay/android-developer/answer/12154973?hl=ko&ref_topic=3452890 

     

    정기 결제 이해하기 - Play Console 고객센터

    도움이 되었나요? 어떻게 하면 개선할 수 있을까요? 예아니요

    support.google.com

    https://developer.android.com/google/play/billing/integrate#java

     

    앱에 Google Play 결제 라이브러리 통합  |  Google Play 결제 시스템  |  Android Developers

    알림: 2022년 8월 2일부터 모든 신규 앱은 결제 라이브러리 버전 4 이상을 사용해야 합니다. 2022년 11월 1일부터는 기존 앱의 모든 업데이트에도 결제 라이브러리 버전 4 이상이 요구됩니다. 자세히

    developer.android.com

    https://developer.android.com/google/play/billing/subscriptions

     

    정기 결제 판매  |  Google Play 결제 시스템  |  Android Developers

    알림: 2022년 8월 2일부터 모든 신규 앱은 결제 라이브러리 버전 4 이상을 사용해야 합니다. 2022년 11월 1일부터는 기존 앱의 모든 업데이트에도 결제 라이브러리 버전 4 이상이 요구됩니다. 자세히

    developer.android.com

    https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptions/acknowledge

     

    Method: purchases.subscriptions.acknowledge  |  Google Play Developer API  |  Google Developers

    이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English Method: purchases.subscriptions.acknowledge 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 정기 결

    developers.google.com

     

    댓글

Designed by Tistory.