Android - Обработка событий пейвола
Этот гайд посвящён обработке событий покупок, восстановлений, выбора продуктов и отрисовки пейвола. Вам также нужно реализовать обработку кнопок (закрытие пейвола, открытие ссылок и т. д.). Подробнее см. в гайде по обработке действий с кнопками.
Пейволы, созданные в Paywall Builder, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют события, на которые ваше приложение может реагировать. Среди них — нажатия кнопок (кнопки закрытия, URL, выбор продуктов и т. п.), а также уведомления о действиях, связанных с покупками. Ниже описано, как реагировать на эти события.
Этот гайд предназначен только для пейволов нового Paywall Builder, которые требуют Adapty SDK v3.0 или новее.
Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши примеры приложений — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции.
Если вам нужно контролировать или отслеживать процессы на экране покупки, реализуйте методы AdaptyUiEventListener.
Если в некоторых случаях вас устраивает поведение по умолчанию, вы можете унаследоваться от AdaptyUiDefaultEventListener и переопределить только те методы, которые хотите изменить.
Ниже приведены значения по умолчанию из AdaptyUiDefaultEventListener.
События, инициированные пользователем
Выбор продукта
Этот метод вызывается, когда продукт выбран для покупки — пользователем или системой:
public override fun onProductSelected(
product: AdaptyPaywallProduct,
context: Context,
) {}
Пример события (нажмите, чтобы раскрыть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}Начало покупки
Этот метод вызывается, когда пользователь инициирует процесс покупки:
public override fun onPurchaseStarted(
product: AdaptyPaywallProduct,
context: Context,
) {}
Пример события (нажмите, чтобы раскрыть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}Метод не вызывается в режиме Observer. Подробнее см. в разделе Android — отображение пейволов Paywall Builder в режиме Observer.
Успешная, отменённая или ожидающая покупка
Этот метод вызывается при успешном завершении покупки:
public override fun onPurchaseFinished(
purchaseResult: AdaptyPurchaseResult,
product: AdaptyPaywallProduct,
context: Context,
) {
if (purchaseResult !is AdaptyPurchaseResult.UserCanceled)
context.getActivityOrNull()?.onBackPressed()
}
Примеры событий (нажмите, чтобы раскрыть)
// Successful purchase
{
"purchaseResult": {
"type": "Success",
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
}
}
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
// Cancelled purchase
{
"purchaseResult": {
"type": "UserCanceled"
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
// Pending purchase
{
"purchaseResult": {
"type": "Pending"
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}В этом случае рекомендуем закрыть экран.
Метод не вызывается в режиме Observer. Подробнее см. в разделе Android — отображение пейволов Paywall Builder в режиме Observer.
Неуспешная покупка
Этот метод вызывается, если покупка завершилась ошибкой. Это включает ошибки Google Play Billing (ограничения оплаты, недействительные продукты, сбои сети), ошибки верификации транзакции и системные ошибки. Обратите внимание: отмена пользователем вызывает onPurchaseFinished с результатом отмены, а ожидающие платежи этот метод не вызывают.
public override fun onPurchaseFailure(
error: AdaptyError,
product: AdaptyPaywallProduct,
context: Context,
) {}
Пример события (нажмите, чтобы раскрыть)
{
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}Метод не вызывается в режиме Observer. Подробнее см. в разделе Android — отображение пейволов Paywall Builder в режиме Observer.
Завершение навигации к веб-оплате
Этот метод вызывается после попытки открыть веб-пейвол для определённого продукта. Вызывается как при успешной, так и при неудачной навигации:
public override fun onFinishWebPaymentNavigation(
product: AdaptyPaywallProduct?,
error: AdaptyError?,
context: Context,
) {}
Параметры:
| Параметр | Описание |
|---|---|
| product | AdaptyPaywallProduct, для которого был открыт веб-пейвол. Может быть null. |
| error | Объект AdaptyError, если навигация к веб-пейволу завершилась ошибкой; null, если навигация прошла успешно. |
Примеры событий (нажмите, чтобы раскрыть)
// Successful navigation
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": null
}
// Failed navigation
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "web_navigation_failed",
"message": "Failed to open web paywall",
"details": {
"underlyingError": "Browser unavailable"
}
}
}Успешное восстановление
Этот метод вызывается при успешном восстановлении покупки:
public override fun onRestoreSuccess(
profile: AdaptyProfile,
context: Context,
) {}
Пример события (нажмите, чтобы раскрыть)
{
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
},
"subscriptions": [
{
"vendorProductId": "premium_monthly",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
]
}
}Рекомендуем закрывать экран, если у пользователя есть нужный accessLevel. Как это проверить, описано в разделе Статус подписки.
Неуспешное восстановление
Этот метод вызывается, если Adapty.restorePurchases() завершается ошибкой:
public override fun onRestoreFailure(
error: AdaptyError,
context: Context,
) {}
Пример события (нажмите, чтобы раскрыть)
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
}Обновление подписки
Пример события (нажмите, чтобы раскрыть)
{
"product": {
"vendorProductId": "premium_yearly",
"localizedTitle": "Premium Yearly",
"localizedDescription": "Premium subscription for 1 year",
"localizedPrice": "$99.99",
"price": 99.99,
"currencyCode": "USD"
},
"subscriptionUpdateParams": {
"replacementMode": "with_time_proration"
}
}Загрузка данных и отрисовка
Ошибки загрузки продуктов
Если вы не передаёте продукты при инициализации, AdaptyUI самостоятельно запрашивает нужные объекты с сервера. Если эта операция завершается ошибкой, AdaptyUI сообщает о ней, вызывая этот метод:
public override fun onLoadingProductsFailure(
error: AdaptyError,
context: Context,
): Boolean = false
Пример события (нажмите, чтобы раскрыть)
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
}Если вернуть true, AdaptyUI повторит запрос через 2 секунды.
Ошибки отрисовки
Если в процессе отрисовки интерфейса возникает ошибка, она передаётся через этот метод:
public override fun onRenderingError(
error: AdaptyError,
context: Context,
) {}
Пример события (нажмите, чтобы раскрыть)
{
"error": {
"code": "rendering_failed",
"message": "Failed to render paywall interface",
"details": {
"underlyingError": "Invalid paywall configuration"
}
}
}В штатной ситуации такие ошибки возникать не должны — если вы всё же столкнулись с подобным, пожалуйста, сообщите нам.