Обработка событий флоу и пейвола — Unity
Этот гайд описывает обработку событий для покупок, восстановлений, выбора продуктов и отображения флоу. Также необходимо реализовать обработку кнопок (закрытие флоу, открытие ссылок и т. д.). Подробности — в гайде по обработке действий флоу.
Флоу и пейволы, настроенные в Flow & Paywall Builder, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют события, на которые ваше приложение может реагировать. Среди них — нажатия кнопок (кнопки закрытия, URL, выбор продуктов и т. д.), а также уведомления о действиях, связанных с покупками. Ниже описано, как обрабатывать эти события.
Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши примеры приложений, которые демонстрируют полную настройку, включая отображение пейволов, совершение покупок и другую базовую функциональность.
Обработка событий
Чтобы контролировать или отслеживать процессы, происходящие на экране флоу в вашем мобильном приложении, реализуйте интерфейс IAdaptyFlowsEventsListener и зарегистрируйте его с помощью Adapty.SetFlowsEventsListener():
using UnityEngine;
using AdaptySDK;
public class FlowEventsHandler : MonoBehaviour, IAdaptyFlowsEventsListener
{
void Start()
{
Adapty.SetFlowsEventsListener(this);
}
// Implement all interface methods below
}Здесь вы добавляете свою логику реагирования на события флоу. SDK не применяет к ним никакого поведения по умолчанию: успешная покупка или ошибка не скрывают экран автоматически — вызовите view.Dismiss(...) самостоятельно в нужный момент.
Пользовательские события
Флоу появился
Вызывается, когда представление флоу отображается на экране.
На iOS также вызывается, когда пользователь нажимает кнопку веб-пейвола внутри флоу и веб-пейвол открывается во встроенном браузере.
public void FlowViewDidAppear(AdaptyUIFlowView view) { }Флоу исчез
Вызывается, когда представление флоу убирается с экрана.
На iOS также вызывается, когда веб-пейвол, открытый из флоу во встроенном браузере, исчезает с экрана.
public void FlowViewDidDisappear(AdaptyUIFlowView view) { }Выбор продукта
Вызывается при выборе продукта для покупки (пользователем или системой).
public void FlowViewDidSelectProduct(
AdaptyUIFlowView view,
string productId
) { }Пример события (нажмите, чтобы раскрыть)
{
"productId": "premium_monthly"
} Начало покупки
Вызывается, когда пользователь инициирует процесс покупки.
public void FlowViewDidStartPurchase(
AdaptyUIFlowView view,
AdaptyPaywallProduct product
) { }В режиме Observer, покупки, начатые из флоу, передаются в ваш IAdaptyUIObserverModeResolver.
Пример события (нажмите, чтобы развернуть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
} Успешная, отменённая или отложенная покупка
Этот метод вызывается, если покупка прошла успешно, пользователь её отменил или покупка находится в статусе ожидания. Отмены пользователем и отложенные платежи (например, когда требуется разрешение родителей) вызывают этот метод, а не FlowViewDidFailPurchase.
Флоу остаётся открытым после покупки, пока вы его не закроете — вызовите view.Dismiss(...) самостоятельно, как только пользователь получит доступ:
public void FlowViewDidFinishPurchase(
AdaptyUIFlowView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchasedResult
) {
switch (purchasedResult.Type) {
case AdaptyPurchaseResultType.Success:
// Check if user has access to premium features
if (purchasedResult.Profile != null
&& purchasedResult.Profile.AccessLevels.TryGetValue("premium", out var premium)
&& premium.IsActive) {
view.Dismiss(null);
}
break;
case AdaptyPurchaseResultType.Pending:
// Handle pending purchase (e.g., user will pay offline with cash)
break;
case AdaptyPurchaseResultType.UserCancelled:
// Handle user cancellation
break;
default:
break;
}
}Примеры событий (нажмите, чтобы развернуть)
// Successful purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Success",
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
}
}
}
}
// Cancelled purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "UserCancelled"
}
}
// Pending purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Pending"
}
} Мы рекомендуем закрывать экран флоу при успешной покупке.
Ошибка при покупке
Этот метод вызывается, если покупка завершилась с ошибкой. Сюда входят ошибки StoreKit/Google Play Billing (ограничения платежей, недействительные продукты, сбои сети), ошибки проверки транзакций и системные ошибки. Обратите внимание, что отмена покупки пользователем вызывает FlowViewDidFinishPurchase с результатом отмены, а ожидающие платежи этот метод не вызывают.
public void FlowViewDidFailPurchase(
AdaptyUIFlowView view,
AdaptyPaywallProduct product,
AdaptyError error
) { }Пример события (нажмите, чтобы развернуть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
}
} Восстановление начато
Вызывается, когда пользователь инициирует процесс восстановления покупок:
public void FlowViewDidStartRestore(AdaptyUIFlowView view) { }Успешное восстановление
Вызывается при успешном восстановлении покупок. Флоу остаётся открытым после восстановления, пока вы его не закроете:
public void FlowViewDidFinishRestore(
AdaptyUIFlowView view,
AdaptyProfile profile
) {
// Check if user has access to premium features
if (profile.AccessLevels.TryGetValue("premium", out var premium) && premium.IsActive) {
view.Dismiss(null);
}
}Пример события (нажмите, чтобы развернуть)
{
"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. Обратитесь к разделу Статус подписки, чтобы узнать, как его проверить.
Ошибка восстановления
Вызывается при сбое восстановления покупок:
public void FlowViewDidFailRestore(
AdaptyUIFlowView view,
AdaptyError error
) { }Пример события (нажмите, чтобы развернуть)
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
} Завершение навигации веб-платежа
После попытки открыть веб-пейвол для покупки (успешной или нет) будет вызван этот метод:
public void FlowViewDidFinishWebPaymentNavigation(
AdaptyUIFlowView view,
AdaptyPaywallProduct product,
AdaptyError error
) { }Параметры:
product: Продукт, для которого был открыт (или предпринята попытка открытия) веб-пейвол, либоnullerror:null, если веб-пейвол успешно открылся, илиAdaptyErrorв случае ошибки
Примеры событий (нажмите, чтобы развернуть)
// 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": null,
"error": {
"code": "wrong_param",
"message": "Current method is not available for this product",
"details": {
"underlyingError": "Product not configured for web purchases"
}
}
} Загрузка данных и отрисовка
Ошибки загрузки продуктов
Вызывается при ошибке загрузки продуктов и предоставляет AdaptyError. Если при инициализации массив продуктов не был передан, AdaptyUI самостоятельно получит необходимые объекты с сервера. Эта операция может завершиться с ошибкой, о которой AdaptyUI сообщит, вызвав этот метод:
public void FlowViewDidFailLoadingProducts(
AdaptyUIFlowView view,
AdaptyError error
) { }Пример события (нажмите, чтобы развернуть)
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
} Ошибки рендеринга и выполнения
Если при рендеринге интерфейса возникает ошибка или происходит другая ошибка выполнения, не связанная с покупкой, она будет передана этим методом. Представление не закрывается автоматически — вызовите view.Dismiss(...) самостоятельно, если это необходимо:
public void FlowViewDidReceiveError(
AdaptyUIFlowView view,
AdaptyError error
) { }Пример события (нажмите, чтобы раскрыть)
{
"error": {
"code": "rendering_failed",
"message": "Failed to render flow interface",
"details": {
"underlyingError": "Invalid flow configuration"
}
}
} В штатной ситуации такие ошибки возникать не должны, поэтому если вы с ними столкнулись — пожалуйста, сообщите нам.
Аналитические события
public void FlowViewDidReceiveAnalyticEvent(
AdaptyUIFlowView view,
string name,
IDictionary<string, object> @params
) { }Флоу отправляет событие flow_screen_showed каждый раз, когда пользователь открывает один из его экранов. Adapty учитывает эти события в собственной аналитике флоу и также передаёт их в ваше приложение, чтобы вы могли построить такую же воронку в своей аналитике.
| Параметр | Описание |
|---|---|
instanceId | Идентификатор экрана, который открыл пользователь. |
screen_order | Порядковый номер экрана во флоу. |
is_last_screen | true, если у экрана нет следующего шага. Флоу с ветвлением может завершаться на нескольких разных экранах — каждый из них возвращает true. |
Оба поля isBackendEvent и isCustomerEvent равны true для этого события: Adapty продолжает его учитывать, и ваше приложение тоже его получает.
Подробнее о том, что делать с этими событиями, — в разделе Отслеживание просмотров экранов флоу.
Флоу также сообщает о значениях, которые пользователи вводят и выбирают. Подробнее — в разделе Обработка данных из флоу.
Обработка системных запросов
IAdaptyUISystemRequestsHandler (регистрируется через Adapty.SetSystemRequestsHandler(...)) предназначен для обработки системных запросов из флоу: запросов разрешений ОС (например, на push-уведомления или доступ к камере) и запросов на оценку приложения. Флоу пока не инициируют такие запросы, поэтому регистрировать обработчик не нужно.
Навигация
Системная кнопка «Назад» в Android
Системная кнопка «Назад» (или жест «Назад») в Android передаётся в FlowViewDidPerformAction как действие SystemBack и сама по себе не закрывает флоу — пользователь покидает флоу через путь, который вы определяете, например через кнопку Close или действие on_device_back в билдере. Если вы хотите, чтобы системная кнопка «Назад» закрывала флоу, обрабатывайте это действие самостоятельно:
public void FlowViewDidPerformAction(
AdaptyUIFlowView view,
AdaptyUIUserAction action
) {
switch (action.Type) {
case AdaptyUIUserActionType.Close:
case AdaptyUIUserActionType.SystemBack:
view.Dismiss(null);
break;
default:
// handle other events
break;
}
}Смотрите гайд по обработке действий флоу для полного списка действий.
Этот гайд описывает обработку событий для покупок, восстановлений, выбора продукта и отображения пейвола. Также необходимо реализовать обработку кнопок (закрытие пейвола, открытие ссылок и т. д.). Подробнее см. в гайде по обработке действий кнопок.
Пейволы, настроенные с помощью Paywall Builder, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют события, на которые ваше приложение может реагировать. Среди них — нажатия кнопок (кнопки закрытия, URL, выбор продукта и т. д.), а также уведомления о действиях, связанных с покупками на пейволе. Ниже описано, как обрабатывать эти события.
Этот гайд охватывает только пейволы, созданные в старом билдере, для которых требуется Adapty SDK версии 3.3.0 или выше.
Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши примеры приложений, которые демонстрируют полную настройку, включая отображение пейволов, совершение покупок и другую базовую функциональность.
Обработка событий
Чтобы контролировать или отслеживать процессы, происходящие на экране пейвола в вашем мобильном приложении, реализуйте интерфейс AdaptyPaywallsEventsListener:
using UnityEngine;
using AdaptySDK;
public class PaywallEventsHandler : MonoBehaviour, AdaptyPaywallsEventsListener
{
void Start()
{
Adapty.SetPaywallsEventsListener(this);
}
// Implement all required interface methods below
}События, инициируемые пользователем
Пейвол появился
Вызывается, когда экран пейвола отображается на экране.
На iOS также вызывается, когда пользователь нажимает кнопку веб-пейвола внутри пейвола и веб-пейвол открывается во встроенном браузере.
public void PaywallViewDidAppear(AdaptyUIPaywallView view) { }Пейвол исчез
Вызывается, когда экран пейвола закрывается.
На iOS также вызывается, когда веб-пейвол, открытый из пейвола во встроенном браузере, исчезает с экрана.
public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { }Выбор продукта
Вызывается, когда продукт выбран для покупки (пользователем или системой).
public void PaywallViewDidSelectProduct(
AdaptyUIPaywallView view,
string productId
) { }Пример события (нажмите, чтобы развернуть)
{
"productId": "premium_monthly"
} Покупка начата
Вызывается, когда пользователь инициирует процесс покупки.
public void PaywallViewDidStartPurchase(
AdaptyUIPaywallView view,
AdaptyPaywallProduct product
) { }Пример события (нажмите, чтобы развернуть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
} Успешная, отменённая или ожидающая покупка
Этот метод вызывается, если покупка прошла успешно, пользователь отменил покупку или покупка находится в состоянии ожидания. Отмены пользователем и ожидающие платежи (например, требующие родительского одобрения) вызывают этот метод, а не PaywallViewDidFailPurchase.
public void PaywallViewDidFinishPurchase(
AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchasedResult
) { }Примеры событий (нажмите, чтобы развернуть)
// Successful purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Success",
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
}
}
}
}
// Cancelled purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "UserCancelled"
}
}
// Pending purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Pending"
}
} В таких случаях рекомендуем закрывать экран.
Покупка завершилась с ошибкой
Если покупка завершается с ошибкой, вызывается этот метод. Сюда входят ошибки StoreKit/Google Play Billing (ограничения платежей, недействительные продукты, сбои сети), ошибки проверки транзакций и системные ошибки. Обратите внимание: отмены пользователем вызывают PaywallViewDidFinishPurchase с результатом отмены, а ожидающие платежи этот метод не вызывают.
public void PaywallViewDidFailPurchase(
AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyError error
) { }Пример события (нажмите, чтобы развернуть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
}
} Восстановление начато
Вызывается, когда пользователь инициирует процесс восстановления покупок:
public void PaywallViewDidStartRestore(AdaptyUIPaywallView view) { }Восстановление выполнено успешно
Вызывается при успешном восстановлении покупок:
public void PaywallViewDidFinishRestore(
AdaptyUIPaywallView view,
AdaptyProfile profile
) { }Пример события (нажмите, чтобы развернуть)
{
"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. Подробнее о том, как это проверить, см. в разделе Статус подписки.
Восстановление завершилось с ошибкой
Вызывается при ошибке восстановления покупок:
public void PaywallViewDidFailRestore(
AdaptyUIPaywallView view,
AdaptyError error
) { }Пример события (нажмите, чтобы развернуть)
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
} Завершена навигация к веб-оплате
После попытки открыть веб-пейвол для покупки (успешной или неудачной) будет вызван этот метод:
public void PaywallViewDidFinishWebPaymentNavigation(
AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyError error
) { }Параметры:
product: продукт, для которого был открыт (или предпринята попытка открыть) веб-пейволerror:null, если веб-пейвол успешно открылся, илиAdaptyErrorпри ошибке
Примеры событий (нажмите, чтобы развернуть)
// 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": "wrong_param",
"message": "Current method is not available for this product",
"details": {
"underlyingError": "Product not configured for web purchases"
}
}
} Получение данных и рендеринг
Ошибки загрузки продуктов
Вызывается при сбое загрузки продуктов и передаёт AdaptyError. Если при инициализации вы не передали массив продуктов, AdaptyUI самостоятельно получит необходимые объекты с сервера. Эта операция может завершиться с ошибкой — в таком случае AdaptyUI сообщит о ней, вызвав данный метод:
public void PaywallViewDidFailLoadingProducts(
AdaptyUIPaywallView view,
AdaptyError error
) { }Пример события (нажмите, чтобы развернуть)
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
} Ошибки отрисовки
Вызывается при возникновении ошибки в процессе отрисовки интерфейса и предоставляет AdaptyError:
public void PaywallViewDidFailRendering(
AdaptyUIPaywallView view,
AdaptyError error
) { }Пример события (нажмите, чтобы развернуть)
{
"error": {
"code": "rendering_failed",
"message": "Failed to render paywall interface",
"details": {
"underlyingError": "Invalid paywall configuration"
}
}
} В штатной ситуации такие ошибки возникать не должны, поэтому если вы с ними столкнулись — пожалуйста, сообщите нам.