외부 결제를 위한 인앱 통합 가이드

이 문서에서는 Play 결제 라이브러리 API를 통합하여 적격 앱에서 외부 결제를 제공하는 방법을 설명합니다. 이 프로그램에 관해 자세히 알아보려면 프로그램 요구사항을 참고하세요.

Play 결제 라이브러리 설정

Android 앱에 Play Billing Library 종속 항목을 추가합니다. 외부 결제 API를 사용하려면 버전 8.3 이상을 사용해야 합니다. 이전 버전에서 이전해야 하는 경우 통합을 시작하기 전에 이전 가이드의 안내에 따라 업그레이드하세요.

결제 클라이언트 초기화

통합 프로세스의 첫 번째 단계는 Google Play 결제 통합 가이드에 설명된 단계와 동일하되 BillingClient 초기화에 약간의 수정이 적용됩니다.

다음 예는 이러한 수정을 적용하여 BillingClient를 초기화하는 방법을 보여줍니다.

Kotlin

val purchasesUpdatedListener =
    PurchasesUpdatedListener { billingResult, purchases ->
        // Handle new Google Play purchase.
    }

val developerProvidedBillingListener =
    DeveloperProvidedBillingListener { details ->
        // Handle user selection for developer provided billing option.
    }

val billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .enableBillingProgram(
        EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.EXTERNAL_PAYMENTS)
            .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
            .build())
    .build()

Java

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        // Handle new Google Play purchase.
    }
};

private DeveloperProvidedBillingListener developerProvidedBillingListener =
    new DeveloperProvidedBillingListener() {
        @Override
        public void onUserSelectedDeveloperBilling(
            DeveloperProvidedBillingDetails details) {
            // Handle user selection for developer provided billing option.
        }
    };

private BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .enableBillingProgram(
        EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.EXTERNAL_PAYMENTS)
            .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
            .build())
    .build();

Google Play에 연결

BillingClient를 초기화한 후 Google Play에 연결에 설명된 대로 Google Play에 연결합니다.

사용자 자격 확인

Google Play에 연결한 후 사용자가 외부 결제 프로그램을 이용할 수 있는지 isBillingProgramAvailableAsync() 메서드를 호출하여 확인할 수 있습니다. 이 메서드는 사용자가 이용할 수 있는 경우 BillingResponseCode.OK를 반환합니다. 다음 샘플은 자격을 확인하는 방법을 보여줍니다.

Kotlin

billingClient.isBillingProgramAvailableAsync(
  BillingProgram.EXTERNAL_PAYMENTS,
  object : BillingProgramAvailabilityListener {
    override fun onBillingProgramAvailabilityResponse(
      billingProgram: Int, billingResult: BillingResult) {
        if (billingResult.responseCode != BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors,
            // handling external payments unavailable, etc.
            return
        }

        // External payments are available. Can proceed with generating an
        // external transaction token.
})

Java

billingClient.isBillingProgramAvailableAsync(
  BillingProgram.EXTERNAL_PAYMENTS,
  new BillingProgramAvailabilityListener() {
    @Override
    public void onBillingProgramAvailabilityResponse(
      int billingProgram, BillingResult billingResult) {
        if (billingResult.getResponseCode() != BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors,
            // handling external payments unavailable, etc.
            return;
        }

        // External payments are available. Can proceed with generating an external transaction token.
      }

    });

앱이 다른 응답 코드에 응답하는 방법에 관한 자세한 내용은 응답 처리 섹션을 참고하세요. Kotlin 확장 프로그램을 사용하는 경우 Kotlin 코루틴을 사용하면 별도의 리스너를 정의할 필요가 없습니다.

사용 가능한 제품 표시

Google Play 결제 시스템 통합과 동일한 방식으로 사용자에게 사용 가능한 제품을 표시할 수 있습니다. 사용자가 구매할 수 있는 제품을 확인하고 구매할 제품을 선택하면 외부 결제 흐름 시작 섹션 에 설명된 대로 외부 결제 흐름을 시작합니다.

외부 거래 토큰 준비

Google Play에 외부 거래를 보고하려면 Play 결제 라이브러리에서 생성된 외부 거래 토큰이 있어야 합니다. 사용자가 외부 결제 API를 통해 외부 웹사이트 또는 앱을 방문할 때마다 새 외부 거래 토큰을 생성해야 합니다. 이는 createBillingProgramReportingDetailsAsync API를 호출하여 실행할 수 있습니다. 토큰은 launchBillingFlow가 호출되기 직전에 생성되어야 합니다.

Kotlin

val params =
    BillingProgramReportingDetailsParams.newBuilder()
        .setBillingProgram(BillingProgram.EXTERNAL_PAYMENTS)
        .build()

billingClient.createBillingProgramReportingDetailsAsync(
  params,
  object : BillingProgramReportingDetailsListener {
    override fun onCreateBillingProgramReportingDetailsResponse(
      billingResult: BillingResult,
      billingProgramReportingDetails: BillingProgramReportingDetails?) {
        if (billingResult.responseCode != BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors.
            return
        }
        val externalTransactionToken =
            billingProgramReportingDetails?.externalTransactionToken
        // Persist the external transaction token locally. Pass it to
        // the external website using DeveloperBillingOptionParams when
        // launchBillingFlow is called.
    }
})

Java

BillingProgramReportingDetailsParams params =
    BillingProgramReportingDetailsParams.newBuilder()
        .setBillingProgram(BillingProgram.EXTERNAL_PAYMENTS)
        .build();

billingClient.createBillingProgramReportingDetailsAsync(
  params,
  new BillingProgramReportingDetailsListener() {
    @Override
    public void onCreateBillingProgramReportingDetailsResponse(
      BillingResult billingResult,
      @Nullable BillingProgramReportingDetails
        billingProgramReportingDetails) {
        if (billingResult.getResponseCode() != BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors.
            return;
        }

        String transactionToken =
          billingProgramReportingDetails.getExternalTransactionToken();

        // Persist the external transaction token locally. Pass it to
        // the external website using DeveloperBillingOptionParams when
        // launchBillingFlow is called.
      }
});

Kotlin 확장 프로그램을 사용하는 경우 Kotlin 코루틴을 사용하면 별도의 리스너를 정의할 필요가 없습니다.

외부 결제 흐름 시작

Google Play 결제 시스템 통합으로 구매 흐름을 시작하는 것과 비슷하지만 이 구매에 외부 결제 흐름을 사용 설정하려는 앱을 나타내는 추가 매개변수 DeveloperBillingOptionParams를 제공하여 launchBillingFlow()를 호출하여 외부 결제 흐름을 시작합니다.

DeveloperBillingOptionParams에는 다음이 포함되어야 합니다.

  • billingProgramEXTERNAL_PAYMENTS 결제 프로그램으로 설정됨
  • linkURI가 링크 대상으로 설정됨
  • launchMode가 Google Play에서 링크를 시작해야 하는 경우 LAUNCH_IN_EXTERNAL_BROWSER_OR_APP으로 설정되고 앱에서 링크를 시작하는 경우 CALLER_WILL_LAUNCH_LINK으로 설정됨

앱이 DeveloperBillingOptionParams가 제공된 launchBillingFlow()를 호출하면 Google Play 결제 시스템이 다음 사항을 확인합니다.

  • 시스템은 사용자의 Google Play 국가가 외부 결제를 지원하는 국가 (즉, 지원되는 국가)인지 확인합니다. 사용자의 Google Play 국가가 지원되는 경우 Google Play는 BillingClient의 구성에 따라 외부 결제가 사용 설정되었는지, DeveloperBillingOptionParams가 제공되었는지 확인합니다.
    • 외부 결제가 사용 설정된 경우 구매 흐름이 사용자 선택 UX를 표시합니다.
    • 외부 결제가 사용 설정되지 않은 경우 구매 흐름이 사용자의 선택권이 없는 표준 Google Play 결제 시스템 UX를 표시합니다.
  • 사용자의 Google Play 국가가 지원되는 국가가 아닌 경우 구매 흐름에는 사용자 선택권이 없는 표준 Google Play 결제 시스템 UX가 표시됩니다.

사용자의 Play 국가가 지원되는 국가임

사용자의 Play 국가가 지원되는 국가가 아님

외부 결제가 사용 설정됨 (BillingClient 설정launchBillingFlow)

사용자에게 사용자 선택 UX가 표시됨

사용자에게 표준 Google Play 결제 시스템 UX가 표시됨

외부 결제가 사용 설정되지 않음 (BillingClient 설정 중에 사용 설정되지 않았거나 launchBillingFlow에 DeveloperBillingOptionParams가 제공되지 않음)

사용자에게 표준 Google Play 결제 시스템 UX가 표시됨

사용자에게 표준 Google Play 결제 시스템 UX가 표시됨

다음 스니펫은 DeveloperBillingOptionParams를 구성하는 방법을 보여줍니다.

Kotlin

val developerBillingOptionParams =
    DeveloperBillingOptionParams.newBuilder()
        .setBillingProgram(BillingProgram.EXTERNAL_PAYMENTS)
        .setLinkUri(Uri.parse("https://www.example.com/external/purchase"))
        .setLaunchMode(
            DeveloperBillingOptionParams.LaunchMode.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP)
        .build()

Java

DeveloperBillingOptionParams developerBillingOptionParams =
    DeveloperBillingOptionParams.newBuilder()
        .setBillingProgram(BillingProgram.EXTERNAL_PAYMENTS)
        .setLinkUri(Uri.parse("https://www.example.com/external/purchase"))
        .setLaunchMode(
            DeveloperBillingOptionParams.LaunchMode.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP)
        .build();

사용자 선택사항 처리

구매 흐름의 나머지를 어떤 식으로 처리할지는 사용자가 Google Play 결제 시스템과 웹사이트에서 결제 중 어느 것을 선택했는지에 따라 달라집니다.

사용자가 웹사이트 또는 결제 앱에서 결제하도록 선택한 경우

사용자가 웹사이트에서 결제하도록 선택하면 Google Play는 DeveloperProvidedBillingListener를 호출하여 사용자가 웹사이트 또는 결제 앱에서 결제하도록 선택했음을 앱에 알립니다. 특히 onUserSelectedDeveloperBilling() 메서드가 호출됩니다.

앱이 launchModeLAUNCH_IN_EXTERNAL_BROWSER_OR_APP으로 설정하면 Google Play에서 링크를 시작합니다. launchModeCALLER_WILL_LAUNCH_LINK로 설정된 경우 앱에서 링크를 시작해야 합니다. 사용자를 결제 앱에 연결할 때는 사용자의 기기에 결제 앱이 이미 설치되어 있는지 확인해야 합니다.

이 토큰을 사용하여 이 선택으로 발생하는 거래를 백엔드 통합 가이드의 설명처럼 보고합니다.

사용자가 Google Play 결제 시스템을 선택한 경우

사용자가 Google Play 결제 시스템을 선택하면 Google Play를 통해 구매가 계속 진행됩니다.

  • Google Play 결제 시스템을 통해 새 인앱 구매를 처리하는 방법에 관한 자세한 내용은 라이브러리 통합 가이드의 구매 처리를 참고하세요.
  • 정기 결제 구매에 관한 추가 가이드는 정기 결제 관리 가이드의 신규 정기 결제를 참고하세요.

정기 결제 변경사항 처리

외부 결제를 사용하는 개발자의 경우 사용자의 선택에 따라 구매를 Google Play 결제 시스템을 통해 처리하거나 externalTransactionId로 보고해야 합니다. 개발자의 웹사이트를 통해 처리된 기존 정기 결제는 만료될 때까지 동일한 결제 시스템을 통해 변경할 수 있습니다.

이 섹션에서는 몇 가지 일반적인 정기 결제 변경 시나리오를 처리하는 방법을 설명합니다.

업그레이드 및 다운그레이드 흐름

업그레이드 및 다운그레이드 흐름을 포함한 정기 결제 요금제 변경사항은 정기 결제가 원래 Google Play 결제 시스템과 개발자의 웹사이트 중 어느 쪽을 통해 구매되었는지에 따라 다르게 처리해야 합니다.

기존 정기 결제에 종속되고 동일한 결제 수단을 공유하며 반복 청구를 정렬하는 부가기능은 업그레이드로 처리됩니다. 다른 부가기능의 경우 사용자는 어느 결제 시스템을 사용할지 선택할 수 있어야 합니다. launchBillingFlow()를 사용하여 새로운 구매 환경을 시작합니다. 외부 결제 흐름 시작에 설명된 대로 외부 결제 흐름 시작에 설명된 대로

개발자의 웹사이트 또는 결제 앱을 통해 구매한 정기 결제

사용자 선택 후 개발자의 웹사이트 또는 결제 앱을 통해 구매된 정기 결제인 경우, 업그레이드 또는 다운그레이드를 요청하는 사용자는 사용자 선택 환경을 다시 거치지 않고 개발자의 웹사이트 또는 결제 앱으로 진행되도록 해야 합니다.

이렇게 하려면 사용자가 업그레이드 또는 다운그레이드를 요청하는 경우 launchBillingFlow()를 호출합니다. SubscriptionUpdateParams 객체에서 다른 매개변수를 지정하는 대신 setOriginalExternalTransactionId()를 사용하여 원래 구매의 외부 거래 ID를 제공합니다.

이 호출에서 DeveloperBillingOptionParams도 제공되어야 합니다. 이렇게 해도 업그레이드와 다운그레이드에 대해 원래 구매와 관련된 사용자 선택이 그대로 유지되므로 사용자 선택 화면이 표시되지 않습니다. 여기에 설명된 대로 이 거래의 새 외부 거래 토큰을 생성해야 합니다.

개발자의 웹사이트 또는 결제 앱을 사용하여 업그레이드 또는 다운그레이드가 완료되면 새로운 정기 결제 구매에 대한 이전 호출을 통해 획득한 외부 거래 토큰을 사용하여 새 거래를 보고해야 합니다.

Google Play 결제 시스템을 통해 구매한 정기 결제

마찬가지로, 현재 정기 결제를 사용자 선택 후 Google Play's 결제 시스템을 통해 구매한 사용자에게는 표준 Google Play 결제 절차를 거치도록 표시해야 합니다. launchBillingFlow 호출에서 DeveloperBillingOptionParams를 설정해서는 안 됩니다.

정기 결제 취소 및 복원

사용자는 언제든지 정기 결제를 취소할 수 있어야 합니다. 사용자가 정기 결제를 취소하는 경우, 유료 기간이 종료될 때까지 사용 권한 해지가 지연될 수 있습니다. 예를 들어 사용자가 월 중간에 정기 결제를 취소했다면 액세스 권한이 삭제될 때까지 최대 2주 동안 서비스에 계속 액세스할 수 있습니다. 이 기간 동안 정기 결제는 기술적으로 여전히 활성 상태이므로 사용자가 서비스를 이용할 수 있습니다.

사용자가 이 활성 기간 중에 취소를 번복하는 경우도 종종 있습니다. 이 가이드에서는 이를 복원이라고 합니다. 다음 섹션에서는 외부 결제 API 통합에서 복원 시나리오를 처리하는 방법을 설명합니다.

개발자의 웹사이트를 통해 구매한 정기 결제

취소된 정기 결제의 외부 거래 ID가 있다면 launchBillingFlow()를 호출하여 정기 결제를 복원하지 않아도 되므로 이러한 유형의 활성화에서 launchBillingFlow를 사용해서는 안 됩니다. 사용자가 취소된 정기 결제의 활성 기간 중에 정기 결제를 복원하면 이 시점에는 거래가 발생하지 않으며, 현재 주기가 만료되고 다음번 갱신이 발생하는 시점에 갱신을 보고하면 됩니다. 여기에는 사용자가 복원의 일환으로 크레딧이나 특별 갱신 가격 혜택을 받는 경우가 포함됩니다 (예: 사용자가 정기 결제를 지속하도록 유도하는 프로모션).

Google Play 결제 시스템을 통해 구매한 정기 결제

일반적으로 사용자는 Google Play 결제 시스템에서 정기 결제를 복원할 수 있습니다. 원래 Google Play's 결제 시스템에서 구매된 후 취소된 정기 결제인 경우 사용자는 Google Play's 정기 결제 재신청 기능을 사용하여 정기 결제가 활성 상태인 동안 취소를 번복하도록 선택할 수 있습니다. 이 경우 백엔드로 SUBSCRIPTION_RESTARTED 실시간 개발자 알림이 수신되고, 새 구매 토큰은 발급되지 않습니다. 즉, 정기 결제를 계속 이어가는 데 원래 토큰이 사용됩니다. Google Play 결제 시스템에서 복원을 관리하는 방법을 알아보려면 정기 결제 관리 가이드의 복원을 참고하세요.

launchBillingFlow()를 호출하여 앱에서 Google Play 결제 시스템의 복원을 트리거할 수도 있습니다. 이렇게 하는 방법에 관한 설명은 정기 결제 만료 전 - 앱 내에서를 참고하세요. 원래 구매에서 사용자 선택 흐름을 거친 사용자의 경우 (정기 결제를 취소했으나 아직 활성 상태인 경우) 시스템이 자동으로 사용자의 선택사항을 감지하여 구매 항목 복원을 위한 사용자 인터페이스를 표시합니다. Google Play를 통해 정기 결제 재구매를 확인하라는 메시지가 표시되나, 사용자 선택 흐름을 다시 거칠 필요는 없습니다. 이 경우 사용자에게 새 구매 토큰이 발급됩니다. 백엔드로 SUBSCRIPTION_PURCHASED 실시간 개발자 알림이 수신되고, 업그레이드 또는 다운그레이드의 경우와 같이 새 구매 상태의 linkedPurchaseToken 값이 취소된 정기 결제의 기존 구매 토큰으로 설정됩니다.

정기 결제 재신청

취소로 인해, 또는 복원 없이 결제가 거부되어 정기 결제가 완전히 만료된 경우 (만료된 계정 보류) 사용자가 사용 권한을 다시 시작하려면 정기 결제를 재신청해야 합니다.

앱을 통해 표준 가입과 비슷하게 정기 결제 재신청을 설정할 수도 있습니다. 사용자는 어느 결제 시스템을 사용할지 선택할 수 있어야 합니다. launchBillingFlow() 이 경우 외부 결제 플로우 시작에 설명된 대로 호출할 수 있습니다.

응답 처리

오류가 발생하면 isBillingProgramAvailableAsync() , createBillingProgramReportingDetailsAsync(), launchBillingFlow() 메서드가 BillingResponseCode.OK 이외의 BillingResponseCode를 제공할 수 있습니다. 다음과 같이 이러한 응답 코드를 처리하는 것이 좋습니다.

  • BillingResponseCode.ERROR: 내부 오류입니다. 거래 또는 외부 웹사이트 열기를 진행하지 마세요. API를 다시 호출하여 재시도하세요.
  • BillingResponseCode.FEATURE_NOT_SUPPORTED: 현재 기기의 Play 스토어에서 외부 결제 API를 지원하지 않습니다. 거래 또는 외부 웹사이트 열기를 진행하지 마세요.
  • BillingResponseCode.DEVELOPER_ERROR: 요청에 오류가 있습니다. 계속하기 전에 디버그 메시지를 사용하여 오류를 식별하고 수정하세요.
  • BillingResponseCode.USER_CANCELED: 외부 웹사이트 또는 앱 열기를 진행하지 마세요. 다음에 사용자를 앱 외부로 안내하려고 할 때 launchBillingFlow()를 다시 호출하여 사용자에게 정보 대화상자를 표시합니다.
  • BillingResponseCode.BILLING_UNAVAILABLE: 이 거래는 외부 결제에 적합하지 않으므로 이 프로그램에서 개발자 결제를 사용할 수 없습니다. 이는 사용자가 이 프로그램을 이용할 수 있는 국가에 거주하지 않거나 계정이 프로그램에 등록되지 않았기 때문입니다. 후자인 경우 Play Console에서 등록 상태를 확인하세요.
  • BillingResponseCode.NETWORK_ERROR, BillingResponseCode.SERVICE_DISCONNECTED, BillingResponseCode.SERVICE_UNAVAILABLE: 적절한 재시도 정책으로 처리해야 하는 일시적인 오류입니다. SERVICE_DISCONNECTED의 경우 다시 시도하기 전에 Google Play와의 연결을 다시 설정합니다.

외부 결제 링크 테스트

라이선스 테스터를 사용하여 외부 결제 통합을 테스트해야 합니다. 라이선스 테스터 계정에서 시작된 거래에는 인보이스가 발행되지 않습니다. 라이선스 테스터 구성에 관한 자세한 내용은 애플리케이션 라이선스로 인앱 결제 테스트를 참고하세요.

다음 단계

인앱 통합을 완료했으면 백엔드 통합을 진행할 수 있습니다.