Z tego przewodnika dowiesz się, jak zintegrować aplikację z interfejsami API Biblioteki płatności w Google Play, aby oferować użytkownikom wybór systemu rozliczeniowego.
Integracja z PBL
Możesz zintegrować wybór systemu rozliczeniowego z PBL w 4 scenariuszach. Scenariusze różnią się w zależności od tego, kto renderuje ekran wyboru i gdzie nastąpi płatność. W tabeli poniżej przedstawiamy scenariusze integracji:
| Który ekran wyboru rozliczeń chcesz wyświetlić? | |||
| Obowiązujące w Google Play | własne (zgodnie z wytycznymi dotyczącymi UX); | ||
| Gdzie odbywa się płatność? | W aplikacji | Scenariusz 1A
Google wyświetla ekran wyboru, a rozliczenia alternatywne są obsługiwane w Twojej aplikacji. |
Scenariusz 1B
Deweloper aplikacji wyświetla ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji. |
| Zewnętrzny link internetowy | Scenariusz 2A
Google renderuje ekran wyboru, a użytkownik jest przekierowywany poza aplikację do Twoich witryn w celu dokonania zakupu. |
Scenariusz 2B
Deweloper aplikacji renderuje ekran wyboru, a użytkownik jest kierowany poza aplikację do własnych witryn w celu dokonania zakupu. |
|
Ilustracja poniżej przedstawia przepływ wyboru płatności w każdym z tych scenariuszy:

Scenariusze integracji PBL
W zależności od scenariusza integracji wykonaj czynności opisane w tej sekcji, aby wdrożyć w aplikacji wybór systemu rozliczeniowego.
Obsługa scenariusza 1A
Google wyświetla ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji. Aby włączyć wybór systemu rozliczeniowego w tym scenariuszu, wykonaj te czynności:
Podczas tworzenia instancji BillingClient wywołaj funkcję
enableBillingProgramz parametremEnableBillingProgramParams, 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 params = 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(params) .build() // Establish a connection to Google Play val billingResult = suspendCancellableCoroutine{ 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. 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() { continuation.resume( BillingResult.newBuilder() .setResponseCode(BillingClient.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();Sprawdź, czy użytkownik ma dostęp do wyboru płatności renderowanego przez Google.
Zadzwoń pod numer
isBillingProgramAvailableAsync, aby sprawdzić dostępność programu, a następnie pod numerqueryProductDetailsAsync, 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: symbol
billingProgramAvailabilityDetailsinformuje, czy dostępny jest ekran wyboru płatności renderowany przez Google lub przez dewelopera.Wywołaj funkcję
launchBillingFlow, aby uruchomić proces zakupu, gdy użytkownik kliknie Kup. Jeśli wybór systemu rozliczeniowego jest dostępny, przekażDeveloperBillingOptionParamsdoBillingFlowParams. 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: kontrola rodzicielska jest wyświetlana w przypadku nadzorowanych użytkowników.
Obsłuż wybór typu rozliczeń przez użytkownika w ten sposób:
- Jeśli użytkownik wybierze rozliczenia w Google Play, wynik rozliczeń zostanie zwrócony do
PurchasesUpdatedListenerzarejestrowanego w kroku 1. - Jeśli użytkownik wybierze Twoje rozliczenia alternatywne, wynik rozliczeń zostanie zwrócony do
DeveloperProvidedBillingListenerzarejestrowanego w kroku 1. Zwrócony elementDeveloperProvidedBillingDetailszawiera w tym przypadku wartośćexternalTransactionToken. Token będzie używany do raportowania transakcji.
- Jeśli użytkownik wybierze rozliczenia w Google Play, wynik rozliczeń zostanie zwrócony do
Scenariusz obsługi 1B
Deweloper wyświetla ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji. Aby włączyć wybór systemu rozliczeniowego w tym scenariuszu, wykonaj te czynności:
Wywołaj
enableBillingProgrambezDeveloperProvidedBillingListenerwEnableBillingProgramParamspodczas tworzenia instancjiBillingClient, a następnie rozpocznij połączenie. Przykład:Kotlin
// Build the parameters to enable the Billing Choice program. val params = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .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() .enableBillingProgram(params) .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. 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() { continuation.resume( BillingResult.newBuilder() .setResponseCode(BillingClient.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();Sprawdź, czy opcja rozliczeń wybrana przez dewelopera jest dostępna dla użytkownika.
Zadzwoń pod numer
isBillingProgramAvailableAsync, aby sprawdzić dostępność programu, a następnie pod numerqueryProductDetailsAsync, 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: symbol
billingProgramAvailabilityDetailsinformuje, czy dostępny jest ekran wyboru rozliczeń renderowany przez Google czy przez dewelopera.Aby uzyskać baner Płatności w Google Play i informacje o programie lojalnościowym, wywołaj metodę
getBillingChoiceInfoAsync. Przykład:Kotlin
// 1. Create the params required for the request val params = GetBillingChoiceInfoParams.newBuilder() .setBillingProgram(BillingClient.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 } });Utwórz zewnętrzny token transakcji 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 websiteJava
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 } } );Gdy użytkownik kliknie Kup, wywołaj funkcję
showBillingProgramInformationDialog, aby wyświetlić okno informacyjne. Przykład znajdziesz w artykule Okno informacyjne dla użytkowników. W kroku 4 w żądaniu należy ustawić parametry BillingProgram i transactionToken.Uwaga: kontrola rodzicielska jest wyświetlana w przypadku nadzorowanych użytkowników.
Jeśli wynik z poprzedniego kroku to
OK, wyświetl ekran wyboru alternatywnego systemu rozliczeniowego.Obsłuż wybór typu rozliczeń przez użytkownika w ten sposób:
- Jeśli użytkownik wybierze Płatności w Google Play, wywołaj
launchBillingFlowzgodnie ze standardowymi wytycznymi dotyczącymi Płatności w Google Play. Wynik płatności zostanie zwrócony na adresPurchasesUpdatedListenerzarejestrowany w kroku 1. - Jeśli użytkownik wybierze Twój alternatywny system rozliczeniowy, musisz samodzielnie obsłużyć transakcję i zgłosić ją do Google Play za pomocą tokena wygenerowanego w kroku 4.
- Jeśli użytkownik wybierze Płatności w Google Play, wywołaj
Obsługa scenariusza 2A
Google wyświetla ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany poza Twoją aplikacją. Aby włączyć wybór systemu rozliczeniowego w tym scenariuszu, wykonaj te czynności:
Podczas tworzenia instancji BillingClient wywołaj funkcję
enableBillingProgramz parametremEnableBillingProgramParams, 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 params = 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(params) .build() // Establish a connection to Google Play val billingResult = suspendCancellableCoroutine{ 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. 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() { continuation.resume( BillingResult.newBuilder() .setResponseCode(BillingClient.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();Sprawdź dostępność tych elementów:
- Wybór systemu rozliczeniowego wyświetlany przez Google
- Zewnętrzny link internetowy
Zadzwoń pod numer
isBillingProgramAvailableAsync, aby sprawdzić dostępność programu, a następnie pod numerqueryProductDetailsAsync, aby wyświetlić dostępne produkty. Przykład:Kotlin
// Check the availability of the billing choice program asynchronously using coroutines val (billingResult, billingProgramAvailabilityDetails) = billingClient.isBillingProgramAvailable(BillingProgram.BILLING_CHOICE) // Ensure the billing program query succeeded if (billingResult.responseCode == BillingResponseCode.OK) { // Retrieve the availability details specific to the billing choice program val billingChoiceAvailabilityDetails = billingProgramAvailabilityDetails.billingChoiceAvailabilityDetails // Check if billing choice is available, renders via Google Play, and external link is supported if (billingChoiceAvailabilityDetails != null && billingChoiceAvailabilityDetails.choiceScreenType == 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. }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. } } );Wywołaj
createBillingProgramReportingDetailsAsync, aby utworzyć zewnętrzny token transakcji, gdy użytkownik wykazuje zamiar dokonania zakupu. Przykład:Kotlin
// Build the parameters for creating reporting details val params = BillingProgramReportingDetailsParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK) .build() // Call the suspend function to create billing program reporting details val (billingResult, billingProgramReportingDetails) = billingClient.createBillingProgramReportingDetails(params) // Handle response failure cases if (billingResult.responseCode != BillingResponseCode.OK) { // Handle failures such as retrying due to network errors. return } // Retrieve the external transaction token 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 websiteJava
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. } } );Wywołaj funkcję
launchBillingFlow, aby uruchomić proces zakupu, gdy użytkownik kliknie Kup. Jeśli użytkownik ma możliwość wyboru systemu rozliczeniowego, wykonaj te czynności:- Przekaż DeveloperBillingOptionParams do
BillingFlowParams. - Przekaż token transakcji zewnętrznej z kroku 3 do
DeveloperBillingOptionParams.
Przykład:
Kotlin
// Build the developer billing option parameters with the external link URI, // the transaction token, and browser/app launch mode. val 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()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: kontrola rodzicielska jest wyświetlana w przypadku nadzorowanych użytkowników.
- Przekaż DeveloperBillingOptionParams do
Obsłuż wybór typu rozliczeń przez użytkownika w ten sposób:
- Jeśli użytkownik wybierze Płatności w Google Play, wywołaj
launchBillingFlowzgodnie ze standardowymi wytycznymi dotyczącymi Płatności w Google Play. Wynik płatności zostanie zwrócony na adresPurchasesUpdatedListenerzarejestrowany w kroku 1. - Jeśli użytkownik wybierze rozliczenia alternatywne, wynik rozliczeń zostanie zwrócony do
DeveloperProvidedBillingListenerzarejestrowanego w kroku- .
- Zwrócony obiekt
DeveloperProvidedBillingDetailszawiera parametrexternalTransactionTokenprzekazany do funkcjiDeveloperBillingOptionParamsw kroku 4, jeśli jest prawidłowym tokenem.
- Zwrócony obiekt
- Jeśli użytkownik wybierze Płatności w Google Play, wywołaj
Scenariusz obsługi 2B
Deweloper wyświetla ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany poza aplikacją. Aby włączyć wybór systemu rozliczeniowego w tym scenariuszu, wykonaj te czynności:
Wywołaj
enableBillingProgrambezDeveloperProvidedBillingListenerwEnableBillingProgramParamspodczas tworzenia instancji BillingClient, a następnie rozpocznij połączenie. Przykład:Kotlin
// Build the parameters to enable the Billing Choice program. val params = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .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() .enableBillingProgram(params) .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. 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() { continuation.resume( BillingResult.newBuilder() .setResponseCode(BillingClient.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();Sprawdź dostępność tych elementów:
- Wybór systemu rozliczeniowego wyświetlany przez Google
- Zewnętrzny link internetowy
Zadzwoń pod numer
isBillingProgramAvailableAsync, aby sprawdzić dostępność programu, a następnie pod numerqueryProductDetailsAsync, aby wyświetlić dostępne produkty. Przykład:Kotlin
// Check the availability of the billing choice program asynchronously using a coroutine val (billingResult, billingProgramAvailabilityDetails) = billingClient.isBillingProgramAvailable(BillingProgram.BILLING_CHOICE) // Ensure the response code is OK if (billingResult.responseCode == BillingResponseCode.OK) { // Retrieve the billing choice availability details val billingChoiceAvailabilityDetails = billingProgramAvailabilityDetails.billingChoiceAvailabilityDetails // Check if billing choice details are available, choice screen is developer-rendered, // and external transaction links are supported. if (billingChoiceAvailabilityDetails != null && billingChoiceAvailabilityDetails.choiceScreenType == 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. }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. } } );Aby uzyskać baner Płatności w Google Play i informacje o programie lojalnościowym, wywołaj metodę
getBillingChoiceInfoAsync.Kotlin
// 1. Create the params required for the request val params = GetBillingChoiceInfoParams.newBuilder() .setBillingProgram(BillingClient.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 } });Wywołaj
createBillingProgramReportingDetailsAsync, aby utworzyć zewnętrzny token transakcji, gdy użytkownik wykazuje zamiar dokonania zakupu. Przykład:Kotlin
// Build the parameters for creating reporting details val params = BillingProgramReportingDetailsParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK) .build() // Call the suspend function to create billing program reporting details val (billingResult, billingProgramReportingDetails) = billingClient.createBillingProgramReportingDetails(params) // Handle response failure cases if (billingResult.responseCode != BillingResponseCode.OK) { // Handle failures such as retrying due to network errors. return } // Retrieve the external transaction token 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 websiteJava
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. } } );Uruchom alternatywny ekran wyboru, gdy użytkownik kliknie Kup.
Obsłuż wybór typu rozliczeń przez użytkownika w ten sposób:
Jeśli użytkownik wybierze Płatności w Google Play, wywołaj
launchBillingFlowzgodnie ze standardowymi wytycznymi dotyczącymi Płatności w Google Play. Wynik płatności zostanie zwrócony na adresPurchasesUpdatedListenerzarejestrowany w kroku 1.Kontrola rodzicielska jest wyświetlana w przypadku nadzorowanych użytkowników.
Jeśli użytkownik wybierze Twój alternatywny system rozliczeniowy, wywołaj funkcję launchExternalLink. Przykład:
Kotlin
// An activity reference from which the purchase flow will be launched. val activity: Activity = ... val 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 ) .build() // Call launchExternalLink with a callback billingClient.launchExternalLink(activity, params) { billingResult -> if (billingResult.responseCode == 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. } }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 wartość OK, przeprowadź transakcję i zgłoś ją do Google Play.Kontrola rodzicielska jest wyświetlana w przypadku nadzorowanych użytkowników.
Wybór systemu rozliczeniowego podczas wymiany subskrypcji
W przypadku zastąpienia subskrypcji ekran wyboru użytkownika nie powinien być wyświetlany, ponieważ wybór użytkownika dotyczący pierwotnego zakupu jest zachowywany w przypadku uaktualnień i obniżeń wersji.
Jeśli pierwotny zakup został zrealizowany za pomocą Płatności w Google Play, zadzwoń pod numer launchBillingFlow i podaj standardowe informacje o zastępowaniu subskrypcji w Płatnościach w Google Play.
Jeśli jednak pierwotny zakup został przetworzony za pomocą alternatywnego systemu płatności, obsługa wymiany subskrypcji będzie się nieznacznie różnić w zależności od scenariusza.
Zastąpienie subskrypcji w scenariuszu 1A
Użytkownicy, którzy chcą przejść na wyższy lub niższy pakiet, powinni skorzystać z alternatywnego systemu rozliczeniowego dewelopera bez ponownego przechodzenia przez proces wyboru przez użytkownika.
Aby to zrobić, wywołaj funkcję launchBillingFlow, gdy użytkownik poprosi o przejście na wyższą lub niższą wersję. Użyj parametru setOriginalExternalTransactionId w obiekcie SubscriptionUpdateParams w parametrach, aby podać zewnętrzny identyfikator transakcji pierwotnego zakupu. Nie wyświetla ekranu wyboru użytkownika, ponieważ wybór użytkownika dotyczący pierwotnego zakupu jest zachowywany w przypadku uaktualnień i obniżeń wersji. Wywołanie metody launchBillingFlow w tym przypadku generuje nowy token transakcji zewnętrznej, który możesz pobrać z wywołania zwrotnego.
Kotlin
// The external transaction ID from the current
// alternative billing subscription.
val externalTransactionId = //... ;
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(
BillingFlowParams.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ę, używając tokena transakcji zewnętrznej uzyskanego w poprzednim wywołaniu w przypadku zakupu nowej subskrypcji.
Zastąpienie subskrypcji w scenariuszu 1B
W takim przypadku należy wygenerować nowy token transakcji zewnętrznej. Jedyna różnica w porównaniu ze zwykłym zakupem polega na tym, że w tym scenariuszu wybór użytkownika jest zachowywany i nie musisz wyświetlać ekranu wyboru w przypadku przejścia na wyższą lub niższą wersję. Musisz jednak wyświetlić okno z informacjami jednorazowymi i potwierdzenie rodzica.
Przykładowy kod integracji znajdziesz w kroku 4 w scenariuszu 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ę, używając tokena transakcji zewnętrznej uzyskanego w poprzednim wywołaniu w przypadku zakupu nowej subskrypcji.
Zastąpienie subskrypcji w scenariuszu 2A
W przypadku subskrypcji, które zostały pierwotnie kupione na stronie dewelopera lub w aplikacji do płatności po dokonaniu wyboru przez użytkownika, użytkownicy proszący o przejście na wyższy lub niższy poziom powinni przejść przez stronę dewelopera lub aplikację do płatności bez ponownego przechodzenia przez proces wyboru.
Aby to zrobić, wywołaj funkcję launchBillingFlow, gdy użytkownik poprosi o przejście na wyższą lub niższą wersję. Zamiast określać inne parametry w obiekcie SubscriptionUpdateParams, użyj parametru setOriginalExternalTransactionId, podając zewnętrzny identyfikator transakcji pierwotnego zakupu.
W tym wywołaniu musi być też podana wartość DeveloperBillingOptionParams. Nie wyświetla to ekranu wyboru użytkownika, ponieważ wybór użytkownika dotyczący pierwotnego zakupu jest zachowywany w przypadku uaktualnień i obniżeń wersji. Przykład:
Kotlin
val externalTransactionId = //... ;
// 1. Construct DeveloperBillingOptionParams indicating the billing program
val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder()
.setBillingProgram(BillingClient.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()
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.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ć metodę launchBillingFlow, aby uruchomić proces zakupu.
Po zakończeniu przejścia na wyższą lub niższą wersję musisz zgłosić nową transakcję, używając tokena transakcji zewnętrznej uzyskanego w poprzednim wywołaniu w przypadku zakupu nowej subskrypcji.
Zastąpienie subskrypcji w scenariuszu 2B
Czynności związane z zastąpieniem subskrypcji w tym scenariuszu są podobne do czynności opisanych w sekcji Zastąpienie subskrypcji w scenariuszu 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 wyłączeniem odpowiedzialności za linki zewnętrzne. W takim przypadku wybór użytkownika jest zachowany 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 scenariuszu 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ę, używając tokena transakcji zewnętrznej uzyskanego w poprzednim wywołaniu w przypadku zakupu nowej subskrypcji.