Интегрируйте библиотеку платежей Google Play в свое приложение.

В этой теме описывается, как интегрировать библиотеку Google Play Billing Library в ваше приложение, чтобы начать продавать продукты.

Жизнь покупки

Вот типичный процесс покупки для разовой покупки или подписки.

  1. Покажите пользователю, что он может купить.
  2. Запустите процесс покупки, чтобы пользователь мог принять покупку.
  3. Подтвердите покупку на вашем сервере.
  4. Предоставьте контент пользователю.
  5. Подтвердите доставку контента. Для потребляемых продуктов потребите покупку, чтобы пользователь мог купить товар снова.

Подписки автоматически продлеваются до тех пор, пока не будут отменены. Подписка может проходить через следующие состояния:

  • Активно : Пользователь находится в хорошем состоянии и имеет доступ к подписке.
  • Отменено : Пользователь отменил подписку, но все еще имеет доступ до истечения срока действия.
  • В льготный период : у пользователя возникли проблемы с оплатой, но он по-прежнему имеет доступ, пока Google повторяет попытку оплаты.
  • На удержании : у пользователя возникла проблема с платежом, и он больше не имеет доступа, пока Google повторяет попытку оплаты.
  • Приостановлено : Пользователь приостановил свой доступ и не сможет получить его, пока не возобновит.
  • Истек срок действия : Пользователь отменил подписку и потерял к ней доступ. Пользователь считается отчисленным по истечении срока действия.

Инициализируйте подключение к Google Play

Первым шагом для интеграции с платежной системой Google Play является добавление библиотеки Google Play Billing Library в ваше приложение и инициализация соединения.

Добавьте зависимость от Google Play Billing Library

Добавьте зависимость 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, модуль Google Play Billing Library KTX содержит расширения 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 Library вам необходимо инициализировать экземпляр BillingClient . BillingClient — это основной интерфейс для связи между Google Play Billing Library и остальной частью вашего приложения. 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 Console, вместе с 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 Services . Чтобы обеспечить надлежащую поддержку для этого сценария, узнайте, как использовать функции обратной совместимости в руководстве по миграции Play Billing Library 5 .

Обработать результат

Библиотека Google Play Billing Library сохраняет результаты запроса в 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 показывает подписку, которая доступна для покупки
Рисунок 1. Экран покупки Google Play показывает подписку, доступную для покупки.

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
Рисунок 2. Экран успешной покупки в Google Play.

Успешная покупка также генерирует токен покупки, который является уникальным идентификатором, представляющим пользователя и идентификатор продукта для продукта внутри приложения, который он приобрел. Ваши приложения могут хранить токен покупки локально, хотя мы настоятельно рекомендуем передавать токен на ваш защищенный внутренний сервер, где вы затем можете проверить покупку и защититься от мошенничества. Этот процесс более подробно описан в разделе Обнаружение и обработка покупок .

Пользователю также отправляется по электронной почте квитанция о транзакции, содержащая идентификатор заказа или уникальный идентификатор транзакции. Пользователи получают электронное письмо с уникальным идентификатором заказа для каждой единовременной покупки продукта, а также для первоначальной покупки подписки и последующих повторяющихся автоматических продлений. Вы можете использовать идентификатор заказа для управления возвратами в консоли Google Play.

Укажите персональную цену

Если ваше приложение может распространяться среди пользователей в Европейском Союзе, используйте метод setIsOfferPersonalized() при вызове launchBillingFlow , чтобы сообщить пользователям, что цена товара была персонализирована с помощью автоматизированного принятия решений.

Экран покупки в Google Play, показывающий, что цена была настроена индивидуально для пользователя.
Рисунок 3. Экран покупки в Google Play, показывающий, что цена была настроена для пользователя.

Вам необходимо ознакомиться со статьей 6 (1) (ea) CRD Директивы о правах потребителей 2011/83/EU, чтобы определить, является ли предлагаемая вами пользователям цена персонализированной.

setIsOfferPersonalized() принимает логический ввод. Если true , пользовательский интерфейс Play включает раскрытие. Если false , пользовательский интерфейс пропускает раскрытие. Значение по умолчанию — false .

Более подробную информацию можно найти в Центре поддержки потребителей .

Прикрепите идентификаторы пользователей

При запуске процесса покупки ваше приложение может прикрепить любые идентификаторы пользователя, которые у вас есть для пользователя, совершающего покупку, используя obfuscatedAccountId или obfuscatedProfileId . Примером идентификатора может быть запутанная версия логина пользователя в вашей системе. Установка этих параметров может помочь Google обнаружить мошенничество . Кроме того, это может помочь вам гарантировать, что покупки приписываются правильному пользователю, как обсуждалось в разделе о предоставлении прав пользователям .

Обнаружение и обработка покупок

Обнаружение и обработка покупки, описанные в этом разделе, применимы ко всем типам покупок, включая покупки вне приложения, такие как погашение по акциям.

Ваше приложение обнаруживает новые покупки и завершенные ожидающие покупки одним из следующих способов:

  1. Когда onPurchasesUpdated вызывается в результате вызова вашим приложением launchBillingFlow (как обсуждалось в предыдущем разделе) или если ваше приложение работает с активным подключением Billing Library, когда совершается покупка вне вашего приложения или завершается ожидающая покупка. Например, член семьи одобряет ожидающую покупку на другом устройстве.
  2. Когда ваше приложение вызывает queryPurchasesAsync для запроса покупок пользователя.

Для #1 onPurchasesUpdated будет автоматически вызываться для новых или завершенных покупок, пока ваше приложение запущено и имеет активное подключение к Google Play Billing Library. Если ваше приложение не запущено или у вашего приложения нет активного подключения к Google Play Billing Library, onPurchasesUpdated не будет вызываться. Помните, что вашему приложению рекомендуется попытаться сохранить активное подключение, пока оно находится на переднем плане, чтобы гарантировать, что ваше приложение получает своевременные обновления покупок.

Для #2 вы должны вызвать BillingClient.queryPurchasesAsync() , чтобы ваше приложение обработало все покупки. Рекомендуется сделать это, когда ваше приложение успешно устанавливает соединение с библиотекой Google Play Billing Library (что рекомендуется, когда ваше приложение запускается или выходит на передний план, как обсуждалось в инициализации BillingClient ) . Это можно сделать, вызвав queryPurchasesAsync при получении успешного результата в onServiceConnected . Соблюдение этой рекомендации имеет решающее значение для обработки таких событий и ситуаций, как:

  • Проблемы с сетью во время покупки : пользователь может совершить успешную покупку и получить подтверждение от Google, но его устройство теряет сетевое подключение до того, как его устройство и ваше приложение получат уведомление о покупке через PurchasesUpdatedListener .
  • Несколько устройств : пользователь может купить товар на одном устройстве, а затем ожидать увидеть этот товар при смене устройства.
  • Обработка покупок, совершенных за пределами вашего приложения : некоторые покупки, например, по акциям, можно совершать за пределами вашего приложения.
  • Обработка переходов состояний покупки : пользователь может завершить оплату ОЖИДАЕМОЙ покупки, пока ваше приложение не запущено, и ожидать получения подтверждения о завершении покупки при открытии вашего приложения.

Как только ваше приложение обнаруживает новую или завершенную покупку, оно должно:

  • Подтвердите покупку.
  • Предоставлять контент пользователю за совершенные покупки.
  • Уведомить пользователя.
  • Сообщите Google, что ваше приложение обработало завершенные покупки.

Эти шаги подробно обсуждаются в следующих разделах, за которыми следует раздел, в котором кратко излагаются все шаги.

Подтвердите покупку

Ваше приложение всегда должно проверять покупки, чтобы убедиться, что они являются законными, прежде чем предоставлять преимущества пользователю. Это можно сделать, следуя рекомендациям, описанным в разделе Проверка покупок перед предоставлением прав . Только после проверки покупки ваше приложение должно продолжить обработку покупки и предоставить пользователю права, что обсуждается в следующем разделе.

Предоставить право пользователю

После того, как ваше приложение подтвердило покупку, оно может продолжить предоставлять пользователю право и уведомлять его. Перед предоставлением права убедитесь, что ваше приложение проверяет, что состояние покупкиPURCHASED . Если покупка находится в состоянии PENDING , ваше приложение должно уведомить пользователя о том, что ему все еще нужно выполнить действия для завершения покупки, прежде чем будет предоставлено право. Предоставляйте право только тогда, когда покупка переходит из состояния PENDING в состояние SUCCESS. Дополнительную информацию можно найти в разделе Обработка ожидающих транзакций .

Если вы прикрепили идентификаторы пользователя к покупке, как обсуждалось в разделе о прикреплении идентификаторов пользователя, вы можете извлечь их и использовать для привязки к правильному пользователю в вашей системе. Этот метод полезен при согласовании покупок, когда ваше приложение может потерять контекст о том, для какого пользователя предназначена покупка. Обратите внимание, что покупки, сделанные вне вашего приложения, не будут иметь установленных идентификаторов. В этом случае ваше приложение может либо предоставить право вошедшему в систему пользователю, либо предложить пользователю выбрать предпочтительную учетную запись.

Уведомить пользователя

После предоставления пользователю права ваше приложение должно отображать уведомление, подтверждающее успешную покупку. Это гарантирует, что пользователь не будет в замешательстве относительно того, была ли покупка успешно завершена, что может привести к тому, что пользователь прекратит использовать ваше приложение, обратится в службу поддержки пользователей или пожалуется на нее в социальных сетях. Помните, что ваше приложение может обнаружить обновления покупок в любой момент жизненного цикла вашего приложения. Например, родитель одобряет ожидающую покупку на другом устройстве, и в этом случае ваше приложение может захотеть отложить уведомление пользователя до подходящего времени. Вот несколько примеров, когда задержка будет уместной:

  • Во время действия игры или катсцен показ сообщения может отвлекать пользователя. В этом случае вы должны уведомить пользователя после того, как действие закончится.
  • Во время начального обучения и настройки пользователя в игре. Например, пользователь мог совершить покупку вне вашего приложения перед его установкой. Мы рекомендуем вам уведомить новых пользователей о награде сразу после того, как они откроют игру или во время начальной настройки пользователя. Если ваше приложение требует от пользователя создания учетной записи или входа в систему перед предоставлением пользователю права, рекомендуется сообщить пользователю, какие шаги необходимо выполнить, чтобы получить свою покупку. Это важно, поскольку возврат средств за покупки осуществляется через 3 дня, если ваше приложение не обработало покупку.

При уведомлении пользователя о покупке Google Play рекомендует следующие механизмы:

  • Показать диалоговое окно в приложении.
  • Отправьте сообщение в окно сообщений внутри приложения и четко укажите, что в окне сообщений внутри приложения есть новое сообщение.
  • Используйте уведомление ОС.

Уведомление должно сообщать пользователю о полученной выгоде. Например, «Вы приобрели 100 золотых монет!». Кроме того, если покупка была результатом выгоды такой программы, как Play Pass, ваше приложение сообщает об этом пользователю. Например, «Предметы получены! Вы только что получили 100 самоцветов с Play Pass. Продолжить». Каждая программа может иметь руководство по рекомендуемому тексту для отображения пользователям для сообщения о выгодах.

Уведомить Google о том, что покупка была обработана

После того, как ваше приложение предоставило пользователю право и уведомило его об успешной транзакции, вашему приложению необходимо уведомить Google о том, что покупка была успешно обработана. Это делается путем подтверждения покупки и должно быть сделано в течение трех дней, чтобы гарантировать, что покупка не будет автоматически возвращена, а право отменено . Процесс подтверждения различных типов покупок описан в следующих разделах.

Потребительские товары

Для расходных материалов, если в вашем приложении есть защищенный бэкэнд, мы рекомендуем использовать Purchases.products:consume для надежного потребления покупок. Убедитесь, что покупка еще не была потреблена, проверив consumptionState из результата вызова Purchases.products:get . Если ваше приложение предназначено только для клиента без бэкэнда, используйте consumeAsync() из библиотеки Google Play Billing Library. Оба метода выполняют требование подтверждения и указывают, что ваше приложение предоставило пользователю право. Эти методы также позволяют вашему приложению сделать одноразовый продукт, соответствующий введенному токену покупки, доступным для повторной покупки. С помощью consumeAsync() вы также должны передать объект, реализующий интерфейс ConsumeResponseListener . Этот объект обрабатывает результат операции потребления. Вы можете переопределить метод onConsumeResponse() , который библиотека Google Play Billing Library вызывает после завершения операции.

Следующий пример иллюстрирует использование продукта с помощью библиотеки Google Play Billing Library с использованием связанного токена покупки:

Котлин

    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 Billing Library в вашем приложении. Перед подтверждением покупки ваше приложение должно проверить, была ли она уже подтверждена с помощью метода isAcknowledged() в Google Play Billing Library.

В следующем примере показано, как подтвердить покупку с помощью библиотеки Google Play Billing:

Котлин

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 Billing Library, когда пользователь завершает покупку, ваш PurchasesUpdatedListener вызывается снова, и PurchaseState теперь имеет PURCHASED . На этом этапе ваше приложение может обработать покупку, используя стандартный метод Detecting and Processing Purchases . Ваше приложение также должно вызвать 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 для проверки текущего состояния покупки.

Обработка многообъемных закупок

Поддерживаемый в версиях 4.0 и выше Google Play Billing Library, Google Play позволяет клиентам приобретать более одного продукта в приложении за одну транзакцию, указав количество из корзины покупок. Ожидается, что ваше приложение будет обрабатывать покупки с несколькими количествами и предоставлять права на основе указанного количества покупок.

Для обработки покупок с несколькими количествами логика подготовки вашего приложения должна проверять количество товара. Вы можете получить доступ к полю quantity из одного из следующих API:

После добавления логики для обработки покупок в нескольких количествах вам необходимо включить функцию покупки в нескольких количествах для соответствующего продукта на странице управления продуктами в приложении в консоли разработчика 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 Игр (включены по умолчанию)

Для разработчиков игр, которые монетизируются через IAP, одним из способов, с помощью которого активные в Google Play Console единицы хранения (SKU) могут продаваться за пределами вашего приложения, является функция напоминания о прекращении покупки, которая подталкивает пользователей к завершению ранее прекращенных покупок во время просмотра Google Play Store. Эти покупки совершаются за пределами вашего приложения, из домашней страницы Google Play Games в Google Play Store.

Эта функция включена по умолчанию , чтобы помочь пользователям продолжить с того места, на котором они остановились, и помочь разработчикам максимизировать продажи. Однако вы можете отказаться от этой функции в своем приложении, отправив форму отказа от функции напоминания о брошенной корзине . Для получения рекомендаций по управлению артикулами в консоли Google Play см. раздел Создание продукта в приложении .

На следующих изображениях показано напоминание о брошенной корзине, появляющееся в магазине Google Play:

на экране Google Play Store отображается приглашение на покупку ранее отмененной покупки
Рисунок 2. На экране Google Play Store отображается запрос на совершение ранее отмененной покупки.

на экране Google Play Store отображается приглашение на покупку ранее отмененной покупки
Рисунок 3. На экране Google Play Store отображается запрос на покупку, от которой ранее отказались.