В этом разделе описывается, как интегрировать библиотеку платежей Google Play в ваше приложение, чтобы начать продавать продукты.
Жизнь покупки
Вот типичный процесс покупки для разовой покупки или подписки.
- Покажите пользователю, что он может купить.
- Запустите процесс покупки, чтобы пользователь мог принять покупку.
- Подтвердите покупку на своем сервере.
- Дайте контент пользователю.
- Подтвердите доставку контента. Для расходных продуктов используйте покупку, чтобы пользователь мог купить ее снова.
Подписки автоматически продлеваются, пока не будут отменены. Подписка может проходить следующие состояния:
- Активный : пользователь имеет хорошую репутацию и имеет доступ к подписке.
- Отменено : пользователь отменил подписку, но все еще имеет доступ до истечения срока действия.
- В льготном периоде : у пользователя возникла проблема с оплатой, но он все еще имеет доступ, пока Google пытается повторно использовать способ оплаты.
- Приостановлено : у пользователя возникла проблема с оплатой, и он больше не имеет доступа, пока Google пытается повторно использовать способ оплаты.
- Приостановлено : пользователь приостановил доступ и не получит доступа до тех пор, пока не возобновит его.
- Срок действия истек : пользователь отменил подписку и потерял доступ к ней. Пользователь считается выбывшим по истечении срока действия.
Инициализировать подключение к Google Play
Первым шагом для интеграции с биллинговой системой Google Play является добавление библиотеки биллинга Google Play в ваше приложение и инициализация соединения.
Добавьте зависимость от библиотеки платежей Google Play.
Добавьте зависимость библиотеки Google Play Billing Library в файл build.gradle
вашего приложения, как показано:
классный
dependencies { def billing_version = "7.0.0" implementation "com.android.billingclient:billing:$billing_version" }
Котлин
dependencies { val billing_version = "7.0.0" implementation("com.android.billingclient:billing:$billing_version") }
Если вы используете Kotlin, модуль KTX библиотеки Google Play Billing Library содержит расширения Kotlin и поддержку сопрограмм, которые позволяют вам писать идиоматический Kotlin при использовании библиотеки Google Play Billing Library. Чтобы включить эти расширения в свой проект, добавьте следующую зависимость в файл build.gradle
вашего приложения, как показано:
классный
dependencies { def billing_version = "7.0.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
Котлин
dependencies { val billing_version = "7.0.0" implementation("com.android.billingclient:billing-ktx:$billing_version") }
Инициализация BillingClient
После добавления зависимости от библиотеки Google Play Billing вам необходимо инициализировать экземпляр BillingClient
. BillingClient
— это основной интерфейс для связи между Библиотекой платежей Google Play и остальной частью вашего приложения. BillingClient
предоставляет удобные методы, как синхронные, так и асинхронные, для многих распространенных операций выставления счетов. Обратите внимание на следующее:
- Рекомендуется одновременно открывать одно активное соединение
BillingClient
, чтобы избежать нескольких обратных вызововPurchasesUpdatedListener
для одного события. - Рекомендуется инициировать соединение для BillingClient, когда ваше приложение запускается или переходит на передний план, чтобы обеспечить своевременную обработку покупок вашим приложением. Этого можно добиться с помощью
ActivityLifecycleCallbacks
зарегистрированного с помощьюregisterActivityLifecycleCallbacks
, и прослушивания onActivityResumed для инициализации соединения при первом обнаружении возобновления действия. Более подробную информацию о том, почему следует следовать этой передовой практике, можно найти в разделе «Обработка покупок» . Также не забудьте завершить соединение, когда ваше приложение закрыто.
Чтобы создать BillingClient
, используйте newBuilder
. Вы можете передать в newBuilder()
любой контекст, и BillingClient
использует его для получения контекста приложения. Это означает, что вам не нужно беспокоиться об утечках памяти. Чтобы получать обновления о покупках, вы также должны вызвать setListener
, передав ссылку на PurchasesUpdatedListener
. Этот прослушиватель получает обновления обо всех покупках в вашем приложении.
Котлин
private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases -> // To be implemented in a later section. } private var billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build()
Ява
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() { @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { // To be implemented in a later section. } }; private BillingClient billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build();
Подключитесь к Google Play
После того, как вы создали BillingClient
, вам необходимо установить соединение с Google Play.
Чтобы подключиться к Google Play, вызовите startConnection
. Процесс подключения является асинхронным, и вам необходимо реализовать BillingClientStateListener
для получения обратного вызова после завершения настройки клиента и его готовности выполнять дальнейшие запросы.
Вам также необходимо реализовать логику повторных попыток для обработки потерянных подключений к Google Play. Чтобы реализовать логику повтора, переопределите метод обратного вызова onBillingServiceDisconnected()
и убедитесь, что BillingClient
вызывает метод startConnection()
для повторного подключения к Google Play, прежде чем делать дальнейшие запросы.
В следующем примере показано, как запустить соединение и проверить его готовность к использованию:
Котлин
billingClient.startConnection(object : BillingClientStateListener { override fun onBillingSetupFinished(billingResult: BillingResult) { if (billingResult.responseCode == BillingResponseCode.OK) { // The BillingClient is ready. You can query purchases here. } } override fun onBillingServiceDisconnected() { // Try to restart the connection on the next request to // Google Play by calling the startConnection() method. } })
Ява
billingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(BillingResult billingResult) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { // The BillingClient is ready. You can query purchases here. } } @Override public void onBillingServiceDisconnected() { // Try to restart the connection on the next request to // Google Play by calling the startConnection() method. } });
Показать продукты, доступные для покупки
После того, как вы установили соединение с Google Play, вы готовы запрашивать доступные продукты и отображать их своим пользователям.
Запрос сведений о продукте — важный шаг перед показом ваших продуктов пользователям, поскольку он возвращает локализованную информацию о продукте. Что касается подписок, убедитесь, что отображение вашего продукта соответствует всем правилам Play .
Чтобы запросить сведения о продукте, продаваемом в приложении, вызовите queryProductDetailsAsync
.
Чтобы обработать результат асинхронной операции, необходимо также указать прослушиватель, реализующий интерфейс ProductDetailsResponseListener
. Затем вы можете переопределить onProductDetailsResponse
, который уведомляет прослушиватель о завершении запроса, как показано в следующем примере:
Котлин
val queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build() billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult, productDetailsList -> // check billingResult // process returned productDetailsList }
Ява
QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build(); billingClient.queryProductDetailsAsync( queryProductDetailsParams, new ProductDetailsResponseListener() { public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) { // check billingResult // process returned productDetailsList } } )
При запросе сведений о продукте передайте экземпляр QueryProductDetailsParams
, который определяет список строк идентификатора продукта, созданных в консоли Google Play, вместе с ProductType
. ProductType
может быть либо ProductType.INAPP
для одноразовых продуктов, либо ProductType.SUBS
для подписок.
Запрос с расширениями Kotlin
Если вы используете расширения Kotlin , вы можете запросить сведения о продукте в приложении, вызвав функцию расширения queryProductDetails()
.
queryProductDetails()
использует сопрограммы Kotlin, поэтому вам не нужно определять отдельный прослушиватель. Вместо этого функция приостанавливает работу до завершения запроса, после чего вы можете обработать результат:
suspend fun processPurchases() {
val productList = listOf(
QueryProductDetailsParams.Product.newBuilder()
.setProductId("product_id_example")
.setProductType(BillingClient.ProductType.SUBS)
.build()
)
val params = QueryProductDetailsParams.newBuilder()
params.setProductList(productList)
// leverage queryProductDetails Kotlin extension function
val productDetailsResult = withContext(Dispatchers.IO) {
billingClient.queryProductDetails(params.build())
}
// Process the result.
}
В редких случаях некоторые устройства не поддерживают ProductDetails
и queryProductDetailsAsync()
, обычно из-за устаревших версий Служб Google Play . Чтобы обеспечить правильную поддержку этого сценария, узнайте, как использовать функции обратной совместимости, в руководстве по переходу на Play Billing Library 5 .
Обработать результат
Библиотека выставления счетов Google Play сохраняет результаты запроса в List
объектов ProductDetails
. Затем вы можете вызвать различные методы для каждого объекта ProductDetails
в списке, чтобы просмотреть соответствующую информацию о продукте, продаваемом в приложении, например его цену или описание. Чтобы просмотреть доступную подробную информацию о продукте, просмотрите список методов в классе ProductDetails
.
Прежде чем выставлять предмет на продажу, убедитесь, что он еще не принадлежит пользователю. Если у пользователя есть расходный материал, который все еще находится в его библиотеке предметов, он должен использовать этот предмет, прежде чем сможет купить его снова.
Прежде чем предлагать подписку, убедитесь, что пользователь еще не подписан. Также обратите внимание на следующее:
-
queryProductDetailsAsync()
возвращает сведения о продукте подписки и максимум 50 предложений на подписку. -
queryProductDetailsAsync()
возвращает только предложения, на которые имеет право пользователь. Если пользователь пытается приобрести предложение, на которое он не имеет права (например, если приложение отображает устаревший список подходящих предложений), Play информирует пользователя о том, что оно не имеет права, и пользователь может выбрать покупку базового плана. вместо.
Запустите процесс покупки
Чтобы запустить запрос на покупку из вашего приложения, вызовите метод launchBillingFlow()
из основного потока вашего приложения. Этот метод принимает ссылку на объект BillingFlowParams
, который содержит соответствующий объект ProductDetails
, полученный в результате вызова queryProductDetailsAsync
. Чтобы создать объект BillingFlowParams
, используйте класс BillingFlowParams.Builder
.
Котлин
// An activity reference from which the billing flow will be launched. val activity : Activity = ...; val productDetailsParamsList = listOf( BillingFlowParams.ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For One-time products, "setOfferToken" method shouldn't be called. // For subscriptions, to get an offer token, call ProductDetails.subscriptionOfferDetails() // for a list of offers that are available to the user .setOfferToken(selectedOfferToken) .build() ) val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build() // Launch the billing flow val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Ява
// An activity reference from which the billing flow will be launched. Activity activity = ...; ImmutableList<ProductDetailsParams> productDetailsParamsList = ImmutableList.of( ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For one-time products, "setOfferToken" method shouldn't be called. // For subscriptions, to get an offer token, call // ProductDetails.subscriptionOfferDetails() for a list of offers // that are available to the user. .setOfferToken(selectedOfferToken) .build() ); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); // Launch the billing flow BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
Метод launchBillingFlow()
возвращает один из нескольких кодов ответа, перечисленных в BillingClient.BillingResponseCode
. Обязательно проверьте этот результат, чтобы убедиться в отсутствии ошибок при запуске процесса покупки. BillingResponseCode
, равный OK
, указывает на успешный запуск.
При успешном вызове launchBillingFlow()
система отображает экран покупки в Google Play. На рис. 1 показан экран покупки подписки:
Google Play вызывает onPurchasesUpdated()
для доставки результата операции покупки прослушивателю, реализующему интерфейс PurchasesUpdatedListener
. Прослушиватель указывается с помощью метода setListener()
при инициализации клиента .
Вы должны реализовать onPurchasesUpdated()
для обработки возможных кодов ответа. В следующем примере показано, как переопределить onPurchasesUpdated()
:
Котлин
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) { if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) { for (purchase in purchases) { // Process the purchase as described in the next section. } } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling the purchase flow. } else { // Handle any other error codes. } }
Ява
@Override void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { // Process the purchase as described in the next section. } } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling the purchase flow. } else { // Handle any other error codes. } }
В случае успешной покупки появится экран успешной покупки в Google Play, аналогичный рис. 2.
В случае успешной покупки также создается токен покупки, который представляет собой уникальный идентификатор, представляющий пользователя и идентификатор продукта для приобретенного продукта внутри приложения. Ваши приложения могут хранить токен покупки локально, однако мы настоятельно рекомендуем передать токен на ваш защищенный внутренний сервер, где вы сможете затем подтвердить покупку и защититься от мошенничества. Этот процесс далее описан в разделе «Обнаружение и обработка покупок» .
Пользователю также отправляется по электронной почте квитанция о транзакции, содержащая идентификатор заказа или уникальный идентификатор транзакции. Пользователи получают электронное письмо с уникальным идентификатором заказа при каждой единоразовой покупке продукта, а также при первоначальной покупке подписки и последующих периодических автоматических продлениях. Вы можете использовать идентификатор заказа для управления возвратами средств в консоли Google Play.
Укажите персональную цену
Если ваше приложение может распространяться среди пользователей в Европейском Союзе, используйте метод setIsOfferPersonalized()
при вызове launchBillingFlow
, чтобы сообщить пользователям, что цена товара была персонализирована с использованием автоматического принятия решений.
Вам необходимо обратиться к ст. 6 (1) (ea) CRD Директивы о правах потребителей 2011/83/EU , чтобы определить, является ли цена, которую вы предлагаете пользователям, персонализированной.
setIsOfferPersonalized()
принимает логические входные данные. Если true
, пользовательский интерфейс Play включает раскрытие информации. Если false
, пользовательский интерфейс пропускает раскрытие. Значение по умолчанию — false
.
Дополнительную информацию см. в Центре помощи потребителям .
Прикрепите идентификаторы пользователей
Когда вы запускаете процесс покупки, ваше приложение может прикрепить любые имеющиеся у вас идентификаторы пользователя для пользователя, совершающего покупку, с помощью obfuscatedAccountId или obfuscatedProfileId . Примером идентификатора может быть запутанная версия имени пользователя в вашей системе. Установка этих параметров может помочь Google обнаружить мошенничество . Кроме того, это может помочь вам гарантировать, что покупки будут отнесены к нужному пользователю, как описано в разделе о предоставлении прав пользователям .
Обнаружение и обработка покупок
Обнаружение и обработка покупок, описанные в этом разделе, применимы ко всем типам покупок, в том числе к покупкам вне приложения, таким как промокоды.
Ваше приложение обнаруживает новые покупки и завершенные ожидающие покупки одним из следующих способов:
- Когда
onPurchasesUpdated
вызывается в результате вызова вашего приложенияlaunchBillingFlow
(как обсуждалось в предыдущем разделе) или если ваше приложение работает с активным подключением к библиотеке выставления счетов, когда покупка совершена вне вашего приложения или ожидающая покупка завершена. Например, член семьи одобряет ожидающую покупку на другом устройстве. - Когда ваше приложение вызывает queryPurchasesAsync для запроса покупок пользователя.
Для # 1 onPurchasesUpdated
будет автоматически вызываться для новых или завершенных покупок, пока ваше приложение работает и имеет активное соединение с библиотекой выставления счетов Google Play. Если ваше приложение не запущено или у него нет активного подключения к библиотеке Google Play Billing, onPurchasesUpdated
не будет вызываться. Помните, что вашему приложению рекомендуется стараться поддерживать активное соединение, пока ваше приложение находится на переднем плане, чтобы обеспечить своевременное получение обновлений для вашего приложения.
Для № 2 вы должны вызвать BillingClient.queryPurchasesAsync(), чтобы убедиться, что ваше приложение обрабатывает все покупки. Рекомендуется делать это, когда ваше приложение успешно устанавливает соединение с Библиотекой выставления счетов Google Play (что рекомендуется, когда ваше приложение запускается или переходит на передний план, как описано в разделе «Инициализация BillingClient» . Это можно сделать, вызвав queryPurchasesAsync при получении успешный результат для onServiceConnected . Следование этой рекомендации имеет решающее значение для обработки таких событий и ситуаций, как:
- Проблемы с сетью во время покупки . Пользователь может совершить успешную покупку и получить подтверждение от Google, но его устройство теряет подключение к сети до того, как его устройство и ваше приложение получат уведомление о покупке через
PurchasesUpdatedListener
. - Несколько устройств : пользователь может купить товар на одном устройстве, а затем ожидать увидеть его при переключении устройств.
- Обработка покупок, совершенных вне вашего приложения . Некоторые покупки, например скидки по рекламным акциям, можно совершать вне вашего приложения.
- Обработка переходов между состояниями покупки . Пользователь может совершить оплату ОЖИДАЮЩЕЙСЯ покупки, пока ваше приложение не запущено, и ожидать получения подтверждения о завершении покупки при открытии вашего приложения.
Как только ваше приложение обнаружит новую или завершенную покупку, оно должно:
- Подтвердите покупку.
- Предоставление контента пользователю за совершенные покупки.
- Уведомить пользователя.
- Сообщите Google, что ваше приложение обработало совершенные покупки.
Эти шаги подробно обсуждаются в следующих разделах, за которыми следует раздел, в котором кратко излагаются все шаги.
Подтвердить покупку
Ваше приложение должно всегда проверять покупки, чтобы убедиться в их законности, прежде чем предоставлять преимущества пользователю. Это можно сделать, следуя инструкциям, описанным в разделе «Проверка покупок перед предоставлением прав» . Только после подтверждения покупки ваше приложение должно продолжить обработку покупки и предоставить права пользователю, что обсуждается в следующем разделе.
Предоставить право пользователю
После того как ваше приложение подтвердит покупку, оно может продолжать предоставлять право пользователю и уведомлять его. Прежде чем предоставить право, убедитесь, что ваше приложение проверяет, что состояние покупки — PURCHASED
. Если покупка находится в состоянии ОЖИДАНИЕ, ваше приложение должно уведомить пользователя о том, что ему все еще необходимо выполнить действия для завершения покупки, прежде чем будет предоставлено право. Предоставляйте право только тогда, когда покупка переходит от ОЖИДАНИЯ к УСПЕХУ. Дополнительную информацию можно найти в разделе «Обработка ожидающих транзакций» .
Если вы прикрепили к покупке идентификаторы пользователей, как описано в разделе «Прикрепление идентификаторов пользователей», вы можете получить и использовать их для привязки к нужному пользователю в вашей системе. Этот метод полезен при сверке покупок, когда ваше приложение может потерять контекст о том, для какого пользователя предназначена покупка. Обратите внимание: для покупок, совершенных вне вашего приложения, эти идентификаторы не будут установлены. В этом случае ваше приложение может либо предоставить право вошедшему в систему пользователю, либо предложить пользователю выбрать предпочтительную учетную запись.
Уведомить пользователя
После предоставления права пользователю ваше приложение должно отображать уведомление о подтверждении успешной покупки. Это гарантирует, что пользователь не запутается в том, успешно ли завершилась покупка, что может привести к тому, что пользователь перестанет использовать ваше приложение, обратится в службу поддержки или пожалуется на это в социальных сетях. Имейте в виду, что ваше приложение может обнаружить обновления покупок в любой момент жизненного цикла приложения. Например, родитель одобряет ожидающую покупку на другом устройстве, и в этом случае ваше приложение может захотеть отложить уведомление пользователя до подходящего времени. Некоторые примеры, когда задержка была бы уместна:
- Во время активной части игры или роликов показ сообщения может отвлекать пользователя. В этом случае вы должны уведомить пользователя после завершения части действия.
- Во время первоначального обучения и настройки пользователя в игре. Например, пользователь мог совершить покупку вне вашего приложения перед его установкой. Мы рекомендуем уведомлять новых пользователей о награде сразу после открытия игры или во время первоначальной настройки пользователя. Если ваше приложение требует от пользователя создания учетной записи или входа в систему перед предоставлением права пользователю, рекомендуется сообщить пользователю, какие шаги необходимо выполнить, чтобы заявить о своей покупке. Это очень важно, поскольку средства за покупки возвращаются через 3 дня, если ваше приложение не обработало покупку.
При уведомлении пользователя о покупке Google Play рекомендует следующие механизмы:
- Показать диалог в приложении.
- Доставьте сообщение в ящик сообщений внутри приложения и четко укажите, что в ящике сообщений внутри приложения появилось новое сообщение.
- Используйте уведомление ОС.
Уведомление должно информировать пользователя о полученной им выгоде. Например, «Вы купили 100 золотых монет!». Кроме того, если покупка произошла в результате использования такой программы, как Play Pass, ваше приложение сообщает об этом пользователю. Например, «Предметы получены! Вы только что получили 100 драгоценных камней по Play Pass. Продолжить». Каждая программа может иметь рекомендации по тексту, который рекомендуется отображать пользователям для информирования о преимуществах.
Сообщите Google, что покупка обработана.
После того как ваше приложение предоставило право пользователю и уведомило его об успешной транзакции, вашему приложению необходимо уведомить Google об успешной обработке покупки. Это делается путем подтверждения покупки и должно быть сделано в течение трех дней, чтобы гарантировать, что покупка не будет автоматически возвращена и право не будет аннулировано . Процесс подтверждения различных типов покупок описан в следующих разделах.
Расходные материалы
Что касается расходных материалов, если ваше приложение имеет защищенную серверную часть, мы рекомендуем использовать Purchases.products:consume
для надежного потребления покупок. Убедитесь, что покупка еще не была использована, проверив consumptionState
из результата вызова Purchases.products:get
. Если ваше приложение предназначено только для клиента и не имеет серверной части, используйте consumeAsync()
из библиотеки выставления счетов Google Play. Оба метода удовлетворяют требованию подтверждения и указывают, что ваше приложение предоставило право пользователю. Эти методы также позволяют вашему приложению сделать одноразовый продукт, соответствующий входному токену покупки, доступным для выкупа. С помощью consumeAsync()
вы также должны передать объект, реализующий интерфейс ConsumeResponseListener
. Этот объект обрабатывает результат операции потребления. Вы можете переопределить метод onConsumeResponse()
, который вызывается Библиотекой выставления счетов Google Play после завершения операции.
В следующем примере показано использование продукта с помощью библиотеки платежей Google Play с использованием соответствующего токена покупки:
Котлин
val consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build() val consumeResult = withContext(Dispatchers.IO) { client.consumePurchase(consumeParams) }
Ява
ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); ConsumeResponseListener listener = new ConsumeResponseListener() { @Override public void onConsumeResponse(BillingResult billingResult, String purchaseToken) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { // Handle the success of the consume operation. } } }; billingClient.consumeAsync(consumeParams, listener);
Непотребительские товары
Чтобы подтвердить покупки, не требующие использования, если ваше приложение имеет защищенную серверную часть, мы рекомендуем использовать Purchases.products:acknowledge
для надежного подтверждения покупок. Убедитесь, что покупка не была ранее подтверждена, проверив acknowledgementState
из результата вызова Purchases.products:get
.
Если ваше приложение предназначено только для клиента, используйте BillingClient.acknowledgePurchase()
из библиотеки платежей Google Play в своем приложении. Прежде чем подтвердить покупку, ваше приложение должно проверить, было ли оно уже подтверждено, с помощью метода isAcknowledged()
в библиотеке платежей Google Play.
В следующем примере показано, как подтвердить покупку с помощью библиотеки платежей Google Play:
Котлин
val client: BillingClient = ... val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ... val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.purchaseToken) val ackPurchaseResult = withContext(Dispatchers.IO) { client.acknowledgePurchase(acknowledgePurchaseParams.build()) }
Ява
BillingClient client = ... AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ... AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
Подписки
Подписки обрабатываются аналогично нерасходным материалам. Если возможно, используйте Purchases.subscriptions.acknowledge
из API разработчика Google Play, чтобы надежно подтвердить покупку из вашего безопасного бэкэнда. Убедитесь, что покупка не была ранее подтверждена, проверив acknowledgementState
в ресурсе покупки из Purchases.subscriptions:get
. В противном случае вы можете подтвердить подписку с помощью BillingClient.acknowledgePurchase()
из библиотеки биллинга Google Play после проверки isAcknowledged()
. Все первоначальные покупки подписки необходимо подтвердить. Продление подписки не требует подтверждения. Дополнительные сведения о том, когда необходимо подтверждать подписки, см. в разделе «Продажа подписок» .
Резюме
В следующем фрагменте кода показано краткое изложение этих шагов.
Котлин
fun handlePurchase(Purchase purchase) { // Purchase retrieved from BillingClient#queryPurchasesAsync or your // onPurchasesUpdated. Purchase purchase = ...; // Step 1: Send the purchase to your secure backend to verify the purchase // following // https://developer.android.com/google/play/billing/security#verify . // Step 2: Update your entitlement storage with the purchase. If purchase is // in PENDING state then ensure the entitlement is marked as pending and the // user does not receive benefits yet. It is recommended that this step is // done on your secure backend and can combine in the API call to your // backend in step 1. // Step 3: Notify the user using appropriate messaging (delaying // notification if needed as discussed above). // Step 4: Notify Google the purchase was processed using the steps // discussed in the processing purchases section. }
Ява
void handlePurchase(Purchase purchase) { // Purchase retrieved from BillingClient#queryPurchasesAsync or your // onPurchasesUpdated. Purchase purchase = ...; // Step 1: Send the purchase to your secure backend to verify the purchase // following // https://developer.android.com/google/play/billing/security#verify // Step 2: Update your entitlement storage with the purchase. If purchase is // in PENDING state then ensure the entitlement is marked as pending and the // user does not receive benefits yet. It is recommended that this step is // done on your secure backend and can combine in the API call to your // backend in step 1. // Step 3: Notify the user using appropriate messaging (delaying // notification if needed as discussed above). // Step 4: Notify Google the purchase was processed using the steps // discussed in the processing purchases section. }
Чтобы убедиться, что ваше приложение правильно выполнило эти шаги, вы можете следовать руководству по тестированию .
Обработка ожидающих транзакций
Google Play поддерживает ожидающие транзакции или транзакции, которые требуют одного или нескольких дополнительных шагов между моментом, когда пользователь инициирует покупку, и моментом обработки способа оплаты покупки. Ваше приложение не должно предоставлять право на эти типы покупок, пока Google не уведомит вас об успешном списании средств с помощью метода оплаты пользователя.
Например, пользователь может инициировать транзакцию, выбрав физический магазин, где он позже расплатится наличными. Пользователь получает код как через уведомление, так и по электронной почте. Когда пользователь приходит в физический магазин, он может активировать код у кассира и оплатить наличными. Затем Google уведомляет вас и пользователя о получении платежа. Затем ваше приложение может предоставить право пользователю.
Вызовите enablePendingPurchases()
как часть инициализации BillingClient
, чтобы включить ожидающие транзакции для вашего приложения. Ваше приложение должно включать и поддерживать ожидающие транзакции для одноразовых продуктов. Прежде чем добавлять поддержку, убедитесь, что вы понимаете жизненный цикл покупки для ожидающих транзакций.
Когда ваше приложение получает новую покупку через PurchasesUpdatedListener
или в результате вызова queryPurchasesAsync
, используйте метод getPurchaseState()
чтобы определить, является ли состояние покупки PURCHASED
или PENDING
. Вы должны предоставлять право только в том случае, если состояние PURCHASED
.
Если ваше приложение запущено и у вас есть активное подключение к библиотеке выставления счетов Play, когда пользователь завершает покупку, ваш PurchasesUpdatedListener
вызывается снова, и PurchaseState
теперь имеет PURCHASED
. На этом этапе ваше приложение может обработать покупку, используя стандартный метод обнаружения и обработки покупок . Ваше приложение также должно вызывать queryPurchasesAsync()
в методе onResume()
вашего приложения для обработки покупок, которые перешли в состояние PURCHASED
пока ваше приложение не работало.
Когда покупка переходит с PENDING
на PURCHASED
, ваш клиент Real_time_developer_notifications получает уведомление ONE_TIME_PRODUCT_PURCHASED
или SUBSCRIPTION_PURCHASED
. Если покупка отменена, вы получите уведомление ONE_TIME_PRODUCT_CANCELED
или SUBSCRIPTION_PENDING_PURCHASE_CANCELED
. Это может произойти, если ваш клиент не совершит оплату в требуемые сроки. Обратите внимание, что вы всегда можете использовать API разработчика Google Play, чтобы проверить текущее состояние покупки.
Осуществляйте закупки в больших объемах
Google Play, поддерживаемый Библиотекой платежей Google Play версии 4.0 и выше, позволяет клиентам приобретать более одного одного и того же продукта внутри приложения за одну транзакцию, указав количество в корзине покупок. Ожидается, что ваше приложение будет обрабатывать покупки в нескольких количествах и предоставлять право на основе указанного количества покупок.
Чтобы учитывать покупки нескольких количеств, логика подготовки вашего приложения должна проверять количество товара. Вы можете получить доступ к полю quantity
с помощью одного из следующих API:
-
getQuantity()
из библиотеки платежей Google Play. -
Purchases.products.quantity
из API разработчика Google Play
После того как вы добавили логику для обработки покупок в нескольких количествах, вам необходимо включить функцию нескольких количеств для соответствующего продукта на странице управления продуктами в приложении в консоли разработчика Google Play.
Запросить платежную конфигурацию пользователя
getBillingConfigAsync()
предоставляет страну, которую пользователь использует для Google Play.
Вы можете запросить конфигурацию выставления счетов пользователя после создания BillingClient
. В следующем фрагменте кода описывается, как вызвать getBillingConfigAsync()
. Обработайте ответ, реализовав BillingConfigResponseListener
. Этот прослушиватель получает обновления для всех запросов конфигурации выставления счетов, инициированных из вашего приложения.
Если возвращенный BillingResult
не содержит ошибок, вы можете проверить поле countryCode
в объекте BillingConfig
чтобы получить страну воспроизведения пользователя.
Котлин
// Use the default GetBillingConfigParams. val getBillingConfigParams = GetBillingConfigParams.newBuilder().build() billingClient.getBillingConfigAsync(getBillingConfigParams, object : BillingConfigResponseListener { override fun onBillingConfigResponse( billingResult: BillingResult, billingConfig: BillingConfig? ) { if (billingResult.responseCode == BillingResponseCode.OK && billingConfig != null) { val countryCode = billingConfig.countryCode ... } else { // TODO: Handle errors } } })
Ява
// Use the default GetBillingConfigParams. GetBillingConfigParams getBillingConfigParams = GetBillingConfigParams.newBuilder().build(); billingClient.getBillingConfigAsync(getBillingConfigParams, new BillingConfigResponseListener() { public void onBillingConfigResponse( BillingResult billingResult, BillingConfig billingConfig) { if (billingResult.getResponseCode() == BillingResponseCode.OK && billingConfig != null) { String countryCode = billingConfig.getCountryCode(); ... } else { // TODO: Handle errors } } });
Напоминания о брошенных корзинах на главной странице Google Play Games (включено по умолчанию)
Для разработчиков игр, которые монетизируются через IAP, одним из способов продажи единиц хранения запасов (SKU), активных в консоли Google Play, за пределами вашего приложения, является функция напоминания об брошенной корзине, которая побуждает пользователей завершить ранее оставленные покупки, пока просмотр магазина Google Play. Эти покупки происходят за пределами вашего приложения, на главной странице Google Play Games в Google Play Store.
Эта функция включена по умолчанию, чтобы помочь пользователям продолжить с того места, на котором они остановились, и помочь разработчикам максимизировать продажи. Однако вы можете отказаться от этой функции в своем приложении, отправив форму отказа от функции напоминания о брошенной корзине . Рекомендации по управлению артикулами в консоли Google Play см. в разделе Создание продукта для продажи в приложении .
На следующих изображениях показано напоминание об брошенной корзине, появляющееся в магазине Google Play: