Обработка событий флоу и пейвола — iOS
Этот гайд охватывает обработку событий для покупок, восстановлений, выбора продукта и рендеринга пейвола. Вам также необходимо реализовать обработку кнопок (закрытие пейвола, открытие ссылок и т. д.). Подробнее — в нашем гайде по обработке действий кнопок.
Флоу и пейволы не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют события, на которые ваше приложение может реагировать. К таким событиям относятся нажатия кнопок (кнопки закрытия, URL, выбор продуктов и т. д.), а также уведомления о действиях, связанных с покупками. Узнайте ниже, как реагировать на эти события.
Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Ознакомьтесь с нашими примерами приложений, которые демонстрируют полную настройку, включая отображение пейволов, совершение покупок и другие базовые функции.
Обработка событий в SwiftUI
Для управления и отслеживания процессов на экране флоу или пейвола в вашем мобильном приложении используйте модификатор .flow в SwiftUI:
@State var flowPresented = false
var body: some View {
Text("Hello, AdaptyUI!")
.flow(
isPresented: $flowPresented,
flowConfiguration: flowConfiguration,
didPerformAction: { action in
switch action {
case .close:
flowPresented = false
case let .openURL(url):
// handle opening the URL (incl. for terms and privacy)
default:
// handle other actions
}
},
didSelectProduct: { product in /* Handle the event */ },
didStartPurchase: { product in /* Handle the event */ },
didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ },
didFailPurchase: { product, error in /* handle the error */ },
didStartRestore: { /* Handle the event */ },
didFinishRestore: { profile in /* check access level and dismiss */ },
didFailRestore: { error in /* handle the error */ },
didReceiveError: { error in
flowPresented = false
},
didFailLoadingProducts: { error in
// Return `true` to retry loading
return false
}
)
}Вы можете регистрировать только те параметры замыкания, которые вам нужны, и опускать те, которые не нужны.
| Параметр | Обязательный | Описание |
|---|---|---|
| isPresented | обязательный | Привязка, управляющая отображением экрана флоу или пейвола. |
| flowConfiguration | обязательный | Объект AdaptyUI.FlowConfiguration, содержащий визуальные данные флоу или пейвола. Подробнее см. в разделе Получение флоу и пейволов. |
| didFinishPurchase | обязательный | Вызывается при успешном завершении Adapty.makePurchase(). Флоу не закрывается автоматически — здесь можно установить привязку презентации в false или ничего не делать, позволив флоу продолжить работу после покупки. |
| didFailPurchase | обязательный | Вызывается при ошибке Adapty.makePurchase(). |
| didFinishRestore | обязательный | Вызывается при успешном завершении Adapty.restorePurchases(). |
| didFailRestore | обязательный | Вызывается при ошибке Adapty.restorePurchases(). |
| didReceiveError | обязательный | Вызывается при возникновении ошибки рендеринга или ошибки времени выполнения в скрипте флоу (например, исключение JavaScript, код AdaptyUIError 4105). В случае ошибки рендеринга обратитесь в поддержку Adapty. |
| placeholderBuilder | необязательный | Функция для отображения плейсхолдера во время загрузки флоу или пейвола. По умолчанию используется ProgressView. |
| fullScreen | необязательный | Определяет, отображается ли флоу или пейвол в полноэкранном режиме или в виде шторки. По умолчанию true. |
| didAppear | необязательный | Вызывается, когда экран флоу или пейвола появляется на экране. |
| didDisappear | необязательный | Вызывается, когда экран флоу или пейвола был закрыт. |
| didPerformAction | необязательный | Вызывается при нажатии пользователем на кнопку. Предопределены два идентификатора действий: close и openURL; остальные — пользовательские и задаются в билдере. |
| didSelectProduct | необязательный | Вызывается, когда пользователь или система выбирает продукт для покупки. |
| didStartPurchase | необязательный | Вызывается, когда пользователь начинает процесс покупки. |
| didFinishWebPaymentNavigation | необязательный | Вызывается при завершении навигации в рамках веб-оплаты. |
| didStartRestore | необязательный | Вызывается, когда пользователь начинает процесс восстановления покупок. |
| didFailLoadingProducts | необязательный | Вызывается при ошибках во время загрузки продуктов. Верните true, чтобы повторить загрузку. |
| didPartiallyLoadProducts | необязательный | Вызывается, когда продукты загружены частично. |
| showAlertItem | необязательный | Привязка, управляющая отображением алертов поверх флоу или пейвола. |
| showAlertBuilder | необязательный | Функция для отображения алерта. |
Обработка событий в UIKit
Для приложений на UIKit события обрабатываются через протокол AdaptyFlowControllerDelegate. Подробнее о настройке AdaptyFlowController с AdaptyFlowControllerDelegate смотрите в разделе Отображение флоу и пейволов — iOS.
Протокол объявляет 13 методов. Четыре из них не имеют реализации по умолчанию и должны быть реализованы при подписке на протокол: didFinishPurchase, didFailPurchase, didFinishRestoreWith и didFailRestoreWith. Остальные имеют реализацию по умолчанию (no-op) и могут быть переопределены при необходимости. Методы сгруппированы ниже по назначению.
Жизненный цикл
func flowControllerDidAppear(_ controller: AdaptyFlowController) { }
func flowControllerDidDisappear(_ controller: AdaptyFlowController) { }Эти методы срабатывают при появлении и закрытии флоу или пейвола.
Действия пользователя
func flowController(
_ controller: AdaptyFlowController,
didPerform action: AdaptyUI.Action
) { }Варианты AdaptyUI.Action:
.close— по умолчанию закрывает контроллер. Переопределите, если нужно оставить контроллер на экране или выполнить дополнительную очистку..openURL(url:)— по умолчанию открывает URL черезUIApplication.shared.open(...)..custom(id:)— срабатывает для кнопок, которым в билдере назначен пользовательский идентификатор действия.
Выбор продукта
func flowController(
_ controller: AdaptyFlowController,
didSelectProduct product: AdaptyPaywallProduct
) { }Вызывается, когда пользователь или система выбирают продукт для покупки. Продукт содержит полную информацию об офере (в v4 совместимость определяется автоматически — отдельного типа AdaptyPaywallProductWithoutDeterminingOffer больше нет).
События покупки
func flowController(
_ controller: AdaptyFlowController,
didStartPurchase product: AdaptyPaywallProduct
) { }
func flowController(
_ controller: AdaptyFlowController,
didFinishPurchase product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
if !purchaseResult.isPurchaseCancelled {
controller.dismiss(animated: true) // or do nothing to let the flow continue
}
}
func flowController(
_ controller: AdaptyFlowController,
didFailPurchase product: AdaptyPaywallProduct,
error: AdaptyError
) { }didFinishPurchase и didFailPurchase не имеют реализаций по умолчанию и должны быть реализованы. Контроллер не закрывается автоматически после успешной покупки — вызовите controller.dismiss(animated:) в нужный момент или оставьте всё как есть, чтобы многоэкранный флоу продолжился после покупки.
События восстановления покупок
func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { }
func flowController(
_ controller: AdaptyFlowController,
didFinishRestoreWith profile: AdaptyProfile
) { }
func flowController(
_ controller: AdaptyFlowController,
didFailRestoreWith error: AdaptyError
) { }didFinishRestoreWith и didFailRestoreWith не имеют реализаций по умолчанию. Перед закрытием контроллера убедитесь, что возвращённый AdaptyProfile содержит нужный уровень доступа.
Ошибки флоу и ошибки загрузки продуктов
func flowController(
_ controller: AdaptyFlowController,
didReceiveError error: AdaptyUIError
) { }
func flowController(
_ controller: AdaptyFlowController,
didFailLoadingProductsWith error: AdaptyError
) -> Bool {
// Return `true` to retry product loading; default returns `false`.
return false
}
func flowController(
_ controller: AdaptyFlowController,
didPartiallyLoadProducts failedIds: [String]
) { }didReceiveError срабатывает при ошибках рендеринга и при ошибках выполнения из скрипта флоу (исключения JavaScript, AdaptyUIError код 4105). При ошибках рендеринга обратитесь в поддержку Adapty. При ошибках загрузки верните true из didFailLoadingProductsWith, чтобы повторить попытку — это удобно при временных сбоях сети.
Навигация при веб-оплате
func flowController(
_ controller: AdaptyFlowController,
didFinishWebPaymentNavigation product: AdaptyPaywallProduct?,
error: AdaptyError?
) { }Вызывается после завершения навигации при веб-оплате — успешного или нет.
Аналитические события
func flowController(
_ controller: AdaptyFlowController,
didReceiveAnalyticEvent name: String,
params: [String: any Sendable]
) { }Флоу отправляет событие flow_screen_showed каждый раз, когда пользователь открывает один из его экранов. Adapty учитывает эти события в собственной аналитике флоу и также передаёт их в ваше приложение, чтобы вы могли построить такую же воронку в своей аналитике.
| Параметр | Описание |
|---|---|
instanceId | Идентификатор экрана, который открыл пользователь. |
screen_order | Порядковый номер экрана во флоу. |
is_last_screen | true, если у экрана нет следующего шага. Флоу с ветвлением может завершаться на нескольких разных экранах — каждый из них возвращает true. |
Оба поля isBackendEvent и isCustomerEvent равны true для этого события: Adapty продолжает его учитывать, и ваше приложение тоже его получает.
Смотрите Отслеживание просмотров экранов флоу, чтобы узнать, как с ними работать.
Флоу также передаёт значения, которые пользователи вводят и выбирают. Смотрите Обработка данных из флоу, чтобы их считать.
Этот гайд охватывает обработку событий для покупок, восстановлений, выбора продукта и отрисовки пейвола. Вам также необходимо реализовать обработку кнопок (закрытие пейвола, открытие ссылок и т. д.). Подробнее см. в гайде по обработке действий кнопок.
Пейволы, настроенные с помощью Paywall Builder, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют ряд событий, на которые ваше приложение может реагировать. Среди этих событий — нажатия кнопок (кнопки закрытия, URL, выбор продуктов и т. д.), а также уведомления о действиях, связанных с покупками на пейволе. Ниже описано, как реагировать на эти события.
Этот гайд охватывает только пейволы, созданные в старом билдере, для работы с которыми требуется Adapty SDK версии 3.0 или выше.
Хотите посмотреть на реальный пример интеграции Adapty SDK в мобильное приложение? Ознакомьтесь с нашими демо-приложениями — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции.
Обработка событий в SwiftUI
Для управления и отслеживания процессов на экране пейвола в вашем мобильном приложении используйте модификатор .paywall в SwiftUI:
@State var paywallPresented = false
var body: some View {
Text("Hello, AdaptyUI!")
.paywall(
isPresented: $paywallPresented,
paywall: paywall,
viewConfiguration: viewConfig,
didPerformAction: { action in
switch action {
case .close:
paywallPresented = false
case let .openURL(url):
// handle opening the URL (incl. for terms and privacy)
default:
// handle other actions
}
},
didSelectProduct: { /* Handle the event */ },
didStartPurchase: { /* Handle the event */ },
didFinishPurchase: { product, info in /* Handle the event */ },
didFailPurchase: { product, error in /* Handle the event */ },
didStartRestore: { /* Handle the event */ },
didFinishRestore: { /* Handle the event */ },
didFailRestore: { /* Handle the event */ },
didFailRendering: { error in
paywallPresented = false
},
didFailLoadingProducts: { error in
return false
}
)
}Вы можете регистрировать только те параметры замыкания, которые вам нужны, и опускать те, которые не нужны. В этом случае неиспользуемые параметры замыкания не будут созданы.
| Параметр | Обязательный | Описание |
|---|---|---|
| isPresented | обязательный | Биндинг, управляющий отображением экрана пейвола. |
| paywallConfiguration | обязательный | Объект AdaptyUI.PaywallConfiguration, содержащий визуальные настройки пейвола. Используйте метод AdaptyUI.paywallConfiguration(for:products:viewConfiguration:observerModeResolver:tagResolver:timerResolver:). Подробнее см. в разделе Получение пейволов Paywall Builder и их конфигурации. |
| didFailPurchase | обязательный | Вызывается при ошибке покупки (например, платёж не разрешён, проблемы с сетью, неверный продукт). Не вызывается при отмене пользователем или ожидающих платежах. |
| didFinishRestore | обязательный | Вызывается при успешном завершении покупки. |
| didFailRestore | обязательный | Вызывается при ошибке восстановления покупки. |
| didFailRendering | обязательный | Вызывается при ошибке рендеринга интерфейса. В этом случае обратитесь в поддержку Adapty. |
| fullScreen | необязательный | Определяет, отображается ли пейвол в полноэкранном режиме или как модальное окно. По умолчанию true. |
| didAppear | необязательный | Вызывается, когда экран пейвола появляется на экране. Также вызывается, когда пользователь нажимает кнопку веб-пейвола внутри пейвола и веб-пейвол открывается во встроенном браузере. |
| didDisappear | необязательный | Вызывается, когда экран пейвола закрывается. Также вызывается, когда веб-пейвол, открытый из пейвола во встроенном браузере, исчезает с экрана. |
| didPerformAction | необязательный | Вызывается при нажатии пользователем кнопки. У разных кнопок разные идентификаторы действий. Два идентификатора заданы заранее: close и openURL, остальные — пользовательские и задаются в билдере. |
| didSelectProduct | необязательный | Вызывается, если продукт выбран для покупки — пользователем или системой. |
| didStartPurchase | необязательный | Вызывается, когда пользователь начинает процесс покупки. |
| didFinishPurchase | необязательный | Вызывается при успешном завершении покупки. |
| didFinishWebPaymentNavigation | необязательный | Вызывается после попытки открыть веб-пейвол для покупки — успешной или нет. |
| didStartRestore | необязательный | Вызывается, когда пользователь начинает процесс восстановления покупок. |
| didFailLoadingProducts | необязательный | Вызывается при ошибках загрузки продуктов. Верните true, чтобы повторить загрузку. |
| didPartiallyLoadProducts | необязательный | Вызывается, когда продукты загружены частично. |
| showAlertItem | необязательный | Биндинг, управляющий отображением элементов алерта поверх пейвола. |
| showAlertBuilder | необязательный | Функция для рендеринга представления алерта. |
| placeholderBuilder | необязательный | Функция для рендеринга заглушки во время загрузки пейвола. |
Обработка событий в UIKit
Для управления процессами, происходящими на экране пейвола в вашем мобильном приложении, или их отслеживания реализуйте методы AdaptyPaywallControllerDelegate.
События, генерируемые пользователем
Выбор продукта
Если пользователь выбирает продукт для покупки, будет вызван следующий метод:
func paywallController(
_ controller: AdaptyPaywallController,
didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer
) { }Пример события (нажмите, чтобы раскрыть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
} Покупка начата
Если пользователь инициирует процесс покупки, будет вызван этот метод:
func paywallController(_ controller: AdaptyPaywallController,
didStartPurchase product: AdaptyPaywallProduct) {
}Пример события (нажмите, чтобы развернуть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
} Не вызывается в режиме Observer. Подробнее см. в разделе iOS — отображение пейволов Paywall Builder в режиме Observer.
Покупка через веб-пейвол
Если пользователь инициирует процесс покупки через веб-пейвол, будет вызван этот метод:
func paywallController(
_ controller: AdaptyPaywallController,
shouldContinueWebPaymentNavigation product: AdaptyPaywallProduct
) {
}Пример события (нажмите, чтобы развернуть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
} Успешная или отменённая покупка
Если покупка прошла успешно, будет вызван следующий метод:
func paywallController(
_ controller: AdaptyPaywallController,
didFinishPurchase product: AdaptyPaywallProductWithoutDeterminingOffer,
purchaseResult: AdaptyPurchaseResult
) { }
}Примеры событий (нажмите, чтобы развернуть)
// 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": "cancelled"
}
} В этом случае рекомендуем закрыть экран пейвола.
В режиме Observer mode этот метод не вызывается. Подробнее см. в разделе iOS — Показ пейволов Paywall Builder в режиме Observer mode.
Неудачная покупка
Если покупка завершается с ошибкой, вызывается этот метод. Сюда входят ошибки StoreKit (ограничения платежей, неверные продукты, сетевые сбои), сбои верификации транзакций и системные ошибки. Обратите внимание: отмена пользователем вызывает didFinishPurchase с результатом «отменено», а ожидающие платежи этот метод не вызывают.
func paywallController(
_ controller: AdaptyPaywallController,
didFailPurchase product: AdaptyPaywallProduct,
error: AdaptyError
) { }Пример события (нажмите, чтобы развернуть)
{
"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"
}
}
} Не вызывается в режиме Observer mode. Подробнее см. в разделе iOS — Отображение пейволов Paywall Builder в режиме Observer mode.
Ошибка покупки через веб-пейвол
Если Adapty.openWebPaywall() завершается с ошибкой, будет вызван этот метод:
func paywallController(
_ controller: AdaptyPaywallController,
didFailWebPaymentNavigation product: AdaptyPaywallProduct,
error: AdaptyError
) { }Пример события (нажмите, чтобы развернуть)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "web_payment_failed",
"message": "Web payment navigation failed",
"details": {
"underlyingError": "Network connection error"
}
}
} Успешное восстановление покупки
Если восстановление покупки прошло успешно, будет вызван этот метод:
func paywallController(
_ controller: AdaptyPaywallController,
didFinishRestoreWith profile: AdaptyProfile
) { }Пример события (нажмите, чтобы развернуть)
{
"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 func paywallController(
_ controller: AdaptyPaywallController,
didFailRestoreWith error: AdaptyError
) { }Пример события (нажмите, чтобы развернуть)
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
} Загрузка данных и рендеринг
Ошибки загрузки продуктов
Если вы не передаёте массив продуктов при инициализации, AdaptyUI самостоятельно получит нужные объекты с сервера. Если эта операция завершится ошибкой, AdaptyUI сообщит об этом через следующий метод:
public func paywallController(
_ controller: AdaptyPaywallController,
didFailLoadingProductsWith error: AdaptyError
) -> Bool {
return true
}Пример события (нажмите, чтобы развернуть)
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
} Если вы вернёте true, AdaptyUI повторит запрос через 2 секунды.
Ошибки рендеринга
Если во время рендеринга интерфейса возникает ошибка, она будет передана через этот метод:
public func paywallController(
_ controller: AdaptyPaywallController,
didFailRenderingWith error: AdaptyError
) { }Пример события (нажмите, чтобы развернуть)
{
"error": {
"code": "rendering_failed",
"message": "Failed to render paywall interface",
"details": {
"underlyingError": "Invalid paywall configuration"
}
}
} В обычной ситуации такие ошибки возникать не должны, поэтому если вы столкнулись с одной из них, пожалуйста, сообщите нам.