Как перейти на библиотеку Google Play Платежей версии 6 с версии 4 или 5

В этой статье рассказывается, как перейти с библиотеки Google Play Платежей версии 4 или 5 на версию 6 и как использовать новые возможности подписок.

Полный список изменений в версии 6.0.0 приведен в примечаниях к выпуску.

Обзор

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

Подробную информацию о новых функциях, представленных в библиотеке Play Платежей версии 5, можно найти в статье Подписки в Play Console: недавние изменения.

Обновление библиотеки Play Платежей с обратной совместимостью

Все существующие подписки были автоматически преобразованы в соответствии с новой моделью в рамках выпуска библиотеки Play Платежей версии 5 и новой платформы для подписок в мае 2022 года. Это значит, что вам не нужно менять настройки подписок, чтобы каталог был совместим с новыми версиями библиотеки Play Платежей. Подробнее о том, как SKU подписок были преобразованы в обратно совместимые подписки, рассказывается в разделе Работа с подписками, созданными ранее этой статьи Справочного центра Play Console.

Старые версии приложения продолжают работать

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

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

Перейдите на библиотеку Play Платежей версии 5 или 6

В библиотеках Play Платежей версий 5 и 6 есть устаревшие методы querySkuDetailsAsync и BillingFlowParams.Builder.setSkuDetails, которые принимают SkuDetails в качестве параметра сценария оплаты. Это значит, что вы можете постепенно перейти на библиотеку Play Платежей версии 6, запланировав разные этапы перехода.

В качестве первого шага вы можете просто обновить версию библиотеки, оставить каталог и серверную часть без изменений и протестировать приложение, пока оно все ещё использует устаревшие методы. Если вы не используете queryPurchases, launchPriceChangeFlow или setVrPurchaseFlow, все должно работать как положено. После этого вы сможете постепенно внедрить новые возможности подписок, выпущенные в мае 2022 года.

Если вы уже внедрили эти функции при переходе на библиотеку Google Play Платежей версии 5, можете сразу перейти к разделам Обновление библиотеки Google Play Платежей и Изменение подписок пользователей. Если вы используете более раннюю версию или ещё не полностью внедрили новые функции, ознакомьтесь с полным руководством по переносу.

Этапы полного переноса

Создайте новые подписки в каталоге товаров на сервере

Используя Play Console или Google Play Developer API, вы можете настроить одну подписку с несколькими основными тарифными планами, в каждый из которых можно добавить несколько специальных предложений. Для самих предложений можно настраивать разные варианты оплаты и доступности. Вы можете создавать предложения на протяжении всего жизненного цикла подписки, выбирая разные планы с автоматическим продлением и предоплатой.

Перед переносом приложения рекомендуем создать новые продукты, следуя структуре объектов на новой платформе подписок для интеграции библиотеки Play Платежей 6. Вы можете объединить дублирующиеся товары в старом каталоге, представляющие одни и те же разрешения, в рамках одной подписки и использовать конфигурации основного тарифного плана и предложения, чтобы представить все варианты, которые вы хотите предложить. Подробную информацию об этой рекомендации можно найти в разделе Работа со старыми подписками статьи Справочного центра Play Console.

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

Чтобы избежать случайных изменений, которые могут привести к проблемам с существующей интеграцией, в процессе преобразования для продуктов по подписке, которые были в вашем каталоге до мая 2022 года, был установлен статус "Только чтение". Изменять такие подписки можно, но это может повлиять на интеграцию с внешним и внутренним интерфейсом.

  • На стороне клиента версии приложения, использующие querySkuDetailsAsync() для получения информации о товарах, могут продавать только обратно совместимые основные планы и специальные предложения. При этом доступна только одна комбинация обратно совместимого основного плана и специального предложения. Если вы добавите новые планы или предложения в преобразованные подписки, то не сможете продавать их в старых версиях приложения.

  • Если вы измените преобразованные подписки в Play Console, то не сможете управлять ими с помощью конечной точки inappproducts, даже если раньше использовали ее для этой цели. Вам также следует перейти на новую конечную точку статуса покупки подписки (purchases.subscriptionsv2.get), чтобы управлять покупками для этих подписок, поскольку старая конечная точка статуса покупки (purchases.subscriptions.get) возвращает только данные, необходимые для обработки покупок основных планов и специальных предложений с обратной совместимостью. Подробнее о том, как управлять статусом покупки подписки…

Управляйте каталогом подписок с помощью нового API

Если вы автоматически управляете каталогом подписок с помощью Google Play Developer API, то для создания подписок, основных планов и специальных предложений, а также управления ими вам нужно использовать новые конечные точки определения подписок. Чтобы узнать больше об изменениях в API каталога товаров, ознакомьтесь с руководством по функциям подписок за май 2022 года.

Чтобы перенести модуль автоматического управления каталогом товаров для подписок Google Play Платежей, замените API inappproducts новым Subscription Publishing API. Он позволяет управлять каталогом подписок и публиковать его. Доступны три новые конечные точки:

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

Для управления каталогом товаров, продаваемых через приложение, по-прежнему следует использовать API inappproducts для разовых покупок.

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

Обновите библиотеку Google Play Платежей

После создания нового каталога подписок вы можете перенести приложение в библиотеку Google Play Платежей версии 5. Замените существующую зависимость библиотеки Play Платежей на обновленную версию в файле build.gradle приложения.

dependencies {
    def billingVersion = "6.0.0"

    implementation "com.android.billingclient:billing:$billingVersion"
}

Проект должен сразу же собраться, даже если вы не изменили вызовы методов, поскольку библиотека Play Платежей 6 обратно совместима. Понятие SKU считается устаревшим, но оно по-прежнему используется, чтобы упростить перенос приложений.

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

Первые шаги по запуску покупок из приложения Android остаются прежними:

Показывать товары, доступные для покупки

Чтобы получить все предложения, доступные пользователю:

  • Замените SkuDetailsParams на QueryProductDetailsParams
  • Переключить звонок в BillingClient.querySkuDetailsAsync() на BillingClient.queryProductDetailsAsync()

Обратите внимание, что теперь результаты запроса – ProductDetails, а не SkuDetails. Каждый элемент ProductDetails содержит информацию о товаре (идентификатор, название, тип и т. д.). Для подписок ProductDetails содержит List<ProductDetails.SubscriptionOfferDetails> – список сведений о предложениях подписки. Для разовых покупок, ProductDetails содержит ProductDetails.OneTimePurchaseOfferDetails. Они позволяют определить, какие предложения нужно показать пользователям.

Ниже показано, как может выглядеть приложение до и после внесения изменений.

До

Kotlin

val skuList = ArrayList<String>()

skuList.add("up_basic_sub")

val params = SkuDetailsParams.newBuilder()

params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS).build()

billingClient.querySkuDetailsAsync(params) {
    billingResult,
    skuDetailsList ->
    // Process the result
}

Java

List<String> skuList = new ArrayList<>();

skuList.add("up_basic_sub");

SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();

params.setSkusList(skuList).setType(SkuType.SUBS).build();

billingClient.querySkuDetailsAsync(params,
    new SkuDetailsResponseListener() {
        @Override
        public void onSkuDetailsResponse(BillingResult billingResult,
                List<SkuDetails> skuDetailsList) {
            // Process the result.
        }
    }
);

После

Kotlin

val productList =
    listOf(
        QueryProductDetailsParams.Product.newBuilder()
            .setProductId("up_basic_sub")
            .setProductType(BillingClient.ProductType.SUBS)
            .build()
    )

val params = QueryProductDetailsParams.newBuilder().setProductList(productList).build()

billingClient.queryProductDetailsAsync(params) {
    billingResult,
    productDetailsList ->
    // Process the result
}

Java

ImmutableList<Product> productList = ImmutableList.of(Product.newBuilder()
                                            .setProductId("up_basic_sub")
                                            .setProductType(ProductType.SUBS)
                                            .build());

QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
    .setProductList(productList)
    .build();

billingClient.queryProductDetailsAsync(
        params,
        new ProductDetailsResponseListener() {
                public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) {
                    // Process the result
                }
        }
);

Обратный вызов для queryProductDetailsAsync возвращает List<ProductDetails>. Каждый элемент ProductDetails содержит информацию о товаре (идентификатор, название, тип и т. д.). Основное отличие заключается в том, что теперь подписки также содержат List<ProductDetails.SubscriptionOfferDetails> со всеми доступными пользователю предложениями.

Поскольку предыдущие версии библиотеки Play Платежей не поддерживают новые объекты (подписки, основные планы, специальные предложения и т. д.), новая система преобразует каждый SKU подписки в один основной план и специальное предложение с обратной совместимостью. Доступные для разовой покупки товары также переносятся в объект ProductDetails. Чтобы получить информацию о предложении, относящемся к контенту, оплачиваемому однократно, используйте метод getOneTimePurchaseOfferDetails().

В редких случаях некоторые устройства не поддерживают ProductDetails и queryProductDetailsAsync(). Обычно это связано с устаревшей версией сервисов Google Play. Чтобы обеспечить надлежащую поддержку в этом случае, вызовите isFeatureSupported() для функции PRODUCT_DETAILS перед вызовом queryProductDetailsAsync. Если ответ OK, устройство поддерживает эту функцию и вы можете вызвать queryProductDetailsAsync(). Если ответ – FEATURE_NOT_SUPPORTED, вы можете запросить список доступных обратно совместимых продуктов с помощью querySkuDetailsAsync(). Подробнее о том, как использовать функции обратной совместимости, рассказывается в руководстве по функциям подписок за май 2022 года.

Запуск процесса покупки специального предложения

Запуск процесса покупки для специального предложения очень похож на запуск процесса покупки для SKU. Чтобы начать запрос о покупке с помощью версии 6, выполните следующие действия:

  • Вместо SkuDetails для BillingFlowParams используйте ProductDetailsParams.
  • Сведения о специальных предложениях, например идентификатор предложения или основного плана, можно получить с помощью объекта SubscriptionOfferDetails.

Чтобы приобрести товар по выбранному пользователем предложению, получите offerToken выбранного предложения и передайте его в объект ProductDetailsParams.

После создания объекта BillingFlowParams запуск сценария оплаты с помощью BillingClient остается прежним.

Ниже показано, как может выглядеть приложение до и после внесения изменений.

До

Kotlin

// An activity reference from which the billing flow will be launched.
val activity : Activity = ...
// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
val billingFlowParams = BillingFlowParams.newBuilder()
                            .setSkuDetails(skuDetails)
                            .build()

val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

Java

// An activity reference from which the billing flow will be launched.
Activity activity = ...;
// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
        .setSkuDetails(skuDetails)
        .build();

BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

После

Kotlin

// 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 the offer token corresponding to the selected
        // offer call productDetails.subscriptionOfferDetails?.get(selectedOfferIndex)?.offerToken
        .setOfferToken(selectedOfferToken)
        .build()
)

val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build()

// Launch the billing flow
val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

Java

// 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 the offer token corresponding to the selected
            // offer call productDetails.getSubscriptionOfferDetails().get(selectedOfferIndex).getOfferToken()
            .setOfferToken(selectedOfferToken)
            .build()
    );

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build();

// Launch the billing flow
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

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

Обработка покупок в библиотеке Google Play Платежей версии 6 выполняется так же, как и в предыдущих версиях.

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

  • Вместо того чтобы передавать значение BillingClient.SkuType в queryPurchasesAsync(), передайте объект QueryPurchasesParams, содержащий значение BillingClient.ProductType.

Ниже показано, как может выглядеть приложение до и после внесения изменений.

До

Kotlin

billingClient.queryPurchasesAsync(BillingClient.SkuType.SUBS) {
    billingResult,
    purchaseList -> {
        // Process the result
    }
}

Java

billingClient.queryPurchasesAsync(
    BillingClient.SkuType.SUBS,
    new PurchasesResponseListener() {
        public void onQueryPurchasesResponse(
                BillingResult billingResult,
                List<Purchase> purchases) {
            // process the result
        }
    }
);

После

Kotlin

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder()
        .setProductType(BillingClient.ProductType.SUBS)
        .build()
) { billingResult, purchaseList ->
    // Process the result
}

Java

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder().setProductType(ProductType.SUBS).build(),
    new PurchasesResponseListener() {
        public void onQueryPurchasesResponse(
                BillingResult billingResult,
                List<Purchase> purchases) {
            // Process the result
        }
    }
);

Шаги по управлению покупками вне приложения и транзакциями в обработке не изменились.

Управляйте статусом покупки подписки с помощью нового API в серверной части

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

Вам нужно внедрить новый Subscription Purchases API в модуль управления статусом покупки подписок, который проверяет статус покупки и управляет правами на подписки Google Play Платежей на вашем сервере. Старая версия API не возвращает все необходимые сведения для управления покупками на новой платформе. Подробную информацию об изменениях по сравнению с предыдущими версиями можно найти в руководстве Новые функции подписок (май 2022 г.).

Обычно Subscription Purchases API вызывается каждый раз, когда вы получаете уведомление для разработчиков в режиме реального времени (SubscriptionNotification), чтобы получить актуальную информацию о статусе подписки. Вам нужно заменить вызовы purchases.subscriptions.get на новую версию Subscription Purchases API – purchases.subscriptionsv2.get. Новый ресурс SubscriptionPurchaseV2 предоставляет достаточно информации, чтобы управлять правами на покупку подписок в новой модели.

Новая конечная точка возвращает статус для всех ваших подписок и покупок независимо от версии приложения, в которой они были проданы, и времени определения продукта (до или после выпуска в мае 2022 года). Таким образом, после переноса вам понадобится только эта версия модуля управления статусом покупки подписки.

Как изменить подписки пользователя

В библиотеке Play Платежей версии 5 и более ранних для применения изменений к подпискам пользователей, например повышения или понижения уровня, использовался метод ProrationMode. В версии 6 этот метод был заменен на ReplacementMode.

Как обрабатывать изменения цен на подписки

Из библиотеки Play Платежей версии 6 удален API launchPriceConfirmationFlow, ранее признанный устаревшим. Альтернативные варианты описаны в руководстве по изменению цен.

Как обрабатывать ошибки библиотеки Play Платежей

В библиотеке Play Платежей 6 добавлен новый код NETWORK_ERROR, который указывает на проблемы с сетевым подключением между устройством пользователя и системой Google Play. Также изменились коды SERVICE_TIMEOUT и SERVICE_UNAVAILABLE. Подробнее о том, как обрабатывать коды ответов BillingResult…

Как обрабатывать транзакции в обработке

Начиная с версии 6.0.0 библиотека Play Платежей не создает идентификатор заказа для незавершенных покупок. Для таких покупок идентификатор заказа указывается после того, как покупка переходит в статус PURCHASED. Убедитесь, что интеграция ожидает идентификатор заказа только после полного завершения транзакции. Вы можете сохранить токен покупки для отчетности. Дополнительную информацию об обработке незавершенных покупок можно найти в руководстве по интеграции библиотеки Google Play Платежей и руководстве по управлению жизненным циклом покупок.