Обработка событий флоу и пейвола - Unity
Этот гайд описывает обработку событий для покупок, восстановлений, выбора продуктов и отображения флоу. Также необходимо реализовать обработку кнопок (закрытие флоу, открытие ссылок и т. д.). Подробности — в гайде по обработке действий флоу.
Флоу и пейволы, настроенные с помощью Flow Builder или 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"
}
}
}В штатной ситуации такие ошибки возникать не должны, поэтому если вы с ними столкнулись — пожалуйста, сообщите нам.
Аналитические события
FlowViewDidReceiveAnalyticEvent зарезервирован для пользовательских аналитических событий из флоу. Флоу пока не отправляют их в ваш код, поэтому оставьте тело метода пустым — IAdaptyFlowsEventsListener является C# интерфейсом, поэтому метод всё равно должен присутствовать:
public void FlowViewDidReceiveAnalyticEvent(
AdaptyUIFlowView view,
string name,
IDictionary<string, object> @params
) { }Обработка системных запросов
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, выбор продуктов и т.д.), а также уведомления о действиях, связанных с покупками, на пейволе. Ниже описано, как реагировать на эти события.
Этот гайд предназначен только для пейволов нового Paywall Builder, для которых требуется Adapty SDK v3.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"
}
}
}В штатной ситуации такие ошибки возникать не должны, поэтому если вы с ними столкнулись — пожалуйста, сообщите нам.