일회성 제품의 선주문 혜택 추가

1. 소개

이 Codelab에서는 일회성 제품 (OTP)을 만들고 제품의 선주문 혜택을 추가하는 데 중점을 둡니다.

참고: 이 Codelab을 시작하기 전에 일회성 제품 EAP 신청 양식을 작성하여 선주문 기능에 대한 액세스 권한을 요청해야 합니다.

시청자층

이 Codelab은 일회성 제품에 익숙하고 일회성 제품에 선주문 혜택을 추가하는 방법을 이해하려는 Android 앱 개발자를 대상으로 합니다.

자격 요건

일회성 제품을 처음 사용하는 경우 지역별 제품 가격 책정으로 새로운 시장 개척하기 Codelab을 완료하는 것이 좋습니다.

학습할 내용…

  • Google Play Console 을 사용하여 일회성 제품의 선주문 혜택을 만드는 방법
  • Play Billing Library API를 사용하여 일회성 제품 및 관련 선주문 혜택 세부정보를 쿼리하는 방법

필요한 항목…

2. 샘플 앱 빌드

이 Codelab에서는 샘플 Android 앱을 사용하여 일회성 제품을 관리하는 방법을 알려줍니다. 샘플 앱은 다음과 같은 측면을 보여주는 완전한 소스 코드가 있는 완전한 기능을 갖춘 Android 앱으로 설계되었습니다.

  • 앱을 PBL과 통합
  • 일회성 제품 및 관련 선주문 혜택 가져오기
  • 지역별 가격 책정을 위한 구매 흐름 실행

다음 데모 동영상은 샘플 앱이 배포되고 실행된 후 어떻게 표시되고 동작하는지 보여줍니다.

일회성 제품 및 Play Billing Library (PBL)에 이미 익숙한 경우 샘플 앱을 다운로드하여 사용해 볼 수 있습니다.

자격 요건

샘플 앱을 빌드하고 배포하기 전에 다음 단계를 따르세요.

빌드

이 빌드 단계의 목표는 샘플 앱의 서명된 Android App Bundle 파일을 생성하는 것입니다.

Android App Bundle을 생성하려면 다음 단계를 따르세요.

  1. GitHub에서 샘플 앱을 다운로드합니다.
  2. 샘플 앱을 빌드합니다. 빌드하기 전에 샘플 앱의 패키지 이름을 변경한 후 빌드합니다. Play Console에 다른 앱의 패키지가 있는 경우 샘플 앱에 제공하는 패키지 이름이 고유해야 합니다.

    **참고**: 샘플 앱을 빌드하면 로컬 테스트에 사용할 수 있는 APK 파일만 생성됩니다. 그러나 Play Console에서 제품이 구성되지 않았으므로 앱을 실행해도 제품과 가격이 가져오지 않습니다.
  3. 서명된 Android App Bundle을 생성합니다.
    1. 업로드 키 및 키 저장소 생성
    2. 업로드 키로 앱 서명
    3. Play 앱 서명 구성

다음 단계는 Android App Bundle을 Google Play Console에 업로드하는 것입니다.

3. Play Console에서 선주문으로 OTP 만들기

Google Play Console에서 일회성 제품 (OTP)을 만들려면 Play Console에 앱이 있어야 합니다. Play Console에서 앱을 만든 다음 이전에 만든 서명된 App Bundle을 업로드합니다.

앱 만들기

앱을 만들려면 다음 단계를 따르세요.

  1. 개발자 계정을 사용하여 Google Play Console에 로그인합니다.
  2. 앱 만들기 를 클릭합니다. 앱 만들기 페이지가 열립니다.
  3. 앱 이름, 기본 언어, 기타 앱 관련 세부정보를 입력합니다.
  4. 앱 만들기 를 클릭합니다. 그러면 Google Play Console에 앱이 만들어집니다.

이제 샘플 앱의 서명된 App Bundle을 업로드할 수 있습니다.

서명된 App Bundle 업로드

  1. 서명된 App Bundle을 Google Play Console 내부 테스트 트랙에 업로드합니다. 업로드한 후에만 Play Console에서 수익 창출 관련 기능을 구성할 수 있습니다.
    1. 테스트 및 출시 > 테스트 > 내부 출시 > 새 출시 버전 만들기 를 클릭합니다.
    2. 출시 버전 이름을 입력하고 서명된 APK 파일을 업로드합니다.
    3. **다음** 을 클릭한 다음 **저장 및 게시** 를 클릭합니다.

이제 일회성 제품을 만들 수 있습니다.

일회성 제품 만들기

이제 사용자가 구매할 일회성 제품을 만듭니다.

  1. Google Play Console에서 샘플 앱을 열고 Play로 수익 창출 > 제품 > 일회성 제품으로 이동합니다.
  2. 일회성 제품 만들기 를 클릭합니다.
  3. 다음 제품 세부정보를 입력합니다.
    • 제품 ID: 고유 ID를 입력합니다. 예: upcoming_movie_1
    • (선택사항) 태그: 관련 태그를 추가합니다.
    • 이름: 제품 이름을 입력합니다. 예: Product Movie
    • 설명: 제품 설명을 입력합니다. 예: Product Description
    • (선택사항) 아이콘 이미지 추가: 제품을 나타내는 아이콘을 업로드합니다.
    참고: 이 Codelab의 목적을 위해 세금, 규정 준수, 프로그램 섹션의 구성은 건너뛰어도 됩니다.
  4. 다음 을 클릭합니다.
  5. 구매 옵션을 추가하고 지역별 사용 가능 여부를 구성합니다. 일회성 제품에는 사용 권한이 부여되는 방식, 가격, 지역별 사용 가능 여부를 정의하는 구매 옵션이 하나 이상 필요합니다. 이 Codelab에서는 제품의 표준 구매 옵션을 추가합니다.구매 옵션 섹션에서 다음 세부정보를 입력합니다.
    • 구매 옵션 ID: 고유 ID를 입력합니다. 예: buy-movie
    • 구매 유형: 구매 를 선택합니다.
    • (선택사항) 태그: 이 구매 옵션에만 적용되는 태그를 추가합니다.
    • (선택사항) 고급 옵션 을 클릭하여 고급 옵션을 구성합니다. 이 Codelab의 목적을 위해 고급 옵션 구성은 건너뛰어도 됩니다.
  6. 다음으로 구매 옵션의 지역별 사용 가능 여부와 가격을 구성해야 합니다. 지역별 사용 가능 여부에서 앱이 아직 게시되지 않은 지역을 포함하여 제품을 사용할 수 있는 지역을 지정합니다. 기본적으로 구매 옵션은 모든 지역에서 사용할 수 있습니다.사용 가능 여부 및 가격 섹션에서 사용 가능 여부 및 액세스 수정 을 클릭합니다.
    1. 사용 불가로 설정 을 선택합니다.
    모든 지역이 자동으로 선택되고 사용 가능 으로 설정됩니다.
    1. United States 국가만 선택 해제한 다음 사용 불가로 설정 을 클릭합니다. 이제 일회성 제품은 United States에서만 사용할 수 있습니다.
    2. 모든 지역 드롭다운에서 사용 가능한 국가 및 지역 을 선택합니다. United States만 표시됩니다.
    3. 가격 아이콘을 클릭합니다. 그러면 가격을 설정하는 대화상자가 표시됩니다.
    4. 10 USD를 입력한 다음 저장 을 클릭합니다.
  7. 초안으로 저장 을 클릭합니다.

참고: 아직 구매 옵션을 활성화하지 마세요. 선주문 혜택을 구성한 후 활성화합니다. 지역별 사용 가능 여부가 설정된 활성 구매 옵션에는 선주문 혜택을 추가할 수 없기 때문입니다.

선주문 혜택 추가하기

이제 이전에 만든 구매 옵션의 선주문 혜택을 추가합니다. 선주문 혜택을 사용하면 사용자가 공식 출시 전에 상품을 구매할 수 있습니다. 선주문 혜택은 구매 구매 옵션에서만 지원되며 지역의 신규 제품에 대해서만 구성할 수 있습니다.

선주문 혜택을 추가하는 데는 다음 두 단계가 포함됩니다.

  1. 선주문 혜택을 위한 구매 구매 옵션을 준비합니다.
  2. 구매 옵션의 선주문 혜택을 추가합니다.

선주문 혜택을 위한 구매 옵션 준비

  1. Google Play Console에서 샘플 앱을 열고 Play로 수익 창출 > 제품 > 일회성 제품으로 이동합니다.
  2. 일회성 제품 페이지에서 제품 (upcoming_movie_1)의 오른쪽 화살표를 클릭합니다. 일회성 제품 수정 페이지가 열립니다.
  3. 이전에 만든 buy-movie 구매 옵션의 오른쪽 화살표를 클릭합니다. 그러면 구매 옵션 수정 페이지가 열립니다.
  4. 사용 가능 여부 및 액세스 수정 을 클릭한 후 사용 가능으로 설정하고 사용자가 선주문할 수 있도록 허용 을 선택합니다.
  5. 모든 지역 드롭다운에서 사용 가능한 국가 및 지역 을 선택합니다. 이전에 구성한 United States만 표시됩니다.
  6. 국가를 선택한 다음 선주문만 가능하도록 설정 을 클릭합니다.
  7. 저장 을 클릭합니다.

구매 옵션에 선주문 혜택을 아직 추가하지 않았습니다. 다음 단계는 선주문 혜택을 추가하는 것입니다.

선주문 혜택 추가하기

  1. Google Play Console에서 샘플 앱을 열고 Play로 수익 창출 > 제품 > 일회성 제품으로 이동합니다.
  2. 일회성 제품 페이지에서 제품 (upcoming_movie_1)의 혜택 추가 > 선주문 을 클릭합니다. 선주문 추가 페이지가 열립니다.
  3. 선주문 세부정보를 입력합니다.
    • 선주문 ID: preorder-offer-1을 입력합니다.
    • (선택사항) 할인 추가: 없음, 비율 또는 정액 할인을 선택할 수 있습니다. 이 Codelab의 목적을 위해 없음 을 선택합니다.
    • (선택사항) 태그: 관련 태그를 추가합니다.
    • 시작일 및 시간: 최소 3일 후의 날짜를 설정합니다.
    • 종료일 및 시간: 시작일로부터 최소 24시간 후의 날짜를 설정합니다.
    • 선주문 후 사용 가능 여부: 선주문 기간이 지난 후 제품을 즉시 사용할 수 있게 할지 아니면 특정 이후 날짜/시간에 사용할 수 있게 할지 선택합니다.
    • (선택사항) 더 낮은 가격 보장: 사용자가 선주문 가격과 출시 가격 중 더 낮은 가격으로 청구되도록 하려면 이 옵션을 선택합니다. 이는 초기 구매자에게 강력한 인센티브가 될 수 있습니다.
  4. 저장 을 클릭합니다.
  5. 일회성 제품 (upcoming_movie_1)의 일회성 제품 수정 페이지를 엽니다.
  6. 구매 옵션 (buy-movie)의 활성화 를 클릭합니다.
  7. 구매 옵션의 선주문 혜택 (preorder-offer-1)에서 활성화 를 클릭합니다. 이렇게 하면 선주문 혜택이 활성화되고 이전에 선주문 세부정보에서 구성한 날짜에 게시됩니다.

선주문 혜택 생성 동영상

다음 동영상은 이전에 설명한 선주문 혜택 생성 단계를 보여줍니다.

4. PBL과 통합

앱을 Play Billing Library (PBL)와 통합하려면 다음 단계를 따르세요.

  1. 샘플 앱에 Play Billing Library 종속 항목을 추가합니다.
    dependencies {
    val billing_version = "8.1.0"
    
    implementation("com.android.billingclient:billing-ktx:$billing_version")
    }
    
  2. BillingClient를 초기화합니다. BillingClient는 앱에 상주하며 Play Billing Library와 통신하는 클라이언트 SDK입니다. 다음 코드 스니펫은 결제 클라이언트를 초기화하는 방법을 보여줍니다.
    private BillingClient createBillingClient() {
    return BillingClient.newBuilder(activity)
        .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
        // For one-time products, add a listener to process and acknowledge the purchases. This will notify
        // Google the purchase was processed.
        // For client-only apps, use billingClient.acknowledgePurchase().
        // If you have a secure backend, you must acknowledge purchases on your server using the
        // server-side API.
        // See https://developer.android.com/google/play/billing/security#acknowledge
        // In this sample snippet purchases aren't processed. You must
        // implement your business logic to process and acknowledge the purchases.
        .setListener((billingResult, purchases) -> {})
        .enableAutoServiceReconnection()
        .build();
     }
    
  3. Google Play에 연결합니다.다음 코드 스니펫은 Google Play에 연결하는 방법을 보여줍니다.
    /**
    * Starts the billing connection with Google Play. This method should be called exactly once
    * before any other methods in this class.
    *
    * @param productList The list of products to query for after the connection is established.
    */
    public void startBillingConnection(List<Product> productList) {
        billingClient.startConnection(
            new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                Log.d(TAG, "Billing Client Connection Successful");
                queryProductDetails(productList);
                } else {
                Log.e(TAG, "Billing Client Connection Failed: " + billingResult.getDebugMessage());
                listener.onBillingSetupFailed(billingResult); // Propagate the error to the listener to show a message to the user.
                }
            }
    
            @Override
            public void onBillingServiceDisconnected() {
                Log.e(TAG, "Billing Client Connection Lost");
                listener.onBillingError("Billing Connection Lost");
            }
            });
    }
    
  4. 일회성 제품 세부정보를 가져옵니다.앱을 PBL과 통합한 후에는 일회성 제품 세부정보를 앱으로 가져와야 합니다. 다음 코드 스니펫은 앱에서 일회성 제품 세부정보를 가져오는 방법을 보여줍니다.
    private void queryProductDetails(List<Product> productList) {
        QueryProductDetailsParams queryProductDetailsParams =
            QueryProductDetailsParams.newBuilder().setProductList(productList).build();
    
        billingClient.queryProductDetailsAsync(
            queryProductDetailsParams,
            new ProductDetailsResponseListener() {
            @Override
            public void onProductDetailsResponse(
                BillingResult billingResult, QueryProductDetailsResult productDetailsResponse) {
                if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                List<ProductDetails> productDetailsList =
                    productDetailsResponse.getProductDetailsList();
                    listener.onProductDetailsResponse(productDetailsList);
                } else {
                Log.e(TAG, "QueryProductDetailsAsync Failed: " + billingResult.getDebugMessage());
                listener.onBillingError("Query Products Failed: " + billingResult.getResponseCode());
                }
            }
            });
    }
    
    ProductDetails에서 일회성 제품(upcoming_movie_1)(이 예에서는)을 가져오면 다음과 비슷한 응답이 표시됩니다.
    {
        "productId": "upcoming_movie_1",
        "type": "inapp",
        "title": "Purrfect Mayhem: The Final Playback (Movies All Day | Play Samples)",
        "name": "Purrfect Mayhem: The Final Playback",
        "description": "Yolo and Thorne must reach the original broadcasting site to initiate the \"Final Playback\" and save the timeline. Follow them through their race against the Clockinators.",
        "skuDetailsToken": "<---skuDetailsToken--->",
        "oneTimePurchaseOfferDetails": {},
        "oneTimePurchaseOfferDetailsList": [
            {
                "priceAmountMicros": 8500000,
                "priceCurrencyCode": "USD",
                "formattedPrice": "$8.50",
                "offerIdToken": "<---offerIdToken--->",
                "offerId": "preorder",
                "purchaseOptionId": "buy-option",
                "offerTags": [],
                "validTimeWindow": {
                    "startTimeMillis": 1756771200000,
                    "endTimeMillis": 1785542400000
                },
                "preorderDetails": {
                    "preorderReleaseTimeMillis": 1785542400000,
                    "preorderPresaleEndTimeMillis": 1785542400000
                }
            }
        ]
    }
    
    선주문 혜택 세부정보는 oneTimePurchaseOfferDetailsList에서 확인할 수 있습니다. 이 목록에는 Play Console에서 선주문 혜택이 구성된 구매 옵션 (buy-option)이 하나 있습니다. 각 구매 옵션은 offerIdToken 으로 고유하게 식별할 수 있습니다.
  5. 선주문 혜택 세부정보와 함께 혜택 토큰을 가져옵니다. 6단계에서 결제 흐름을 시작하려면 혜택 토큰이 필요합니다.
    @Override
    public void onProductDetailsResponse(List<ProductDetails> productDetailsList) {
    
    if (productDetailsList != null && !productDetailsList.isEmpty()) {
    
    // Process productDetailsList returned by QueryProductDetailsResult
    for (ProductDetails productDetails : productDetailsResult.getProductDetailsList()) {
      for (OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails :
          productDetails.getOneTimePurchaseOfferDetailsList()) {
        // Checks if the offer is a preorder offer.
        if (oneTimePurchaseOfferDetails.getPreorderDetails() != null) {
          // Process the returned PreorderDetails
          OneTimePurchaseOfferDetails.PreorderDetails preorderDetails =
              oneTimePurchaseOfferDetails.getPreorderDetails();
          // Get preorder release time in millis.
          long preorderReleaseTimeMillis = preorderDetails.getPreorderReleaseTimeMillis();
          // Get preorder presale end time in millis.
          long preorderPresaleEndTimeMillis = preorderDetails.getPreorderPresaleEndTimeMillis();
          // Get offer ID
            String offerId = oneTimePurchaseOfferDetails.getOfferId();
          // Get the associated purchase option ID
          if (oneTimePurchaseOfferDetails.getPurchaseOptionId() != null) {
            String purchaseOptionId = oneTimePurchaseOfferDetails.getPurchaseOptionId();
          }
        }
      }
      }
      } else {
            Log.e(TAG, "No product details found for " + productId);
        }
    }
    
  6. 결제 흐름을 시작합니다.
    /**
     * Launches the billing flow for the product with the given offer token.
    *
    * @param activity The activity instance from which the billing flow will be launched.
    * @param productDetails The product details of the product to purchase.
    * @param offerToken The offer token of the product to purchase.
    * @return The result of the billing flow.
    */
    public void launchPurchase(Activity activity, ProductDetails productDetails, String offerToken) {
        ImmutableList<BillingFlowParams.ProductDetailsParams> productDetailsParamsList =
            ImmutableList.of(
                BillingFlowParams.ProductDetailsParams.newBuilder()
                    .setProductDetails(productDetails)
                    .setOfferToken(offerToken)
                    .build());
        BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(productDetailsParamsList)
            .build();
        billingClient.launchBillingFlow(activity, billingFlowParams);
    }
    

5. 구매 옵션 테스트

실제 앱에서 일회성 제품을 제공하기 전에 라이선스 테스터와 Play Billing Lab을 사용하여 PBL 통합을 테스트할 수 있습니다.

Play Billing Lab을 사용하여 구매 옵션을 테스트하는 방법을 알아보려면 지역별 제품 가격 책정으로 새로운 시장 개척하기 Codelab을 참고하세요.

6. 다음 단계

참조 문서

7. 축하합니다.

축하합니다. Google Play Console을 성공적으로 탐색하여 일회성 제품의 선주문 혜택을 만들었습니다. 이제 일회성 구매를 위한 Google Play의 유연한 제품 카탈로그를 더 깊이 이해할 수 있습니다.

설문조사

이 Codelab에 대한 의견은 매우 소중합니다. 잠시 시간을 내어 설문조사를 작성해 주세요.