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
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:
| Gdzie odbywa się płatność? | |||
| W aplikacji | Zewnętrzny link internetowy | ||
| Który ekran wyboru płatności chcesz wyświetlić? | Obowiązujące w Google Play | Scenariusz 1A
Google renderuje ekran wyboru, a rozliczenia alternatywne są obsługiwane w aplikacji. |
Scenariusz 1B
Deweloper aplikacji wyświetla ekran wyboru, a alternatywny system rozliczeniowy jest obsługiwany w aplikacji. |
| własne (zgodnie z wytycznymi dotyczącymi UX); | Scenariusz 2A
Google wyświetla ekran wyboru, a użytkownik jest przekierowywany poza aplikację na Twoje strony internetowe w celu dokonania zakupu. |
Scenariusz 2B
Deweloper aplikacji wyświetla ekran wyboru, a użytkownik jest kierowany poza aplikację na własne strony internetowe 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 zaimplementować wybór rozliczeń w aplikacji.
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 opcja rozliczeń jest dostępna, 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 Płatności w 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 elementexternalTransactionToken. Token będzie używany do raportowania transakcji.
- Jeśli użytkownik wybierze Płatności w 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 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.
Wyświetl ekran wyboru alternatywnego systemu rozliczeniowego, jeśli wynik z poprzedniego kroku to
OK.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
launchBillingFlowzgodnie ze standardowymi wskazówkami dotyczącymi Płatności w Play. Wynik płatności zostanie zwrócony na adresPurchasesUpdatedListenerzarejestrowany w kroku 1. - Jeśli użytkownik wybierze Twoje rozliczenia alternatywne, 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 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 wyrenderowany 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 sposobu płatności, 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 płatności przez użytkownika w ten sposób:
- Jeśli użytkownik wybierze Płatności w Play, wywołaj
launchBillingFlowzgodnie ze standardowymi wskazówkami dotyczącymi Płatności w 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 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 wyrenderowany 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 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. } } );Wyświetl ekran z alternatywną opcją, gdy użytkownik kliknie „Kup”.
Obsłuż wybór typu płatności przez użytkownika w ten sposób:
Jeśli użytkownik wybierze Płatności w Play, wywołaj
launchBillingFlowzgodnie ze standardowymi wskazówkami dotyczącymi Płatności w 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 Twoje rozliczenia alternatywne, 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 sposobu rozliczeń 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 znaku 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 dotyczącego 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 płatniczej po wyborze użytkownika, użytkownicy proszący o przejście na wyższy lub niższy poziom powinni przejść przez stronę dewelopera lub aplikację płatniczą bez ponownego przechodzenia przez proces wyboru użytkownika.
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ż w przypadku uaktualnień i obniżeń wersji zachowywany jest wybór użytkownika dotyczący pierwotnego zakupu. 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.