В этом руководстве рассказывается, как интегрировать в приложение API библиотеки Play Платежей, чтобы предлагать пользователям выбор платежной системы.
Интеграция с PBL
Вы можете интегрировать выбор платежной системы с библиотекой платежей в приложении в четырех сценариях. Сценарии различаются в зависимости от того, кто показывает экран выбора и где будет осуществляться платеж. В таблице ниже приведены сценарии интеграции.
| Какой экран выбора платежной системы вы хотите показывать? | |||
| Google Play | Ваш собственный (в соответствии с правилами в отношении удобства использования) | ||
| Где происходит оплата? | Приложения | Сценарий 1A
Google создает экран выбора, а альтернативная платежная система работает в вашем приложении. |
Сценарий 1Б
Разработчик приложения создает экран выбора, а альтернативная платежная система работает в приложении. |
| Внешняя ссылка | Сценарий 2A
Google создает экран выбора, и пользователь переходит из приложения на ваш сайт, чтобы совершить покупку. |
Сценарий 2Б
Разработчик приложения создает экран выбора, а пользователь переходит на сайт разработчика, чтобы совершить покупку. |
|
На иллюстрации ниже показан процесс выбора способа оплаты для каждого из этих сценариев.
Сценарии интеграции PBL
В зависимости от того, как вы интегрируете выбор платежной системы, выполните инструкции из этого раздела.
Обработка сценария 1A
Google отрисовывает экран выбора, а альтернативная платежная система обрабатывается в приложении. Чтобы включить выбор платежной системы в этом случае, выполните следующие действия:
При создании экземпляра BillingClient вызовите
enableBillingProgramсEnableBillingProgramParams, а затем установите подключение. Пример:Kotlin
// Build the parameters to enable the Billing Choice program and assign the listener // to handle user selection of the developer-provided billing option. val enableBillingProgramParams = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperProvidedBillingListener(developerProvidedBillingListener) .build() // Build the parameters to enable support for pending purchases. val pendingPurchasesParams = PendingPurchasesParams.newBuilder() .enableOneTimeProducts() .build() // Construct the BillingClient instance with the purchases updated listener, // pending purchases support, and the billing choice params. val billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases(pendingPurchasesParams) .enableBillingProgram(enableBillingProgramParams) .build() // Establish a connection to Google Play val billingResult = suspendCancellableCoroutine<BillingResult> { continuation -> billingClient.startConnection(object : BillingClientStateListener { // Called when the connection setup process completes. override fun onBillingSetupFinished(billingResult: BillingResult) { // Resume the coroutine and pass back the BillingResult to the caller. if (continuation.isActive) { continuation.resume(billingResult) } } // Called if the connection to the Play Store service is dropped. // This prevents the await or suspension point from hanging indefinitely. override fun onBillingServiceDisconnected() { if (continuation.isActive) { continuation.resume( BillingResult.newBuilder() .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED) .setDebugMessage("Billing service disconnected during connection setup") .build() ) } } }) }
Java
EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperProvidedBillingListener(developerProvidedBillingListener) .build(); BillingClient billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases( PendingPurchasesParams.newBuilder() .enableOneTimeProducts() .build() ) .enableBillingProgram(params) .build();Убедитесь, что пользователю доступен экран выбора платежной системы, созданный Google.
Позвоните по номеру
isBillingProgramAvailableAsync, чтобы узнать, доступна ли программа, а затем по номеруqueryProductDetailsAsync, чтобы посмотреть доступные продукты. Пример: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. } } );Примечание.
billingProgramAvailabilityDetailsпоказывает, доступен ли экран выбора платежной системы, созданный Google или разработчиком.Вызовите
launchBillingFlow, чтобы запустить процесс покупки, когда пользователь нажмет "Купить". Если доступен выбор платежной системы, передайте значениеDeveloperBillingOptionParamsв параметрBillingFlowParams. Пример: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);Примечание. Родительский контроль отображается для контролируемых пользователей.
Обрабатывайте выбор типа платежной системы пользователем следующим образом:
- Если пользователь выберет Play Платежи, результат оплаты будет возвращен в
PurchasesUpdatedListener, зарегистрированный на шаге 1. - Если пользователь выберет альтернативную платежную систему, результат оплаты будет возвращен в
DeveloperProvidedBillingListener, зарегистрированный на шаге 1. В этом случае возвращаемый объектDeveloperProvidedBillingDetailsсодержит объектexternalTransactionToken. Токен будет использоваться для отслеживания транзакций.
- Если пользователь выберет Play Платежи, результат оплаты будет возвращен в
Сценарий 1Б
Разработчик создает экран выбора, а альтернативная платежная система обрабатывается в приложении. Чтобы включить выбор платежной системы в этом случае, выполните следующие действия:
При создании экземпляра
BillingClientвызовитеenableBillingProgramбезDeveloperProvidedBillingListenerвEnableBillingProgramParams, а затем установите подключение. Пример:Kotlin
// Build the parameters to enable the Billing Choice program. val enableBillingProgramParams = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .build() // Build the parameters to enable support for pending purchases. val pendingPurchasesParams = PendingPurchasesParams.newBuilder() .enableOneTimeProducts() .build() // Construct the BillingClient instance with the purchases updated listener, // pending purchases support, and the billing choice params. val billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases(pendingPurchasesParams) .enableBillingProgram(enableBillingProgramParams) .build() // Establish a connection to Google Play val billingResult = suspendCancellableCoroutine<BillingResult> { continuation -> billingClient.startConnection(object : BillingClientStateListener { // Called when the connection setup process completes. override fun onBillingSetupFinished(billingResult: BillingResult) { // Resume the coroutine and pass back the BillingResult to the caller. if (continuation.isActive) { continuation.resume(billingResult) } } // Called if the connection to the Play Store service is dropped. // This prevents the await or suspension point from hanging indefinitely. override fun onBillingServiceDisconnected() { if (continuation.isActive) { continuation.resume( BillingResult.newBuilder() .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED) .setDebugMessage("Billing service disconnected during connection setup") .build() ) } } }) }
Java
EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .build(); BillingClient billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases() .enableBillingProgram(params) .build();Убедитесь, что пользователю доступен экран выбора платежной системы, созданный разработчиком.
Позвоните по номеру
isBillingProgramAvailableAsync, чтобы узнать, доступна ли программа, а затем по номеруqueryProductDetailsAsync, чтобы посмотреть доступные продукты. Пример: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. } } );Примечание. В
billingProgramAvailabilityDetailsуказано, какой экран выбора платежной системы доступен: созданный Google или разработчиком.Вызовите метод
getBillingChoiceInfoAsync, чтобы получить баннер Play Платежей и информацию о программе лояльности. Пример:Kotlin
// 1. Create the params required for the request val params = GetBillingChoiceInfoParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE) .build() // 2. Call the suspend method on your billingClient instance val (billingResult, playBillingChoiceInfo) = billingClient.getBillingChoiceInfo(params) if (billingResult.responseCode == BillingResponseCode.OK && playBillingChoiceInfo != null) { // Access the URL of the image associated with the Play Billing Choice val imageUrl = playBillingChoiceInfo.playBillingChoiceImageUrl // Access the Play Loyalty string information, if available val loyaltyInfo = playBillingChoiceInfo.playBillingLoyaltyInfo // Populate your developer-rendered UI elements playBillingLoyaltyTextView.text = loyaltyInfo loadImage(imageUrl, playBillingImageView) } else { // Handle error scenarios }
Java
// 1. Create the params required for the request GetBillingChoiceInfoParams params = GetBillingChoiceInfoParams.newBuilder() .setBillingProgram(BillingClient.BillingProgram.BILLING_CHOICE) .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE) .build(); // 2. Call the method asynchronously on your billingClient instance billingClient.getBillingChoiceInfoAsync(params, (billingResult, playBillingChoiceInfo) -> { if (billingResult.getResponseCode() == BillingResponseCode.OK && playBillingChoiceInfo != null) { // Access the URL of the image associated with the Play Billing Choice String imageUrl = playBillingChoiceInfo.getPlayBillingChoiceImageUrl(); // Access the Play Loyalty string information, if available String loyaltyInfo = playBillingChoiceInfo.getPlayBillingLoyaltyInfo(); // Populate your developer-rendered UI elements playBillingLoyaltyTextView.setText(loyaltyInfo); loadImage(imageUrl, playBillingImageView); } else { // Handle error scenarios } });Создайте токен внешней транзакции, задав для параметра DeveloperBillingType значение IN_APP. Пример:
Kotlin
// Build the parameters specifying the billing program and that the billing type is IN_APP. val params = BillingProgramReportingDetailsParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperBillingType(DeveloperBillingType.IN_APP) .build() // Call the suspending extension function to request the reporting details val (billingResult, billingProgramReportingDetails) = billingClient.createBillingProgramReportingDetails(params) if (billingResult.responseCode != BillingResponseCode.OK) { // Handle failures such as retrying due to network errors. return } // Extract the transaction token from the returned reporting details val transactionToken = billingProgramReportingDetails?.externalTransactionToken // Persist the external transaction token locally. Pass it to // DeveloperBillingOptionParams when launchBillingFlow is called. // It can also be used as part of your external website
Java
BillingProgramReportingDetailsParams params = BillingProgramReportingDetailsParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperBillingType(DeveloperBillingType.IN_APP) .build(); billingClient.createBillingProgramReportingDetailsAsync( params, new BillingProgramReportingDetailsListener() { @Override public void onCreateBillingProgramReportingDetailsResponse( BillingResult billingResult, @Nullable BillingProgramReportingDetails billingProgramReportingDetails ) { if (billingResult.getResponseCode() != BillingResponseCode.OK) { // Handle failures such as retrying due to network errors. return; } String transactionToken = billingProgramReportingDetails.getExternalTransactionToken(); // Persist the external transaction token locally. Pass it to // DeveloperBillingOptionParams when launchBillingFlow is called. // It can also be used as part of your external website } } );Когда пользователь нажимает "Купить", вызовите функцию
showBillingProgramInformationDialog, чтобы показать диалоговое окно с информацией. Например, диалоговое окно с информацией для пользователей. В запросе должны быть указаны BillingProgram и transactionToken, полученные на шаге 4.Примечание. Родительский контроль отображается для контролируемых пользователей.
Если на предыдущем шаге вы получили значение
OK, запустите экран выбора альтернативной платежной системы.Обрабатывайте выбор типа платежной системы пользователем следующим образом:
- Если пользователь выберет Google Play Платежи, вызовите
launchBillingFlowв соответствии со стандартными рекомендациями по использованию Google Play Платежей. Результат оплаты возвращается вPurchasesUpdatedListener, зарегистрированный на шаге 1. - Если пользователь выберет альтернативную платежную систему, вам нужно будет самостоятельно обработать транзакцию и сообщить о ней в Google Play, используя токен, сгенерированный на шаге 4.
- Если пользователь выберет Google Play Платежи, вызовите
Как обрабатывать сценарий 2A
Экран выбора платежной системы создается Google, а альтернативная платежная система обрабатывает платежи за пределами вашего приложения. Чтобы включить выбор платежной системы в этом случае, выполните следующие действия:
При создании экземпляра BillingClient вызовите
enableBillingProgramсEnableBillingProgramParams, а затем установите подключение. Пример:Kotlin
// Build the parameters to enable the Billing Choice program and assign the listener // to handle user selection of the developer-provided billing option. val enableBillingProgramParams = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperProvidedBillingListener(developerProvidedBillingListener) .build() // Build the parameters to enable support for pending purchases. val pendingPurchasesParams = PendingPurchasesParams.newBuilder() .enableOneTimeProducts() .build() // Construct the BillingClient instance with the purchases updated listener, // pending purchases support, and the billing choice params. val billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases(pendingPurchasesParams) .enableBillingProgram(enableBillingProgramParams) .build() // Establish a connection to Google Play val billingResult = suspendCancellableCoroutine<BillingResult> { continuation -> billingClient.startConnection(object : BillingClientStateListener { // Called when the connection setup process completes. override fun onBillingSetupFinished(billingResult: BillingResult) { // Resume the coroutine and pass back the BillingResult to the caller. if (continuation.isActive) { continuation.resume(billingResult) } } // Called if the connection to the Play Store service is dropped. // This prevents the await or suspension point from hanging indefinitely. override fun onBillingServiceDisconnected() { if (continuation.isActive) { continuation.resume( BillingResult.newBuilder() .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED) .setDebugMessage("Billing service disconnected during connection setup") .build() ) } } }) }
Java
EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperProvidedBillingListener(developerProvidedBillingListener) .build(); BillingClient billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases( PendingPurchasesParams.newBuilder() .enableOneTimeProducts() .build() ) .enableBillingProgram(params) .build();Проверьте, доступны ли следующие элементы:
- Выбор платежной системы, реализованный Google
- Внешняя ссылка
Позвоните по номеру
isBillingProgramAvailableAsync, чтобы узнать, доступна ли программа, а затем по номеруqueryProductDetailsAsync, чтобы посмотреть доступные товары. Пример: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. } } );Вызовите метод
createBillingProgramReportingDetailsAsync, чтобы создать внешний токен транзакции, когда пользователь выразит намерение совершить покупку. Пример: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 website
Java
BillingProgramReportingDetailsParams params = BillingProgramReportingDetailsParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK) .build(); billingClient.createBillingProgramReportingDetailsAsync( params, new BillingProgramReportingDetailsListener() { @Override public void onCreateBillingProgramReportingDetailsResponse( BillingResult billingResult, @Nullable BillingProgramReportingDetails billingProgramReportingDetails ) { if (billingResult.getResponseCode() != BillingResponseCode.OK) { // Handle failures such as retrying due to network errors. return; } String transactionToken = billingProgramReportingDetails.getExternalTransactionToken(); // Persist the external transaction token locally. Pass it to // DeveloperBillingOptionParams when launchBillingFlow is called. // It can also be used as part of your external website. } } );Вызовите
launchBillingFlow, чтобы запустить процесс покупки, когда пользователь нажмет "Купить". Если пользователю доступен выбор платежной системы, выполните следующие действия:- Передайте параметр
DeveloperBillingOptionParamsвBillingFlowParams. - Передайте токен внешней транзакции, полученный на шаге 3, в
DeveloperBillingOptionParams.
Пример:
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() val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .enableDeveloperBillingOption(developerBillingOptionParams) .build() val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
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();Примечание. Родительский контроль отображается для контролируемых пользователей.
- Передайте параметр
Обрабатывайте выбор типа платежной системы пользователем следующим образом:
- Если пользователь выберет Google Play Платежи, вызовите
launchBillingFlowв соответствии со стандартными рекомендациями по использованию Google Play Платежей. Результат оплаты возвращается вPurchasesUpdatedListener, зарегистрированный на шаге 1. - Если пользователь выберет альтернативную платежную систему, результат оплаты будет возвращен в
DeveloperProvidedBillingListener, зарегистрированный на шаге- .
- Возвращенный объект
DeveloperProvidedBillingDetailsсодержит объектexternalTransactionToken, который был передан вDeveloperBillingOptionParamsна шаге 4, если это действительный токен.
- Возвращенный объект
- Если пользователь выберет Google Play Платежи, вызовите
Сценарий 2Б
Разработчик создает экран выбора платежной системы, а альтернативная платежная система используется за пределами приложения. Чтобы включить выбор платежной системы в этом случае, выполните следующие действия:
Вызовите
enableBillingProgramбезDeveloperProvidedBillingListenerвEnableBillingProgramParamsпри создании экземпляра BillingClient, а затем запустите подключение. Пример:Kotlin
// Build the parameters to enable the Billing Choice program. val enableBillingProgramParams = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .build() // Build the parameters to enable support for pending purchases. val pendingPurchasesParams = PendingPurchasesParams.newBuilder() .enableOneTimeProducts() .build() // Construct the BillingClient instance with the purchases updated listener, // pending purchases support, and the billing choice params. val billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases(pendingPurchasesParams) .enableBillingProgram(enableBillingProgramParams) .build() // Establish a connection to Google Play val billingResult = suspendCancellableCoroutine<BillingResult> { continuation -> billingClient.startConnection(object : BillingClientStateListener { // Called when the connection setup process completes. override fun onBillingSetupFinished(billingResult: BillingResult) { // Resume the coroutine and pass back the BillingResult to the caller. if (continuation.isActive) { continuation.resume(billingResult) } } // Called if the connection to the Play Store service is dropped. // This prevents the await or suspension point from hanging indefinitely. override fun onBillingServiceDisconnected() { if (continuation.isActive) { continuation.resume( BillingResult.newBuilder() .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED) .setDebugMessage("Billing service disconnected during connection setup") .build() ) } } }) }
Java
EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .build(); BillingClient billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases() .enableBillingProgram(params) .build();Проверьте, доступны ли следующие элементы:
- Выбор платежной системы, реализованный Google
- Внешняя ссылка
Позвоните по номеру
isBillingProgramAvailableAsync, чтобы узнать, доступна ли программа, а затем по номеруqueryProductDetailsAsync, чтобы посмотреть доступные товары. Пример: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. } } );Вызовите метод
getBillingChoiceInfoAsync, чтобы получить баннер Play Платежей и информацию о программе лояльности.Kotlin
// 1. Create the params required for the request val params = GetBillingChoiceInfoParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE) .build() // 2. Call the suspend method on your billingClient instance val (billingResult, playBillingChoiceInfo) = billingClient.getBillingChoiceInfo(params) if (billingResult.responseCode == BillingResponseCode.OK && playBillingChoiceInfo != null) { // Access the URL of the image associated with the Play Billing Choice val imageUrl = playBillingChoiceInfo.playBillingChoiceImageUrl // Access the Play Loyalty string information, if available val loyaltyInfo = playBillingChoiceInfo.playBillingLoyaltyInfo // Populate your developer-rendered UI elements playBillingLoyaltyTextView.text = loyaltyInfo loadImage(imageUrl, playBillingImageView) } else { // Handle error scenarios }
Java
// 1. Create the params required for the request GetBillingChoiceInfoParams params = GetBillingChoiceInfoParams.newBuilder() .setBillingProgram(BillingClient.BillingProgram.BILLING_CHOICE) .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE) .build(); // 2. Call the method asynchronously on your billingClient instance billingClient.getBillingChoiceInfoAsync(params, (billingResult, playBillingChoiceInfo) -> { if (billingResult.getResponseCode() == BillingResponseCode.OK && playBillingChoiceInfo != null) { // Access the URL of the image associated with the Play Billing Choice String imageUrl = playBillingChoiceInfo.getPlayBillingChoiceImageUrl(); // Access the Play Loyalty string information, if available String loyaltyInfo = playBillingChoiceInfo.getPlayBillingLoyaltyInfo(); // Populate your developer-rendered UI elements playBillingLoyaltyTextView.setText(loyaltyInfo); loadImage(imageUrl, playBillingImageView); } else { // Handle error scenarios } });Вызовите метод
createBillingProgramReportingDetailsAsync, чтобы создать внешний токен транзакции, когда пользователь выразит намерение совершить покупку. Пример: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 website
Java
BillingProgramReportingDetailsParams params = BillingProgramReportingDetailsParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK) .build(); billingClient.createBillingProgramReportingDetailsAsync( params, new BillingProgramReportingDetailsListener() { @Override public void onCreateBillingProgramReportingDetailsResponse( BillingResult billingResult, @Nullable BillingProgramReportingDetails billingProgramReportingDetails ) { if (billingResult.getResponseCode() != BillingResponseCode.OK) { // Handle failures such as retrying due to network errors. return; } String transactionToken = billingProgramReportingDetails.getExternalTransactionToken(); // Persist the external transaction token locally. Pass it to // DeveloperBillingOptionParams when launchBillingFlow is called. // It can also be used as part of your external website. } } );Запускайте свой экран выбора, когда пользователь нажимает "Купить".
Обрабатывайте выбор типа платежной системы пользователем следующим образом:
Если пользователь выберет Google Play Платежи, вызовите
launchBillingFlowв соответствии со стандартными рекомендациями по использованию Google Play Платежей. Результат оплаты возвращается вPurchasesUpdatedListener, зарегистрированный на шаге 1.Родительский контроль доступен для контролируемых пользователей.
Если пользователь выбирает альтернативную платежную систему, вызовите launchExternalLink. Пример:
Kotlin
// An activity reference from which the purchase flow will be launched. val params = LaunchExternalLinkParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setExternalTransactionToken(transactionToken) // 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);Передайте токен внешней транзакции из шага 4 в
LaunchExternalLinkParams. Если возвращается значение OK, выполните транзакцию и сообщите о ней в Google Play.Родительский контроль доступен для контролируемых пользователей.
Выбор платежной системы при замене подписки
При замене подписки экран выбора не должен показываться, поскольку выбор пользователя для исходной покупки сохраняется при переходе на более или менее дорогой тарифный план.
Если первоначальная покупка была обработана через Google Play Платежи, позвоните по номеру launchBillingFlow и сообщите стандартную информацию о замене подписки Google Play Платежей.
Однако если исходная покупка была оформлена через альтернативную платежную систему, замена подписки будет выполняться по-разному в зависимости от ситуации.
Замена подписки в сценарии 1А
Пользователи, запрашивающие обновление или понижение версии, должны делать это через альтернативную платежную систему разработчика, не проходя процедуру выбора пользователя снова.
Для этого вызовите launchBillingFlow, когда пользователь запросит переход на другую версию. Используйте setOriginalExternalTransactionId внутри объекта SubscriptionUpdateParams в параметрах, чтобы указать внешний идентификатор транзакции для исходной покупки. Экран выбора платежной системы не показывается, поскольку выбор, сделанный при первоначальной покупке, сохраняется при переходе на более дорогой или дешевый тариф. В этом случае вызов launchBillingFlow создает новый внешний токен транзакции для транзакции, который можно получить из обратного вызова.
Kotlin
// The external transaction ID from the current // alternative billing subscription. val externalTransactionId = "external_transaction_id" val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .build() val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList( listOf( BillingFlowParams.ProductDetailsParams.newBuilder() // Fetched using queryProductDetailsAsync. .setProductDetails(productDetailsNewPlan) // offerIdToken can be found in // ProductDetails=>SubscriptionOfferDetails. .setOfferToken(offerTokenNewPlan) .build() ) ) .setSubscriptionUpdateParams( SubscriptionUpdateParams.newBuilder() .setOriginalExternalTransactionId(externalTransactionId) .build() ) .enableDeveloperBillingOption(developerBillingOptionParams) .build() val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams) // When the user selects the alternative billing flow, // the DeveloperProvidedBillingListener is triggered.
Java
// The external transaction ID from the current
// alternative billing subscription.
String externalTransactionId = //... ;
DeveloperBillingOptionParams developerBillingOptionParams =
DeveloperBillingOptionParams.newBuilder()
.setBillingProgram(BillingProgram.BILLING_CHOICE)
.build();
List<ProductDetailsParams> productDetailsParamsList = new ArrayList<>();
productDetailsParamsList.add(
ProductDetailsParams.newBuilder()
// Fetched using queryProductDetailsAsync.
.setProductDetails(productDetailsNewPlan)
// offerIdToken can be found in
// ProductDetails=>SubscriptionOfferDetails
.setOfferToken(offerTokenNewPlan)
.build());
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder()
.setOriginalExternalTransactionId(externalTransactionId)
.build())
.enableDeveloperBillingOption(developerBillingOptionParams)
.build();
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
// When the user selects the alternative billing flow,
// the DeveloperProvidedBillingListener is triggered.
После перехода на другую подписку вам нужно сообщить о новой транзакции, используя токен внешней транзакции, полученный при предыдущем вызове для покупки новой подписки.
Замена подписки в сценарии 1Б
В этом случае необходимо сгенерировать новый внешний токен транзакции. Единственное отличие от обычной покупки заключается в том, что в этом случае выбор пользователя сохраняется и вам не нужно показывать экран выбора для перехода на более или менее дорогой тарифный план. Однако вы должны показывать диалоговое окно с информацией, которая показывается только один раз, и подтверждение родителя.
Пример кода для интеграции можно найти в шаге 4 сценария 1Б: разработчик показывает экран выбора, а альтернативная платежная система обрабатывается в приложении.
После перехода на другую подписку вам нужно сообщить о новой транзакции, используя токен внешней транзакции, полученный при предыдущем вызове для покупки новой подписки.
Замена подписки в сценарии 2A
Если подписка была оформлена на сайте разработчика или в платежном приложении после выбора пользователем платежной системы, то при переходе на более дорогой или дешевый тарифный план пользователь должен снова перейти на сайт разработчика или в платежное приложение, не выбирая платежную систему.
Для этого вызовите launchBillingFlow, когда пользователь запросит переход на другую версию. Вместо того чтобы указывать другие параметры в объекте SubscriptionUpdateParams, используйте setOriginalExternalTransactionId, указав внешний идентификатор транзакции для исходной покупки.
В этом вызове также должен быть указан параметр DeveloperBillingOptionParams. При этом экран выбора платежной системы не показывается, поскольку выбор, сделанный при первоначальной покупке, сохраняется при переходе на более дорогой или дешевый тариф. Пример:
Kotlin
val externalTransactionId = "external_transaction_id" // 1. Construct DeveloperBillingOptionParams indicating the billing program val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .build() // 2. Build BillingFlowParams combining DeveloperBillingOptionParams and SubscriptionUpdateParams val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList( listOf( BillingFlowParams.ProductDetailsParams.newBuilder() // Fetched using queryProductDetailsAsync. .setProductDetails(productDetailsNewPlan) // offerIdToken can be found in ProductDetails=>SubscriptionOfferDetails. .setOfferToken(offerTokenNewPlan) .build() ) ) .setSubscriptionUpdateParams( SubscriptionUpdateParams.newBuilder() .setOriginalExternalTransactionId(externalTransactionId) .build() ) .enableDeveloperBillingOption(developerBillingOptionParams) .build()
Java
String externalTransactionId = //... ;
// 1. Construct DeveloperBillingOptionParams indicating the billing program
DeveloperBillingOptionParams developerBillingOptionParams =
DeveloperBillingOptionParams.newBuilder()
.setBillingProgram(BillingClient.BillingProgram.BILLING_CHOICE)
.build();
// 2. Add ProductDetailsParams
List productDetailsParamsList = new ArrayList<>();
productDetailsParamsList.add(
ProductDetailsParams.newBuilder()
// Fetched using queryProductDetailsAsync.
.setProductDetails(productDetailsNewPlan)
// offerIdToken can be found in ProductDetails=>SubscriptionOfferDetails
.setOfferToken(offerTokenNewPlan)
.build());
// 3. Build BillingFlowParams combining DeveloperBillingOptionParams and SubscriptionUpdateParams
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder()
.setOriginalExternalTransactionId(externalTransactionId)
.build())
.enableDeveloperBillingOption(developerBillingOptionParams)
.build();
Вам также нужно будет создать новый токен внешней транзакции. Пример:
Kotlin
val params = BillingProgramReportingDetailsParams.newBuilder() .setBillingProgram(BillingProgram.BILLING_CHOICE) .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK) .build() val (billingResult, billingProgramReportingDetails) = billingClient.createBillingProgramReportingDetails(params) if (billingResult.responseCode != BillingResponseCode.OK) { // Handle failures such as retrying due to network errors. return } val externalTransactionToken = billingProgramReportingDetails?.externalTransactionToken // Persist the external transaction token locally. Pass it to // the external website using DeveloperBillingOptionParams when // launchBillingFlow is called.
Java
BillingProgramReportingDetailsParams params =
BillingProgramReportingDetailsParams.newBuilder()
.setBillingProgram(BillingProgram.BILLING_CHOICE)
.setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
.build();
billingClient.createBillingProgramReportingDetailsAsync(
params,
new BillingProgramReportingDetailsListener() {
@Override
public void onCreateBillingProgramReportingDetailsResponse(
BillingResult billingResult,
@Nullable BillingProgramReportingDetails billingProgramReportingDetails) {
if (billingResult.getResponseCode() != BillingResponseCode.OK) {
// Handle failures such as retrying due to network errors.
return;
}
String transactionToken =
billingProgramReportingDetails.getExternalTransactionToken();
// Persist the external transaction token locally. Pass it to
// the external website using DeveloperBillingOptionParams when
// launchBillingFlow is called.
}
});
После создания нового токена необходимо вызвать метод launchBillingFlow, чтобы запустить процесс покупки.
После перехода на другую подписку вам нужно сообщить о новой транзакции, используя токен внешней транзакции, полученный при предыдущем вызове для покупки новой подписки.
Замена подписки в сценарии 2Б
Действия по замене подписки в этом сценарии аналогичны описанным в разделе Замена подписки в сценарии 2A. Единственное отличие заключается в том, что после создания токена транзакции вместо метода launchBillingFlow нужно вызвать метод launchExternalLink, чтобы показать диалоговое окно с отказом от ответственности. В этом случае выбор пользователя сохраняется, и вам не нужно показывать экран выбора при переходе на более новую или более старую версию.
Образец кода для интеграции можно найти на шаге 6 в сценарии 2Б: разработчик показывает экран выбора, а альтернативная платежная система обрабатывается в приложении.
После перехода на другую подписку вам нужно сообщить о новой транзакции, используя токен внешней транзакции, полученный при предыдущем вызове для покупки новой подписки.