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

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

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

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

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

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

  • Активный: пользователь имеет хорошую репутацию и имеет доступ к подписке.
  • Отменено: пользователь отменил подписку, но все еще имеет доступ до истечения срока действия.
  • В льготном периоде: у пользователя возникла проблема с оплатой, но он все еще имеет доступ, пока 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 , используйте 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 product, "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) {
           handlePurchase(purchase)
       }
   } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) {
       // Handle an error caused by a user cancelling 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) {
            handlePurchase(purchase);
        }
    } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {
        // Handle an error caused by a user cancelling the purchase flow.
    } else {
        // Handle any other error codes.
    }
}

В случае успешной покупки появится экран успешной покупки в Google Play, аналогичный рис. 2.

Экран успешной покупки в Google Play
Рисунок 2. Экран успешной покупки в Google Play.

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

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

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

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

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

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

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

Дополнительную информацию см. в Центре помощи потребителям .

Обработка покупок

Как только пользователь совершает покупку, вашему приложению необходимо обработать эту покупку. В большинстве случаев ваше приложение уведомляется о покупках через PurchasesUpdatedListener . Однако в некоторых случаях ваше приложение будет уведомлено о покупках путем вызова BillingClient.queryPurchasesAsync() , как описано в разделе «Извлечение покупок» .

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

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

  1. Подтвердите покупку.
  2. Передайте контент пользователю и подтвердите доставку контента. При желании пометьте предмет как израсходованный, чтобы пользователь мог купить его снова.

Чтобы подтвердить покупку, сначала убедитесь, что покупка находится в состоянии PURCHASED . Если покупка PENDING , вам следует обработать ее, как описано в разделе «Обработка ожидающих транзакций» . Для покупок, полученных с помощью onPurchasesUpdated() или queryPurchasesAsync() , вам следует дополнительно проверить покупку, чтобы обеспечить ее законность, прежде чем ваше приложение предоставит право. Чтобы узнать, как правильно подтвердить покупку, см. раздел Проверка покупок перед предоставлением прав .

После того как вы подтвердите покупку, ваше приложение готово предоставить право пользователю. Учетную запись пользователя, связанную с покупкой, можно идентифицировать с помощью ProductPurchase.obfuscatedExternalAccountId , возвращаемого Purchases.products:get для покупок продуктов в приложении, и SubscriptionPurchase.obfuscatedExternalAccountId , возвращаемого Purchases.subscriptions:get для подписок на стороне сервера, или obfuscatedAccountId из Purchase.getAccountIdentifiers() на стороне клиента, если он был установлен с помощью setObfuscatedAccountId при совершении покупки.

После предоставления права ваше приложение должно подтвердить покупку. Это подтверждение сообщает Google Play, что вы предоставили право на покупку.

Процесс предоставления права и подтверждения покупки зависит от того, является ли покупка расходным материалом, нерасходным материалом или подпиской.

Расходные материалы

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

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

Котлин

suspend fun handlePurchase(purchase: Purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    val purchase : Purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant entitlement to the user.

    val consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.getPurchaseToken())
            .build()
    val consumeResult = withContext(Dispatchers.IO) {
        client.consumePurchase(consumeParams)
    }
}

Ява

void handlePurchase(Purchase purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    Purchase purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant entitlement to the user.

    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 = ...

suspend fun handlePurchase() {
    if (purchase.purchaseState === PurchaseState.PURCHASED) {
        if (!purchase.isAcknowledged) {
            val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.purchaseToken)
            val ackPurchaseResult = withContext(Dispatchers.IO) {
               client.acknowledgePurchase(acknowledgePurchaseParams.build())
            }
        }
     }
}

Ява

BillingClient client = ...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...

void handlePurchase(Purchase purchase) {
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
        if (!purchase.isAcknowledged()) {
            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() . Все первоначальные покупки подписки необходимо подтвердить. Продление подписки не требует подтверждения. Дополнительные сведения о том, когда необходимо подтверждать подписки, см. в разделе «Продажа подписок» .

Получение покупок

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

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

Чтобы справиться с такими ситуациями, убедитесь, что ваше приложение вызывает BillingClient.queryPurchasesAsync() в методе onResume() , чтобы гарантировать успешную обработку всех покупок, как описано в разделе «Обработка покупок» .

В следующем примере показано, как получить информацию о покупках подписки пользователя. Обратите внимание, что queryPurchasesAsync() возвращает только активные подписки и неизрасходованные разовые покупки.

Котлин

val params = QueryPurchasesParams.newBuilder()
               .setProductType(ProductType.SUBS)

// uses queryPurchasesAsync Kotlin extension function
val purchasesResult = billingClient.queryPurchasesAsync(params.build())

// check purchasesResult.billingResult
// process returned purchasesResult.purchasesList, e.g. display the plans user owns

Ява

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder()
      .setProductType(ProductType.SUBS)
      .build(),
    new PurchasesResponseListener() {
      public void onQueryPurchasesResponse(BillingResult billingResult, List<Purchase> purchases) {
        // check billingResult
        // process returned purchase list, e.g. display the plans user owns

      }
    }
);

Обработка покупок, совершенных вне вашего приложения

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

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

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

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

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

Всегда помните о пользователях, когда решаете, когда и как уведомлять пользователей о покупках, совершенных вне вашего приложения. Каждый раз, когда пользователь не получает немедленное уведомление, он может запутаться и прекратить использовать ваше приложение, обратиться в службу поддержки пользователей или пожаловаться на это в социальных сетях. Примечание. PurchasesUpdatedListener регистрируется в контексте вашего приложения для обработки обновлений покупок, включая покупки, инициированные вне вашего приложения. Это означает, что если процесс вашего приложения не существует, ваш PurchasesUpdatedListener не будет уведомлен. Вот почему ваше приложение должно вызывать BillingClient.queryPurchasesAsync() в методе onResume() , как указано в разделе Fetch Purchases .

Обработка ожидающих транзакций

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

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

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

Когда ваше приложение получает новую покупку через PurchasesUpdatedListener или в результате вызова queryPurchasesAsync() , используйте метод getPurchaseState() , чтобы определить, является ли состояние покупки PURCHASED или PENDING . Вы должны предоставлять право только в том случае, если состояние PURCHASED .

Если ваше приложение запускается, когда пользователь завершает покупку, ваш PurchasesUpdatedListener вызывается снова, и PurchaseState теперь PURCHASED . На этом этапе ваше приложение может обработать покупку, используя стандартный метод обработки покупок . Ваше приложение также должно вызывать queryPurchasesAsync() в методе onResume() вашего приложения для обработки покупок, которые перешли в состояние PURCHASED , пока ваше приложение не работало.

Когда покупка переходит с PENDING на PURCHASED , ваш клиент уведомлений для разработчиков в реальном времени получает уведомление ONE_TIME_PRODUCT_PURCHASED или SUBSCRIPTION_PURCHASED . Если покупка отменена, вы получите уведомление ONE_TIME_PRODUCT_CANCELED или SUBSCRIPTION_PENDING_PURCHASE_CANCELED . Это может произойти, если ваш клиент не совершит оплату в требуемый период времени. Обратите внимание, что вы всегда можете использовать API разработчика Google Play, чтобы проверить текущее состояние покупки.

Работа с оптовыми закупками

Google Play, поддерживаемый в версии 4.0 и более поздних версиях Библиотеки выставления счетов 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
        }
      }
    });