Если ваше PWA размещено в Google Play и вы хотите монетизировать его, продавая внутриигровые товары или подписки, политика Play потребует от вас внедрения Play Billing. Для этого вам потребуется внедрить два API: API цифровых товаров и API запросов платежей .
API цифровых товаров
API цифровых товаров — это интерфейс между вашим приложением и Google Play. Он позволяет получать доступ к цифровым продуктам и информации, которую вы указали для внутриигровых товаров и подписок в Play Console, а также получать информацию о существующих покупках пользователя. Если вы еще не добавили внутриигровые товары или подписки в Play Console, обязательно следуйте инструкциям по настройке Play Billing в Play Console .
30 ноября 2021 года была выпущена ChromeOS 96 с реализацией Digital Goods API 2.0.
Первоначальный этап тестирования первой версии API для цифровых товаров завершился 30 января 2022 года. Поэтому она устарела, и доступна только версия 2 API.
23 июня 2022 года была выпущена ChromeOS 103 с реализацией Digital Goods API 2.1. В этом релизе нет критических изменений, он включает только новые методы и дополнительные поля: listPurchaseHistory() и itemType .
Зарегистрируйтесь для участия в испытании Origin.
Примечание: API цифровых товаров в настоящее время доступен в рамках пробной версии Origin — механизма, позволяющего разработчикам получить ранний доступ к новым веб-API. Вам потребуется зарегистрироваться для участия в пробной версии Digital Goods API v2 Origin и запросить токен, который необходимо будет указать на любой странице вашего сайта Origin .
При регистрации в пробном периоде вы увидите дату «Действителен до», до которой ваш токен гарантированно будет работать. Не забудьте продлить срок действия ваших токенов по мере приближения этой даты, чтобы продолжить участие в пробном периоде. API, предлагаемые в рамках пробного периода, могут изменяться, поэтому обязательно следите за последними изменениями в любом пробном периоде, в котором вы участвуете. В случае возникновения каких-либо проблем обратитесь к документации по API цифровых товаров .
API запроса платежа
API запроса платежа обрабатывает фактическую платежную транзакцию при совершении покупки. Он использует данные о товаре, предоставленные API цифровых товаров, для совершения внутриигровой покупки с использованием соответствующего способа оплаты, в нашем случае это Google Play Billing.
Функция обнаружения API цифровых товаров
Проверить правильность включения API на вашем веб-сайте можно с помощью пробной версии, проверив наличие метода getDigitalGoodsService в объекте window .
if ('getDigitalGoodsService' in window) { // Digital Goods API is supported! } else { console.log('DigitalGoodsService is not available.'); // Use another payment method }
Подключитесь к сервису Google Play Billing.
API цифровых товаров разработан для совместимости с различными браузерами и цифровыми магазинами, аналогично тому, как API запросов платежей не зависит от браузера и может использоваться с различными платежными системами. Чтобы получить экземпляр сервиса, связанного с Google Play Billing, передайте строку "https://play.google.com/billing" в качестве способа оплаты в метод getDigitalGoodsService() .
Если метод выдает ошибку, значит, способ оплаты через Google Play Billing недоступен (например, пользователь заходит на ваше PWA через браузер). Вместо этого следует предложить другой способ оплаты транзакций.
if ('getDigitalGoodsService' in window) { // Digital Goods API is supported! try { const service = await window.getDigitalGoodsService('https://play.google.com/billing'); // Google Play Billing service is available } catch (error) { // Google Play Billing service is not available. Use another payment flow. } }
Получить подробную информацию о товаре
После подключения сервиса «Цифровые товары» к Google Play вы сможете использовать API для получения информации о товарах и покупках.
Метод getDetails() позволяет получить информацию об элементах, которые вы настроили в Play Console. Такая информация, как название продукта, описание и цена, должна отображаться пользователю в пользовательском интерфейсе вашего приложения, чтобы он знал, что доступно для покупки и по какой цене.
Для вызова метода getDetails() потребуется список идентификаторов элементов, соответствующих идентификаторам продуктов и подписок, созданных вами в Play Console.
const itemDetails = await service.getDetails(['product_1', 'product_2', 'product_3']); for (const item of itemDetails) { // Display item information to user displayItem(item.title, item.description, item.price); }
Для отображения цены, соответствующей языковому модулю пользователя, потребуется дополнительное форматирование:
const localePrice = new Intl.NumberFormat(navigator.language, { style: 'currency', currency: item.price.currency, }).format(item.price.value);
Примечание: API цифровых товаров не предоставляет способа получения списка идентификаторов товаров. Вместо этого вам потребуется либо жестко прописать их в вашем клиенте, либо получить их с вашего бэкэнд-сервера. API разработчиков Google Play позволяет запрашивать список идентификаторов товаров с бэкэнда. (Подробнее о внедрении ключевых компонентов Play Billing на вашем бэкэнд-сервере см . здесь.) Какое бы решение вы ни выбрали, убедитесь, что идентификаторы товаров соответствуют тем, что указаны в Play Console.
В версии 2.1 API одним из полей, возвращаемых функцией getDetails() является itemType . Это перечисление, значение которого — ”product” или ”subscription” указывающее, является ли соответствующий элемент внутриигровым продуктом или подпиской соответственно. Возможность различать два типа продуктов может быть полезна, если вам нужно применять разные подходы к каждому типу продукта. Например, у вас может быть отдельная страница для подписки пользователей и другая страница для других продуктов, не являющихся подписками. Это также полезно для определения подходящего REST-ресурса Google Play Developer API для использования в вашем бэкэнде ( purchases.products или purchases.subscriptions ).
Купить товар
После того, как ваши товары и подробная информация будут отображены пользователю, вы можете построить процесс покупки с помощью API запроса платежа. При использовании совместно с API цифровых товаров требуется только один входной параметр: methodData .
Система Play Billing позволяет покупать только один предмет за раз; цена и характеристики предмета уже известны серверу Play, поэтому параметр details не требуется. Более подробное объяснение см. в пояснительной статье .
Используйте член supportedMethods параметра methodData в PaymentRequest , чтобы указать Google Play Billing в качестве способа оплаты, используя строку "https://play.google.com/billing" . Затем в члене data передайте идентификатор товара в качестве артикула sku .
const paymentMethodData = [ { supportedMethods: 'https://play.google.com/billing', data: { sku: item.itemId, }, }, ];
Затем создайте запрос на оплату и вызовите show() , чтобы запустить процесс оплаты:
const request = new PaymentRequest(paymentMethodData); const paymentResponse = await request.show();
Это отобразит пользователю интерфейс покупки в Play Store, где он увидит подробную информацию о продукте, который пытается приобрести. Он может либо отменить транзакцию, либо продолжить оплату. Если пользователь отменит оплату, промис, возвращаемый функцией show() будет отклонен с ошибкой. Если он успешно оплатит и завершит покупку, промис разрешится с помощью PaymentResponse . В свойстве details ответа на платеж возвращается токен покупки.
Для предотвращения мошенничества крайне важно проверять покупку и токен покупки на вашем бэкэнд-сервере. Также рекомендуется отслеживать пользователей и связанные с ними токены покупок. Узнайте, как реализовать проверку на вашем бэкэнд-сервере .
После подтверждения покупки вызовите complete() для ответа на платеж, чтобы завершить процесс оплаты и закрыть интерфейс выставления счетов. Вы также можете передать необязательную строку result , чтобы указать состояние процесса оплаты. Браузер сам решает, показывать ли пользователю какие-либо сообщения об этом результате. Chrome не создает никаких видимых пользователю подсказок, поэтому рекомендуется отображать собственные сообщения об ошибке или об успехе в вашем PWA.
/* Changes were recently made so that the PaymentResponse `details` property returns the purchase token as `purchaseToken` instead of `token`. Note that `token` will be deprecated at some point in the future. To ensure that your app won't be affected by this, make the change to `purchaseToken` in your client code and use the latest version of Bubblewrap (v1.13.5 and later) to update and generate a new app package to upload to the Play Console. */ const { purchaseToken } = paymentResponse.details; let paymentComplete; if (validatePurchaseOnBackend(purchaseToken)) { paymentComplete = await paymentResponse.complete('success'); // Let user know their purchase transaction has successfully completed and been verified } else { paymentComplete = await paymentResponse.complete('fail'); // Let user know their purchase transaction failed to verify }
Повышение и понижение уровня подписки
Процесс покупки одинаков как для внутриигровых товаров, так и для подписок. Однако для подписок Google Play предлагает дополнительные варианты покупки: повышение и понижение уровня. При формировании data для способа оплаты вам потребуется передать следующие данные, чтобы запустить процесс повышения или понижения уровня:
-
sku: Это идентификатор товара для новой подписки, на которую будет произведено повышение или понижение уровня подписки. -
oldSku: Это идентификатор товара для текущей подписки пользователя. -
purchaseToken: Это токен покупки для текущей подписки пользователя. Как уже отмечалось ранее, рекомендуется отслеживать токены покупок в бэкэнде. И в этом, и в других случаях, следует связывать пользователя с его текущими покупками и токенами покупок. -
prorationMode: Так будет производиться оплата новой подписки при замене текущей подписки пользователя.
| Режим пропорционального распределения | Описание |
|---|---|
Немедленная оплата и расчет пропорциональной стоимости | Подписка обновляется немедленно, а цикл выставления счетов остается прежним. Разница в цене за оставшийся период затем списывается с пользователя. |
immediateAndChargeFullPrice | При повышении или понижении уровня подписки с пользователя немедленно взимается полная стоимость нового права доступа. Остаток средств от предыдущей подписки пропорционально времени используется для оплаты новой подписки. Этот режим пропорционального распределения был недавно добавлен в релизе Google Play Billing Library 4.0. Теперь он доступен через Bubblewrap, начиная с версии 1.13.5. |
немедленно Без пропорционального распределения | ВРЕМЕННО ОТКЛЮЧЕНО. В этом режиме пропорционального распределения существует потенциальная возможность мошенничества, позволяющая пользователям получить расширенную подписку без дополнительной оплаты за один расчетный период. Обратите внимание, что мы временно отключили этот режим, пока работаем над исправлением. |
immediateWithTimeProration | Подписка обновляется или понижается немедленно. Оставшееся время корректируется в зависимости от разницы в цене и зачисляется на счет новой подписки путем переноса следующей даты выставления счета. Это поведение по умолчанию. |
отложенный | Повышение или понижение уровня подписки происходит только при её продлении. Это особенно полезно для понижения уровня подписки. |
unknownSubscriptionUpgradeDowngradePolicy | Единой политики нет. Это не рекомендуется. |
Подробнее о различных режимах пропорционального распределения можно узнать в справочной документации библиотеки Google Play Billing. Дополнительную информацию об обновлении и понижении уровня подписки, а также рекомендации по режимам пропорционального распределения можно найти в документации для разработчиков Android.
Использование этих дополнительных полей будет выглядеть примерно так:
const paymentMethod = [ { supportedMethods: 'https://play.google.com/billing', data: { sku: item.itemId, oldSku: oldPurchase.itemId, purchaseToken: oldPurchase.purchaseToken, prorationMode: 'immediateAndChargeProratedPrice', }, }, ];
Здесь item — это ItemDetails новой подписки, на которую пользователь пытается перейти на более высокий или более низкий уровень, а oldPurchase — это PurchaseDetails текущей подписки пользователя.
Подтвердите покупку
После того, как пользователь совершит покупку, вы должны предоставить ему соответствующие права доступа (доступ к приобретенному товару или контенту). Затем подтвердите покупку. Подтверждение покупки дает Google Play понять, что вы получили и обработали покупку надлежащим образом.
Примечание: Если покупка не подтверждена в течение 72 часов с момента совершения покупки, платеж возвращается пользователю, а покупка аннулируется. Токен покупки становится недействительным, поэтому при запросе существующих покупок аннулированная покупка не будет возвращена. Это гарантирует, что с пользователя не будет списана неправомерная сумма в случае сетевой ошибки, из-за которой ему не будет предоставлен товар.
Вам следует подтверждать покупки на своем бэкэнд-сервере, используя API разработчиков Google Play. Мы рекомендуем сначала предоставить права доступа, а затем подтвердить покупку одновременно на вашем бэкэнд-сервере.
- После того, как пользователь совершит покупку на стороне клиента, отправьте токен покупки и идентификатор товара в запросе на ваш бэкэнд-сервер.
- Для получения подробной информации о покупке и ее подтверждения на вашем бэкэнде позвоните по следующему номеру:
- purchases.products.get для внутриигровых товаров.
- purchases.subscriptions.get для оформления подписок.
- Предоставьте соответствующие права доступа в вашей серверной базе данных.
- Затем подтвердите покупку, позвонив по телефону:
- purchases.products.acknowledge для внутриигровых товаров.
- purchases.subscriptions.acknowledge for subscriptions.
Совершить покупку
Подтверждение покупки сообщает Google Play, что пользователь теперь является владельцем товара и не должен иметь возможности приобрести его снова. Если это товар, который пользователю нужно будет купить только один раз и который останется у него навсегда (например, скин игрового персонажа), то этот товар не является расходным.
В качестве альтернативы, можно ограничить количество предметов, которые пользователь может приобрести один раз. В этом случае пользователю потребуется использовать предмет, прежде чем он сможет купить еще один. Когда пользователь «использует» предмет, чтобы сообщить Google Play о его использовании, следует вызвать метод consume() . После этого Google Play сделает предмет доступным для повторной покупки.
Для предметов, которые пользователь может приобрести в нескольких экземплярах, необходимо обеспечить возможность многократной покупки без предварительного использования (мы называем такие предметы повторяемыми). Аналогично, эти предметы должны быть «потреблены», прежде чем Google Play позволит пользователю купить их снова. Поэтому, даже если пользователь еще не использовал предмет, необходимо вызвать метод consume() , чтобы пометить предмет как потребленный.
// After the user purchases the item, send the purchase token and item ID to your backend to grant the entitlement and acknowledge it right away . . . // When the user uses the item or if it is a repeatable item, consume it so it’s available for purchase again. service.consume(purchaseToken); }
Проверить существующие покупки
Последний ключевой пользовательский сценарий — проверка существующих покупок (внутриигровых товаров, которые еще не были использованы, и действующих подписок), чтобы сообщить пользователям, какими подписками или товарами они в настоящее время владеют. Эти существующие покупки будут представлять собой предыдущие покупки в Google Play на любом устройстве, совершенные внутри приложения или в Play Store. Покупки, совершенные вне приложения в Play Store, называются покупками вне приложения .
При получении информации о существующих покупках следует также проверить статус подтверждения и подтвердить все покупки, которые были совершены ранее, но не были должным образом подтверждены. Рекомендуется подтверждать покупки как можно скорее, чтобы права пользователя были актуальными и корректно отображались в приложении.
Метод listPurchases() API цифровых товаров вернет список объектов PurchaseDetails , содержащий itemId и purchaseToken для каждой покупки. Вам потребуется использовать API разработчиков Google Play на вашем бэкэнд-сервере, чтобы проверить состояние покупок и соответствующим образом подтвердить их. Вам следует:
- Для получения списка покупок пользователя вызовите метод
listPurchases()из API цифровых товаров на стороне клиента. - Для каждой покупки передавайте
purchaseTokenиitemIdв вашу административную панель. - При необходимости предоставьте права доступа в вашей серверной базе данных.
- Затем вызовите функцию и проверьте состояние
acknowledgementState).- purchases.products.get для внутриигровых товаров.
- purchases.subscriptions.get для оформления подписок.
- Если значение равно 0 (это еще не подтверждено), то вызовите:
- purchases.products.acknowledge для внутриигровых товаров.
- purchases.subscriptions.acknowledge for subscriptions.
Узнайте больше о том, как проверять покупки на вашем бэкэнд-сервере перед предоставлением прав доступа .
История покупок
В то время как метод listPurchases возвращает информацию о существующих покупках пользователя, метод listPurchaseHistory() (в версии 2.1 API) возвращает самую последнюю покупку, совершенную пользователем для каждого товара, независимо от того, истекла ли покупка, отменена или потреблена. Метод listPurchaseHistory() возвращает список объектов PurchaseDetails содержащий itemId и purchaseToken для каждой покупки, который вам потребуется использовать с Google Play Developer API на вашем бэкэнд-сервере для получения дополнительной информации.
Покупки вне приложения
Покупки вне приложения — это покупки, совершаемые не в рамках обычного процесса внутриигровых покупок. Обычно они происходят в Play Store, а не в вашем приложении. Существует два основных способа совершения пользователями покупок вне приложения:
- Использование промокода : В пользовательском меню Play Store, в разделе «Предложения и уведомления» -> «Использовать промокод» или в разделе «Платежи и подписки» -> «Использовать подарочный код» .
- Повторная подписка : В пользовательском меню Play Store, в разделе «Платежи и подписки» -> «Подписки» . Здесь пользователи могут управлять всеми своими подписками в разных приложениях. Для истекших или отмененных подписок у пользователей есть возможность «Повторно подписаться».
Когда пользователи повторно оформляют подписку в Play Store, их покупки не подтверждаются автоматически, что может привести к возврату средств. Такое поведение является преднамеренным, поскольку с пользователей должна взиматься плата за подписку только в том случае, если они открывают приложение для его использования. Пользователь может увидеть сообщение «Подтвердите подписку», напоминающее ему о необходимости открыть приложение.

Задача разработчика — обеспечить подтверждение этих покупок после запуска приложения пользователем. Поэтому мы рекомендуем проверять наличие существующих покупок (обычно это происходит при первом запуске приложения) и подтверждать все покупки, которые еще не были подтверждены.
Предоставьте пользователям возможность управлять подписками
Для обеспечения удобного пользовательского опыта важно предоставить пользователям возможность управлять своими подписками и отменять их прямо в приложении. Мы рекомендуем создать прямую ссылку на странице настроек или в меню, которая будет перенаправлять пользователя на страницу управления подписками вашего приложения в Play Store. Замените следующий URL-адрес на соответствующие значения «sub-product-id» и «app-package-name»:
https://play.google.com/store/account/subscriptions?sku=sub-product-id&package=app-package-nameСледующие шаги
Эти сценарии взаимодействия пользователей и фрагменты кода представляют собой базовую реализацию, демонстрирующую, как использовать API цифровых товаров и API запросов платежей в вашем PWA для реализации Play Billing. Вам следует использовать API в зависимости от контекста вашего приложения и сценариев его использования. Пример комплексной реализации можно найти в нашем примере с открытым исходным кодом .
Затем ознакомьтесь с тем, как внедрить важные компоненты Play Billing на вашем бэкэнд-сервере , чтобы обеспечить безопасность вашего приложения и его постоянную актуальность в соответствии с правами пользователей.