Wskazówki dotyczące integracji w aplikacji w przypadku wyboru systemu rozliczeniowego

Z tego przewodnika dowiesz się, jak zintegrować aplikację z interfejsami API Biblioteki płatności w Play , aby oferować użytkownikom wybór systemu rozliczeniowego.

Integracja z PBL

Wybór systemu rozliczeniowego możesz zintegrować z PBL na 4 sposoby. Różnią się one tym, kto renderuje ekran wyboru i gdzie nastąpi płatność. W tabeli poniżej znajdziesz opis sposobów integracji:

Który ekran wyboru systemu rozliczeniowego chcesz renderować?
Google Play Własny (zgodnie z wytycznymi dotyczącymi wrażeń użytkownika)
Gdzie nastąpi płatność? W aplikacji Sposób 1A

Google renderuje ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji.

Sposób 1B

Deweloper aplikacji renderuje ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji.

Zewnętrzny link internetowy Sposób 2A

Google renderuje ekran wyboru, a użytkownik jest przekierowywany poza aplikację do Twoich witryn w celu dokonania zakupu.

Sposób 2B

Deweloper aplikacji renderuje ekran wyboru, a użytkownik jest przekierowywany poza aplikację do Twoich witryn w celu dokonania zakupu.

Ilustracja poniżej przedstawia przepływ wyboru systemu rozliczeniowego w każdym z tych sposobów:

Proces wyboru systemu rozliczeniowego pokazujący sekwencję wywołań interfejsu API i interakcji użytkownika w 4 scenariuszach integracji.
Rysunek 1. Sposoby integracji wyboru systemu rozliczeniowego

Sposoby integracji z PBL

W zależności od sposobu integracji wykonaj czynności opisane w tej sekcji, aby wdrożyć wybór systemu rozliczeniowego w aplikacji.

Obsługa sposobu 1A

Google renderuje ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji. Aby włączyć wybór systemu rozliczeniowego w tym sposobie:

  1. Podczas tworzenia instancji BillingClient wywołaj metodę enableBillingProgram z parametrem EnableBillingProgramParams, a następnie rozpocznij połączenie. Przykład:

    Kotlin

    // Build the parameters to enable the Billing Choice program and assign the listener
    // to handle user selection of the developer-provided billing option.
    val enableBillingProgramParams = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
        .build()
    
    // Build the parameters to enable support for pending purchases.
    val pendingPurchasesParams = PendingPurchasesParams.newBuilder()
        .enableOneTimeProducts()
        .build()
    
    // Construct the BillingClient instance with the purchases updated listener,
    // pending purchases support, and the billing choice params.
    val billingClient = BillingClient.newBuilder(context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(pendingPurchasesParams)
        .enableBillingProgram(enableBillingProgramParams)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine<BillingResult> { continuation ->
        billingClient.startConnection(object : BillingClientStateListener {
            // Called when the connection setup process completes.
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                // Resume the coroutine and pass back the BillingResult to the caller.
                if (continuation.isActive) {
                    continuation.resume(billingResult)
                }
            }
    
            // Called if the connection to the Play Store service is dropped.
            // This prevents the await or suspension point from hanging indefinitely.
            override fun onBillingServiceDisconnected() {
                if (continuation.isActive) {
                    continuation.resume(
                        BillingResult.newBuilder()
                            .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED)
                            .setDebugMessage("Billing service disconnected during connection setup")
                            .build()
                    )
                }
            }
        })
    }

    Java

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases(
                    PendingPurchasesParams.newBuilder()
                            .enableOneTimeProducts()
                            .build()
            )
            .enableBillingProgram(params)
            .build();
    
    
  2. Sprawdź, czy wybór systemu rozliczeniowego renderowany przez Google jest dostępny dla użytkownika.

    Aby sprawdzić dostępność programu , wywołaj metodę isBillingProgramAvailableAsync, a następnie wywołaj metodę queryProductDetailsAsync, aby wyświetlić dostępne produkty. Przykład:

    Kotlin

    val (billingResult, billingProgramAvailabilityDetails) = billingClient.isBillingProgramAvailable(BillingProgram.BILLING_CHOICE)
    
    if (billingResult.responseCode == BillingResponseCode.OK) {
        val billingChoiceAvailabilityDetails = billingProgramAvailabilityDetails.billingChoiceAvailabilityDetails
        if (billingChoiceAvailabilityDetails != null &&
            billingChoiceAvailabilityDetails.choiceScreenType == ChoiceScreenType.GOOGLE_RENDERED
        ) {
            // Billing choice is available. Query products and proceed.
        } else {
            // Fallback to other available programs.
        }
    } else {
        // Fallback to other available programs.
    }

    Java

    
    // ...
    billingClient.isBillingProgramAvailableAsync(
        BillingProgram.BILLING_CHOICE,
        (billingResult, billingProgramAvailabilityDetails) -> {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                BillingChoiceAvailabilityDetails billingChoiceAvailabilityDetails =
                    billingProgramAvailabilityDetails.getBillingChoiceAvailabilityDetails();
    
                if (billingChoiceAvailabilityDetails != null &&
                    billingChoiceAvailabilityDetails.getChoiceScreenType() == ChoiceScreenType.GOOGLE_RENDERED) {
                    // Billing choice is available. Query products and proceed.
                } else {
                    // Fallback to other available programs.
                }
            } else {
                // Fallback to other available programs.
            }
        }
    );
    
    

    Uwaga: billingProgramAvailabilityDetails informuje, czy dostępny jest ekran wyboru systemu rozliczeniowego renderowany przez Google czy przez dewelopera.

  3. Wywołaj launchBillingFlow, aby uruchomić proces zakupu, gdy użytkownik kliknie Kup. Jeśli wybór systemu rozliczeniowego jest dostępny, przekaż DeveloperBillingOptionParams do BillingFlowParams. Przykład:

    Kotlin

    val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .build()
    
    val billingFlowParams = BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .enableDeveloperBillingOption(developerBillingOptionParams)
        .build()
    
    val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

    Java

    
    DeveloperBillingOptionParams developerBillingOptionParams =
        DeveloperBillingOptionParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .build();
    BillingFlowParams billingFlowParams =
        BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(productDetailsParamsList)
            .enableDeveloperBillingOption(developerBillingOptionParams)
            .build();
    
    BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
    
    

    Uwaga: w przypadku użytkowników nadzorowanych wyświetla się kontrola rodzicielska.

  4. Obsłuż wybór typu rozliczeń przez użytkownika w ten sposób:

    • Jeśli użytkownik wybierze Płatności w Play, wynik rozliczeń zostanie zwrócony do elementu PurchasesUpdatedListener zarejestrowanego w kroku 1.
    • Jeśli użytkownik wybierze Twoje rozliczenia alternatywne, wynik rozliczeń zostanie zwrócony do elementu DeveloperProvidedBillingListener zarejestrowanego w kroku 1. W tym przypadku zwrócony element DeveloperProvidedBillingDetails zawiera externalTransactionToken. Token będzie używany do raportowania transakcji.

Obsługa sposobu 1B

Deweloper renderuje ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji. Aby włączyć wybór systemu rozliczeniowego w tym sposobie:

  1. Podczas tworzenia instancji BillingClient wywołaj metodę enableBillingProgram bez elementu DeveloperProvidedBillingListener w parametrze EnableBillingProgramParams, a następnie rozpocznij połączenie. Przykład:

    Kotlin

    // Build the parameters to enable the Billing Choice program.
    val enableBillingProgramParams = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .build()
    
    // Build the parameters to enable support for pending purchases.
    val pendingPurchasesParams = PendingPurchasesParams.newBuilder()
        .enableOneTimeProducts()
        .build()
    
    // Construct the BillingClient instance with the purchases updated listener,
    // pending purchases support, and the billing choice params.
    val billingClient = BillingClient.newBuilder(context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(pendingPurchasesParams)
        .enableBillingProgram(enableBillingProgramParams)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine<BillingResult> { continuation ->
        billingClient.startConnection(object : BillingClientStateListener {
            // Called when the connection setup process completes.
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                // Resume the coroutine and pass back the BillingResult to the caller.
                if (continuation.isActive) {
                    continuation.resume(billingResult)
                }
            }
    
            // Called if the connection to the Play Store service is dropped.
            // This prevents the await or suspension point from hanging indefinitely.
            override fun onBillingServiceDisconnected() {
                if (continuation.isActive) {
                    continuation.resume(
                        BillingResult.newBuilder()
                            .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED)
                            .setDebugMessage("Billing service disconnected during connection setup")
                            .build()
                    )
                }
            }
        })
    }

    Java

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases()
            .enableBillingProgram(params)
            .build();
    
    
  2. Sprawdź, czy wybór systemu rozliczeniowego renderowany przez dewelopera jest dostępny dla użytkownika.

    Aby sprawdzić dostępność programu , wywołaj metodę isBillingProgramAvailableAsync, a następnie wywołaj metodę queryProductDetailsAsync, aby wyświetlić dostępne produkty. Przykład:

    Kotlin

    val (billingResult, billingProgramAvailabilityDetails) =
        billingClient.isBillingProgramAvailable(BillingProgram.BILLING_CHOICE)
    
    if (billingResult.responseCode == BillingResponseCode.OK) {
        val billingChoiceAvailabilityDetails =
            billingProgramAvailabilityDetails.billingChoiceAvailabilityDetails
    
        if (billingChoiceAvailabilityDetails != null &&
            billingChoiceAvailabilityDetails.choiceScreenType == ChoiceScreenType.DEVELOPER_RENDERED
        ) {
            // Billing choice is available. Query products and proceed.
            // You can inspect details such as:
            // - billingChoiceAvailabilityDetails.choiceScreenType
            // - billingChoiceAvailabilityDetails.isExternalLinkAvailable
        } else {
            // Fallback to other available programs.
        }
    } else {
        // Fallback to other available programs.
    }

    Java

    
    // ...
    billingClient.isBillingProgramAvailableAsync(
        BillingProgram.BILLING_CHOICE,
        (billingResult, billingProgramAvailabilityDetails) -> {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                BillingChoiceAvailabilityDetails billingChoiceAvailabilityDetails =
                    billingProgramAvailabilityDetails.getBillingChoiceAvailabilityDetails();
    
                if (billingChoiceAvailabilityDetails != null
                        && billingChoiceAvailabilityDetails.getChoiceScreenType() == ChoiceScreenType.DEVELOPER_RENDERED) {
                    // Billing choice is available. Query products and proceed.
                    // You can inspect details such as:
                    // - billingChoiceAvailabilityDetails.getChoiceScreenType()
                    // - billingChoiceAvailabilityDetails.isExternalLinkAvailable()
                } else {
                    // Fallback to other available programs.
                }
            } else {
                // Fallback to other available programs.
            }
        }
    );
    
    

    Uwaga: billingProgramAvailabilityDetails informuje, czy dostępny jest ekran wyboru systemu rozliczeniowego renderowany przez Google czy przez dewelopera.

  3. Aby uzyskać baner Płatności w Play i informacje o lojalności, wywołaj metodę getBillingChoiceInfoAsync. Przykład:

    Kotlin

    // 1. Create the params required for the request
    val params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE)
        .build()
    
    // 2. Call the suspend method on your billingClient instance
    val (billingResult, playBillingChoiceInfo) = billingClient.getBillingChoiceInfo(params)
    
    if (billingResult.responseCode == BillingResponseCode.OK && playBillingChoiceInfo != null) {
        // Access the URL of the image associated with the Play Billing Choice
        val imageUrl = playBillingChoiceInfo.playBillingChoiceImageUrl
    
        // Access the Play Loyalty string information, if available
        val loyaltyInfo = playBillingChoiceInfo.playBillingLoyaltyInfo
    
        // Populate your developer-rendered UI elements
        playBillingLoyaltyTextView.text = loyaltyInfo
        loadImage(imageUrl, playBillingImageView)
    } else {
        // Handle error scenarios
    }

    Java

    
    // 1. Create the params required for the request
    GetBillingChoiceInfoParams params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingClient.BillingProgram.BILLING_CHOICE)
        .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE)
        .build();
    // 2. Call the method asynchronously on your billingClient instance
    billingClient.getBillingChoiceInfoAsync(params, (billingResult, playBillingChoiceInfo) -> {
        if (billingResult.getResponseCode() == BillingResponseCode.OK && playBillingChoiceInfo != null) {
          // Access the URL of the image associated with the Play Billing Choice
            String imageUrl = playBillingChoiceInfo.getPlayBillingChoiceImageUrl();
            // Access the Play Loyalty string information, if available
            String loyaltyInfo = playBillingChoiceInfo.getPlayBillingLoyaltyInfo();
    
            // Populate your developer-rendered UI elements
            playBillingLoyaltyTextView.setText(loyaltyInfo);
              loadImage(imageUrl, playBillingImageView);
          } else {
              // Handle error scenarios
          }
    });
    
    
  4. Utwórz token transakcji zewnętrznej z parametrem DeveloperBillingType ustawionym na IN_APP. Przykład:

    Kotlin

    // Build the parameters specifying the billing program and that the billing type is IN_APP.
    val params = BillingProgramReportingDetailsParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setDeveloperBillingType(DeveloperBillingType.IN_APP)
        .build()
    
    // Call the suspending extension function to request the reporting details
    val (billingResult, billingProgramReportingDetails) =
        billingClient.createBillingProgramReportingDetails(params)
    
    if (billingResult.responseCode != BillingResponseCode.OK) {
        // Handle failures such as retrying due to network errors.
        return
    }
    
    // Extract the transaction token from the returned reporting details
    val transactionToken = billingProgramReportingDetails?.externalTransactionToken
    
    // Persist the external transaction token locally. Pass it to
    // DeveloperBillingOptionParams when launchBillingFlow is called.
    // It can also be used as part of your external website

    Java

    
    BillingProgramReportingDetailsParams params =
        BillingProgramReportingDetailsParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperBillingType(DeveloperBillingType.IN_APP)
            .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
                // DeveloperBillingOptionParams when launchBillingFlow is called.
                // It can also be used as part of your external website
            }
        }
    );
    
    
    
  5. Gdy użytkownik kliknie Kup, wywołaj metodę showBillingProgramInformationDialog, aby wyświetlić okno informacyjne. Przykład znajdziesz w sekcji Okno informacyjne dla użytkowników. W żądaniu należy ustawić BillingProgram i transactionToken z kroku 4.

    Uwaga: w przypadku użytkowników nadzorowanych wyświetla się kontrola rodzicielska.

  6. Jeśli wynik z poprzedniego kroku to OK, uruchom alternatywny ekran wyboru systemu rozliczeniowego.

  7. Obsłuż wybór typu rozliczeń przez użytkownika w ten sposób:

Obsługa sposobu 2A

Google renderuje ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany poza aplikacją. Aby włączyć wybór systemu rozliczeniowego w tym sposobie:

  1. Podczas tworzenia instancji BillingClient wywołaj metodę enableBillingProgram z parametrem EnableBillingProgramParams, a następnie rozpocznij połączenie. Przykład:

    Kotlin

    // Build the parameters to enable the Billing Choice program and assign the listener
    // to handle user selection of the developer-provided billing option.
    val enableBillingProgramParams = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
        .build()
    
    // Build the parameters to enable support for pending purchases.
    val pendingPurchasesParams = PendingPurchasesParams.newBuilder()
        .enableOneTimeProducts()
        .build()
    
    // Construct the BillingClient instance with the purchases updated listener,
    // pending purchases support, and the billing choice params.
    val billingClient = BillingClient.newBuilder(context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(pendingPurchasesParams)
        .enableBillingProgram(enableBillingProgramParams)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine<BillingResult> { continuation ->
        billingClient.startConnection(object : BillingClientStateListener {
            // Called when the connection setup process completes.
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                // Resume the coroutine and pass back the BillingResult to the caller.
                if (continuation.isActive) {
                    continuation.resume(billingResult)
                }
            }
    
            // Called if the connection to the Play Store service is dropped.
            // This prevents the await or suspension point from hanging indefinitely.
            override fun onBillingServiceDisconnected() {
                if (continuation.isActive) {
                    continuation.resume(
                        BillingResult.newBuilder()
                            .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED)
                            .setDebugMessage("Billing service disconnected during connection setup")
                            .build()
                    )
                }
            }
        })
    }

    Java

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases(
                    PendingPurchasesParams.newBuilder()
                            .enableOneTimeProducts()
                            .build()
            )
            .enableBillingProgram(params)
            .build();
    
    
  2. Sprawdź dostępność tych elementów:

    • wybór systemu rozliczeniowego renderowany przez Google;
    • zewnętrzny link internetowy.

    Aby sprawdzić dostępność programu , wywołaj metodę isBillingProgramAvailableAsync, a następnie wywołaj metodę queryProductDetailsAsync, aby wyświetlić dostępne produkty. Przykład:

    Kotlin

    Java

    
    // ...
    billingClient.isBillingProgramAvailableAsync(
        BillingProgram.BILLING_CHOICE,
        (billingResult, billingProgramAvailabilityDetails) -> {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                BillingChoiceAvailabilityDetails billingChoiceAvailabilityDetails =
                    billingProgramAvailabilityDetails.getBillingChoiceAvailabilityDetails();
    
                if (billingChoiceAvailabilityDetails != null
                        && billingChoiceAvailabilityDetails.getChoiceScreenType() == ChoiceScreenType.GOOGLE_RENDERED
                        && billingChoiceAvailabilityDetails.isExternalLinkAvailable()) {
                    // Billing choice is available and external transaction links are supported.
                    // Query products and proceed.
                } else {
                    // Fallback to other available programs.
                }
            } else {
                // Fallback to other available programs.
            }
        }
    );
    
    
    
  3. Gdy użytkownik wyrazi chęć zakupu, wywołaj metodę createBillingProgramReportingDetailsAsync, aby utworzyć token transakcji zewnętrznej. Przykład:

    Kotlin

    Java

    
    BillingProgramReportingDetailsParams params =
        BillingProgramReportingDetailsParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
            .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
                // DeveloperBillingOptionParams when launchBillingFlow is called.
                // It can also be used as part of your external website.
            }
        }
    );
    
    
  4. Wywołaj launchBillingFlow, aby uruchomić proces zakupu, gdy użytkownik kliknie Kup. Jeśli wybór systemu rozliczeniowego jest dostępny dla użytkownika, wykonaj te czynności:

    1. Przekaż DeveloperBillingOptionParams do BillingFlowParams.
    2. Przekaż token transakcji zewnętrznej z kroku 3 do parametru DeveloperBillingOptionParams.

    Przykład:

    Kotlin

    Java

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

    Uwaga: w przypadku użytkowników nadzorowanychwyświetla się kontrola rodzicielska.

  5. Obsłuż wybór typu rozliczeń przez użytkownika w ten sposób:

Obsługa sposobu 2B

Deweloper renderuje ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany poza aplikacją. Aby włączyć wybór systemu rozliczeniowego w tym sposobie:

  1. Podczas tworzenia instancji BillingClient wywołaj metodę enableBillingProgram bez elementu DeveloperProvidedBillingListener w parametrze EnableBillingProgramParams, a następnie rozpocznij połączenie. Przykład:

    Kotlin

    // Build the parameters to enable the Billing Choice program.
    val enableBillingProgramParams = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .build()
    
    // Build the parameters to enable support for pending purchases.
    val pendingPurchasesParams = PendingPurchasesParams.newBuilder()
        .enableOneTimeProducts()
        .build()
    
    // Construct the BillingClient instance with the purchases updated listener,
    // pending purchases support, and the billing choice params.
    val billingClient = BillingClient.newBuilder(context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(pendingPurchasesParams)
        .enableBillingProgram(enableBillingProgramParams)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine<BillingResult> { continuation ->
        billingClient.startConnection(object : BillingClientStateListener {
            // Called when the connection setup process completes.
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                // Resume the coroutine and pass back the BillingResult to the caller.
                if (continuation.isActive) {
                    continuation.resume(billingResult)
                }
            }
    
            // Called if the connection to the Play Store service is dropped.
            // This prevents the await or suspension point from hanging indefinitely.
            override fun onBillingServiceDisconnected() {
                if (continuation.isActive) {
                    continuation.resume(
                        BillingResult.newBuilder()
                            .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED)
                            .setDebugMessage("Billing service disconnected during connection setup")
                            .build()
                    )
                }
            }
        })
    }

    Java

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases()
            .enableBillingProgram(params)
            .build();
    
    
  2. Sprawdź dostępność tych elementów:

    • wybór systemu rozliczeniowego renderowany przez Google;
    • zewnętrzny link internetowy.

    Aby sprawdzić dostępność programu , wywołaj metodę isBillingProgramAvailableAsync, a następnie wywołaj metodę queryProductDetailsAsync, aby wyświetlić dostępne produkty. Przykład:

    Kotlin

    Java

    
    // ...
    
    billingClient.isBillingProgramAvailableAsync(
        BillingProgram.BILLING_CHOICE,
        (billingResult, billingProgramAvailabilityDetails) -> {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                BillingChoiceAvailabilityDetails billingChoiceAvailabilityDetails =
                    billingProgramAvailabilityDetails.getBillingChoiceAvailabilityDetails();
                if (billingChoiceAvailabilityDetails != null &&
                    billingChoiceAvailabilityDetails.getChoiceScreenType() == ChoiceScreenType.DEVELOPER_RENDERED &&
                    billingChoiceAvailabilityDetails.isExternalLinkAvailable()) {
                    // Billing choice is available and external transaction links are supported. Query products and proceed.
                } else {
                    // Fallback to other available programs.
                }
            } else {
                // Fallback to other available programs.
            }
        }
    );
    
    
  3. Aby uzyskać baner Płatności w Play i informacje o lojalności, wywołaj metodę getBillingChoiceInfoAsync.

    Kotlin

    // 1. Create the params required for the request
    val params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE)
        .build()
    
    // 2. Call the suspend method on your billingClient instance
    val (billingResult, playBillingChoiceInfo) = billingClient.getBillingChoiceInfo(params)
    
    if (billingResult.responseCode == BillingResponseCode.OK && playBillingChoiceInfo != null) {
        // Access the URL of the image associated with the Play Billing Choice
        val imageUrl = playBillingChoiceInfo.playBillingChoiceImageUrl
    
        // Access the Play Loyalty string information, if available
        val loyaltyInfo = playBillingChoiceInfo.playBillingLoyaltyInfo
    
        // Populate your developer-rendered UI elements
        playBillingLoyaltyTextView.text = loyaltyInfo
        loadImage(imageUrl, playBillingImageView)
    } else {
        // Handle error scenarios
    }

    Java

    
    // 1. Create the params required for the request
    GetBillingChoiceInfoParams params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingClient.BillingProgram.BILLING_CHOICE)
        .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE)
        .build();
    // 2. Call the method asynchronously on your billingClient instance
    billingClient.getBillingChoiceInfoAsync(params, (billingResult, playBillingChoiceInfo) -> {
        if (billingResult.getResponseCode() == BillingResponseCode.OK && playBillingChoiceInfo != null) {
          // Access the URL of the image associated with the Play Billing Choice
            String imageUrl = playBillingChoiceInfo.getPlayBillingChoiceImageUrl();
            // Access the Play Loyalty string information, if available
            String loyaltyInfo = playBillingChoiceInfo.getPlayBillingLoyaltyInfo();
    
            // Populate your developer-rendered UI elements
            playBillingLoyaltyTextView.setText(loyaltyInfo);
              loadImage(imageUrl, playBillingImageView);
          } else {
              // Handle error scenarios
          }
    });
    
    
  4. Gdy użytkownik wyrazi chęć zakupu, wywołaj metodę createBillingProgramReportingDetailsAsync, aby utworzyć token transakcji zewnętrznej. Przykład:

    Kotlin

    Java

    
    BillingProgramReportingDetailsParams params =
        BillingProgramReportingDetailsParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
            .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
                // DeveloperBillingOptionParams when launchBillingFlow is called.
                // It can also be used as part of your external website.
            }
        }
    );
    
    
  5. Gdy użytkownik kliknie Kup, uruchom alternatywny ekran wyboru.

  6. Obsłuż wybór typu rozliczeń przez użytkownika w ten sposób:

    • Jeśli użytkownik wybierze Płatności w Play, wywołaj metodę launchBillingFlow postępując zgodnie ze standardowymi wskazówkami dotyczącymi Płatności w Play. Wynik rozliczeń zostanie zwrócony do elementu PurchasesUpdatedListener zarejestrowanego w kroku 1.

      W przypadku użytkowników nadzorowanych wyświetla się kontrola rodzicielska.

    • Jeśli użytkownik wybierze Twoje rozliczenia alternatywne, wywołaj metodę launchExternalLink. Przykład:

      Kotlin

      Java

      
      // An activity reference from which the purchase flow will be launched.
      Activity activity = ...;
      
      LaunchExternalLinkParams params = LaunchExternalLinkParams.newBuilder()
          .setBillingProgram(BillingProgram.BILLING_CHOICE)
          // You can pass along the external transaction token from
          // BillingProgramReportingDetails as a URL parameter in the URI
          .setLinkUri(yourLinkUri)
          .setLinkType(LaunchExternalLinkParams.LinkType.LINK_TO_DIGITAL_CONTENT_OFFER)
          .setLaunchMode(
              LaunchExternalLinkParams.LaunchMode.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP)
          .setExternalTransactionToken(transactionToken)
          .build();
      
      LaunchExternalLinkResponseListener listener =
          new LaunchExternalLinkResponseListener() {
            @Override
            public void onLaunchExternalLinkResponse(BillingResult billingResult) {
              if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // Proceed with the rest of the purchase flow. If the user
                // purchases an item, be sure to report the transaction to Google
                // Play.
              } else {
                // Handle failures such as retrying due to network errors.
              }
            }
          };
      
      billingClient.launchExternalLink(activity, params, listener);
      
      
    • Przekaż token transakcji zewnętrznej z kroku 4 do LaunchExternalLinkParams. Jeśli zwróci on wartość OK, kontynuuj transakcję i zgłoś ją do Google Play.

      W przypadku użytkowników nadzorowanych wyświetla się kontrola rodzicielska.

Wybór systemu rozliczeniowego podczas zastępowania subskrypcji

W przypadku zastępowania subskrypcji nie należy wyświetlać ekranu wyboru użytkownika, ponieważ wybór użytkownika dotyczący pierwotnego zakupu jest zachowywany w przypadku przejścia na wyższą lub niższą wersję.

Jeśli pierwotny zakup został zrealizowany za pomocą Płatności w Google Play, wywołaj metodę launchBillingFlow ze standardowymi informacjami o zastępowaniu subskrypcji w Płatnościach w Google Play.

Jeśli jednak pierwotny zakup został zrealizowany za pomocą alternatywnego systemu rozliczeniowego, obsługa zastępowania subskrypcji różni się w zależności od sposobu.

Zastępowanie subskrypcji w sposobie 1A

Użytkownicy, którzy chcą przejść na wyższą lub niższą wersję, powinni korzystać z alternatywnego systemu rozliczeniowego dewelopera bez konieczności ponownego wybierania systemu rozliczeniowego.

Aby to zrobić, gdy użytkownik poprosi o przejście na wyższą lub niższą wersję, wywołaj metodę launchBillingFlow. W parametrach użyj metody setOriginalExternalTransactionId w obiekcie SubscriptionUpdateParams, aby podać identyfikator transakcji zewnętrznej dla pierwotnego zakupu. Nie spowoduje to wyświetlenia ekranu wyboru użytkownika, ponieważ wybór użytkownika dotyczący pierwotnego zakupu jest zachowywany w przypadku przejścia na wyższą lub niższą wersję. W tym przypadku wywołanie metody launchBillingFlow generuje nowy token transakcji zewnętrznej dla transakcji, którą możesz pobrać z wywołania zwrotnego.

Kotlin

// The external transaction ID from the current
// alternative billing subscription.
val externalTransactionId = "external_transaction_id"

val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder()
    .setBillingProgram(BillingProgram.BILLING_CHOICE)
    .build()

val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(
        listOf(
            BillingFlowParams.ProductDetailsParams.newBuilder()
                // Fetched using queryProductDetailsAsync.
                .setProductDetails(productDetailsNewPlan)
                // offerIdToken can be found in
                // ProductDetails=>SubscriptionOfferDetails.
                .setOfferToken(offerTokenNewPlan)
                .build()
        )
    )
    .setSubscriptionUpdateParams(
        SubscriptionUpdateParams.newBuilder()
            .setOriginalExternalTransactionId(externalTransactionId)
            .build()
    )
    .enableDeveloperBillingOption(developerBillingOptionParams)
    .build()

val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

// When the user selects the alternative billing flow,
// the DeveloperProvidedBillingListener is triggered.

Java


// The external transaction ID from the current
// alternative billing subscription.
String externalTransactionId = //... ;

DeveloperBillingOptionParams developerBillingOptionParams =
    DeveloperBillingOptionParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .build();

List<ProductDetailsParams> productDetailsParamsList = new ArrayList<>();
productDetailsParamsList.add(
    ProductDetailsParams.newBuilder()
        // Fetched using queryProductDetailsAsync.
        .setProductDetails(productDetailsNewPlan)
        // offerIdToken can be found in
        // ProductDetails=>SubscriptionOfferDetails
        .setOfferToken(offerTokenNewPlan)
        .build());

BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .setSubscriptionUpdateParams(
            SubscriptionUpdateParams.newBuilder()
                .setOriginalExternalTransactionId(externalTransactionId)
                .build())
        .enableDeveloperBillingOption(developerBillingOptionParams)
        .build();

BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

// When the user selects the alternative billing flow,
// the DeveloperProvidedBillingListener is triggered.


Po zakończeniu przejścia na wyższą lub niższą wersję musisz zgłosić nową transakcję za pomocą tokena transakcji zewnętrznej uzyskanego w poprzednim wywołaniu w przypadku zakupu nowej subskrypcji.

Zastępowanie subskrypcji w sposobie 1B

W tym sposobie należy wygenerować nowy token transakcji zewnętrznej. Jedyna różnica w porównaniu ze zwykłym zakupem polega na tym, że w tym sposobie zachowywany jest wybór użytkownika i nie musisz wyświetlać ekranu wyboru w przypadku przejścia na wyższą lub niższą wersję. Musisz jednak wyświetlić jednorazowe okno informacyjne i potwierdzenie rodzicielskie.

Przykładowy kod integracji znajdziesz w kroku 4 w sekcji Sposób 1B: deweloper renderuje ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji.

Po zakończeniu przejścia na wyższą lub niższą wersję musisz zgłosić nową transakcję za pomocą tokena transakcji zewnętrznej uzyskanego w poprzednim wywołaniu w przypadku zakupu nowej subskrypcji.

Zastępowanie subskrypcji w sposobie 2A

W przypadku subskrypcji, które zostały pierwotnie kupione w witrynie dewelopera lub w aplikacji do płatności po wybraniu przez użytkownika systemu rozliczeniowego, użytkownicy, którzy chcą przejść na wyższą lub niższą wersję, powinni korzystać z witryny dewelopera lub aplikacji do płatności bez konieczności ponownego wybierania systemu rozliczeniowego.

Aby to zrobić, gdy użytkownik poprosi o przejście na wyższą lub niższą wersję, wywołaj metodę launchBillingFlow. Zamiast określać inne parametry w obiekcie SubscriptionUpdateParams, użyj metody setOriginalExternalTransactionId, podając identyfikator transakcji zewnętrznej dla pierwotnego zakupu. W tym wywołaniu należy też podać parametr DeveloperBillingOptionParams. Nie spowoduje to wyświetlenia ekranu wyboru użytkownika, ponieważ wybór użytkownika dotyczący pierwotnego zakupu jest zachowywany w przypadku przejścia na wyższą lub niższą wersję. Przykład:

Kotlin

val externalTransactionId = "external_transaction_id"

// 1. Construct DeveloperBillingOptionParams indicating the billing program
val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder()
    .setBillingProgram(BillingProgram.BILLING_CHOICE)
    .build()

// 2. Build BillingFlowParams combining DeveloperBillingOptionParams and SubscriptionUpdateParams
val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(
        listOf(
            BillingFlowParams.ProductDetailsParams.newBuilder()
                // Fetched using queryProductDetailsAsync.
                .setProductDetails(productDetailsNewPlan)
                // offerIdToken can be found in ProductDetails=>SubscriptionOfferDetails.
                .setOfferToken(offerTokenNewPlan)
                .build()
        )
    )
    .setSubscriptionUpdateParams(
        SubscriptionUpdateParams.newBuilder()
            .setOriginalExternalTransactionId(externalTransactionId)
            .build()
    )
    .enableDeveloperBillingOption(developerBillingOptionParams)
    .build()

Java


String externalTransactionId = //... ;

// 1. Construct DeveloperBillingOptionParams indicating the billing program
DeveloperBillingOptionParams developerBillingOptionParams =
    DeveloperBillingOptionParams.newBuilder()
        .setBillingProgram(BillingClient.BillingProgram.BILLING_CHOICE)
        .build();

// 2. Add ProductDetailsParams
List productDetailsParamsList = new ArrayList<>();
productDetailsParamsList.add(
    ProductDetailsParams.newBuilder()
        // Fetched using queryProductDetailsAsync.
        .setProductDetails(productDetailsNewPlan)
        // offerIdToken can be found in ProductDetails=>SubscriptionOfferDetails
        .setOfferToken(offerTokenNewPlan)
        .build());

// 3. Build BillingFlowParams combining DeveloperBillingOptionParams and SubscriptionUpdateParams
BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .setSubscriptionUpdateParams(
            SubscriptionUpdateParams.newBuilder()
                .setOriginalExternalTransactionId(externalTransactionId)
                .build())
        .enableDeveloperBillingOption(developerBillingOptionParams)
        .build();


Musisz też wygenerować nowy token transakcji zewnętrznej. Przykład:

Kotlin

val params =
    BillingProgramReportingDetailsParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
        .build()

val (billingResult, billingProgramReportingDetails) =
    billingClient.createBillingProgramReportingDetails(params)

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.BILLING_CHOICE)
        .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
        .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.
      }
    });

Po wygenerowaniu nowego tokena musisz wywołać launchBillingFlow metodę, aby uruchomić proces zakupu.

Po zakończeniu przejścia na wyższą lub niższą wersję musisz zgłosić nową transakcję za pomocą tokena transakcji zewnętrznej uzyskanego w poprzednim wywołaniu w przypadku zakupu nowej subskrypcji.

Zastępowanie subskrypcji w sposobie 2B

Czynności związane z obsługą zastępowania subskrypcji w tym sposobie są podobne do czynności opisanych w sekcji Zastępowanie subskrypcji w sposobie 2A. Jedyna różnica polega na tym, że po wygenerowaniu tokena transakcji zamiast wywoływać metodę launchBillingFlow musisz wywołać metodę launchExternalLink, aby wyświetlić okno z informacją o opuszczeniu aplikacji. W tym sposobie zachowywany jest wybór użytkownika i nie musisz wyświetlać ekranu wyboru w przypadku przejścia na wyższą lub niższą wersję.

Przykładowy kod integracji znajdziesz w kroku 6 w sekcji Sposób 2B: deweloper renderuje ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji.

Po zakończeniu przejścia na wyższą lub niższą wersję musisz zgłosić nową transakcję za pomocą tokena transakcji zewnętrznej uzyskanego w poprzednim wywołaniu w przypadku zakupu nowej subskrypcji.