Flutter - Обработка событий флоу и пейвола
Это руководство охватывает обработку событий покупок, восстановлений, выбора продукта и рендеринга. Закрытие экрана и открытие ссылок обрабатываются реализацией flowViewDidPerformAction по умолчанию — см. наш гайд по обработке действий кнопок, чтобы переопределить их или обработать пользовательские действия кнопок.
Флоу и пейволы, настроенные с помощью билдера, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют события, на которые ваше приложение может реагировать. К таким событиям относятся нажатия кнопок (кнопки закрытия, URL, выбор продуктов и т. д.), а также уведомления о действиях, связанных с покупками, выполненных во флоу или пейволе. Ниже описано, как обрабатывать эти события.
Чтобы управлять процессами, происходящими на экране флоу или пейвола в вашем мобильном приложении, или отслеживать их, реализуйте методы AdaptyUIFlowsEventsObserver и установите наблюдатель перед отображением любого экрана:
AdaptyUI().setFlowsEventsObserver(this);Три метода наблюдателя обязательны — без них класс не скомпилируется: flowViewDidFinishPurchase, flowViewDidFinishRestore и flowViewDidReceiveError. Остальные методы опциональны. Чтобы отвязать ранее установленный наблюдатель, передайте null в setFlowsEventsObserver.
Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши примеры приложений — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции.
В примерах событий ниже показаны свойства, доступные для каждого объекта, с поясняющими значениями в комментариях.
События, генерируемые пользователем
Отображение вью
Этот метод вызывается, когда флоу или вью пейвола появляется на экране.
На iOS также вызывается, когда пользователь нажимает кнопку веб-пейвола внутри пейвола и веб-пейвол открывается во встроенном браузере.
void flowViewDidAppear(AdaptyUIFlowView view) {
}Скрытие вью
Этот метод вызывается, когда флоу или вью пейвола убирается с экрана.
На iOS также вызывается, когда веб-пейвол, открытый из пейвола во встроенном браузере, исчезает с экрана.
void flowViewDidDisappear(AdaptyUIFlowView view) {
}Выбор продукта
Если продукт выбран для покупки (пользователем или системой), будет вызван следующий метод:
void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) {
}Пример события (нажмите, чтобы развернуть)
void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) {
// productId is a String:
productId; // 'premium_monthly'
}Начало покупки
Если пользователь инициирует процесс покупки, будет вызван этот метод:
void flowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) {
}Пример события (нажмите, чтобы развернуть)
void flowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
product.localizedTitle; // 'Premium Monthly'
product.localizedDescription; // 'Premium subscription for 1 month'
product.price.amount; // 9.99 (double)
product.price.currencyCode; // 'USD'
product.price.localizedString; // '$9.99'
}Завершённая покупка
Этот метод обязателен. Он вызывается при успешной покупке, отмене покупки пользователем или если покупка находится в состоянии ожидания:
void flowViewDidFinishPurchase(AdaptyUIFlowView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchaseResult) {
switch (purchaseResult) {
case AdaptyPurchaseResultSuccess(profile: final profile):
// successful purchase
break;
case AdaptyPurchaseResultPending():
// purchase is pending
break;
case AdaptyPurchaseResultUserCancelled():
// user cancelled the purchase
break;
default:
break;
}
}Примеры событий (нажмите, чтобы развернуть)
void flowViewDidFinishPurchase(AdaptyUIFlowView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchaseResult) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
switch (purchaseResult) {
case AdaptyPurchaseResultSuccess(profile: final profile):
// profile — AdaptyProfile:
profile.accessLevels['premium']?.isActive; // true
profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
break;
case AdaptyPurchaseResultPending():
// no additional data
break;
case AdaptyPurchaseResultUserCancelled():
// no additional data
break;
}
}В отличие от v3, у этого метода нет поведения по умолчанию — экран больше не закрывается автоматически после успешной покупки. Решите самостоятельно, что происходит дальше: продолжить флоу или вызвать view.dismiss(). Подробнее об управлении закрытием экрана — в разделе Реагирование на действия кнопок.
Завершение навигации в веб-платёжке
Этот метод вызывается после попытки открыть веб-пейвол для конкретного продукта. Это касается как успешных, так и неудачных попыток навигации:
void flowViewDidFinishWebPaymentNavigation(AdaptyUIFlowView view,
AdaptyPaywallProduct? product,
AdaptyError? error) {
}Параметры:
| Параметр | Описание |
|---|---|
| product | Объект AdaptyPaywallProduct, для которого был открыт веб-пейвол. Может быть null. |
| error | Объект AdaptyError, если навигация по веб-пейволу завершилась ошибкой; null, если навигация прошла успешно. |
Неудачная покупка
Этот метод вызывается при неудачной попытке покупки (например, из-за проблем с оплатой или сетевых ошибок). Он не срабатывает при отмене пользователем или ожидающих транзакциях — они обрабатываются через flowViewDidFinishPurchase:
void flowViewDidFailPurchase(AdaptyUIFlowView view,
AdaptyPaywallProduct product,
AdaptyError error) {
}Восстановление начато
Если пользователь инициирует процесс восстановления покупок, этот метод будет вызван:
void flowViewDidStartRestore(AdaptyUIFlowView view) {
}Успешное восстановление
Этот метод обязательный. Если восстановление покупки прошло успешно, он будет вызван:
void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) {
}Пример события (нажмите, чтобы развернуть)
void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) {
// profile — AdaptyProfile:
profile.accessLevels['premium']?.isActive; // true
profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
profile.subscriptions['premium_monthly']?.isActive; // true
profile.subscriptions['premium_monthly']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
}Мы рекомендуем закрывать экран, если у пользователя есть необходимый accessLevel. Обратитесь к разделу Статус подписки, чтобы узнать, как его проверить, и к разделу Обработка действий кнопок, чтобы узнать, как закрыть экран.
Неудачное восстановление
Если восстановление покупки завершается с ошибкой, будет вызван этот метод:
void flowViewDidFailRestore(AdaptyUIFlowView view, AdaptyError error) {
}Загрузка данных и отображение
Ошибки загрузки продуктов
Если вы не передаёте массив продуктов при инициализации, AdaptyUI самостоятельно запросит необходимые объекты с сервера. Если эта операция завершится ошибкой, AdaptyUI сообщит об этом, вызвав следующий метод:
void flowViewDidFailLoadingProducts(AdaptyUIFlowView view, AdaptyError error) {
}Ошибки отображения
Этот метод обязателен. Он заменяет метод paywallViewDidFailRendering из v3: ошибки, возникающие при рендеринге интерфейса, а также другие ошибки представления, передаются через него. После реализации метода решение о закрытии остаётся за вами — мы рекомендуем закрывать представление при таких ошибках; именно так ведёт себя встроенная логика SDK по умолчанию, когда наблюдатель не задан:
void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) {
// log the error and dismiss the broken view
view.dismiss();
}В нормальной ситуации ошибки рендеринга возникать не должны, поэтому если вы с ними столкнётесь — пожалуйста, сообщите нам.
Аналитические события
Опциональный метод flowViewDidReceiveAnalyticEvent предназначен для получения пользовательских аналитических событий из флоу. Флоу пока не отправляет такие события в ваш код, поэтому реализовывать этот метод не нужно.
Обработка покупок в режиме наблюдателя
Если вы активировали SDK в режиме наблюдателя и отображаете флоу или пейвол, отрисованный Adapty, SDK не совершает покупки самостоятельно. Когда пользователь нажимает кнопку покупки или восстановления, SDK вызывает ваш AdaptyUIObserverModeResolver. Подробнее о настройке читайте в разделе Отображение флоу в режиме наблюдателя.
Обработка системных запросов
AdaptyUISystemRequestsHandler (регистрируется через AdaptyUI().setSystemRequestsHandler(...)) предназначен для системных запросов из флоу: запросы разрешений ОС (например, push-уведомления или доступ к камере) и запросы на оценку в App Store. Флоу пока не инициируют такие запросы, поэтому регистрировать обработчик не нужно.
Если вы регистрируете обработчик, обратите внимание: handlePermission — это обязательный метод класса; запросите разрешение своим кодом, затем верните AdaptyUIPermissionResult.granted() или AdaptyUIPermissionResult.denied(); handleAppReviewRequest — необязательный.
Этот гайд охватывает обработку событий покупок, восстановления, выбора продуктов и отображения пейвола. Также необходимо реализовать обработку кнопок (закрытие пейвола, открытие ссылок и т. д.). Подробнее см. в нашем гайде по обработке действий кнопок.
Пейволы, созданные в Paywall Builder, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют события, на которые ваше приложение может реагировать. Среди них — нажатия кнопок (кнопки закрытия, URL, выбор продукта и т. д.), а также уведомления о действиях, связанных с покупками, выполненных на пейволе. Ниже описано, как обрабатывать эти события.
Это руководство предназначено только для пейволов, созданных в новом Paywall Builder, для работы с которыми требуется Adapty SDK v3.0 или более поздней версии.
Чтобы контролировать или отслеживать процессы, происходящие на экране пейвола в вашем мобильном приложении, реализуйте методы AdaptyUIPaywallsEventsObserver и установите наблюдатель до отображения любого экрана:
AdaptyUI().setPaywallsEventsObserver(this);Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши примеры приложений — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции.
В примерах событий ниже показаны свойства, доступные для каждого объекта, с иллюстративными значениями в комментариях.
События, генерируемые пользователем
Пейвол появился
Этот метод вызывается, когда представление пейвола отображается на экране.
На iOS также вызывается, когда пользователь нажимает на кнопку веб-пейвола внутри пейвола, и веб-пейвол открывается во встроенном браузере.
void paywallViewDidAppear(AdaptyUIPaywallView view) {
}Пейвол исчез
Этот метод вызывается, когда представление пейвола убирается с экрана.
На iOS также вызывается, когда веб-пейвол, открытый из пейвола во встроенном браузере, исчезает с экрана.
void paywallViewDidDisappear(AdaptyUIPaywallView view) {
}Выбор продукта
Если продукт выбран для покупки (пользователем или системой), этот метод будет вызван:
void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) {
}Пример события (нажмите, чтобы развернуть)
void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) {
// productId is a String:
productId; // 'premium_monthly'
}Начало покупки
Если пользователь инициирует процесс покупки, будет вызван этот метод:
void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) {
}Пример события (нажмите, чтобы развернуть)
void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
product.localizedTitle; // 'Premium Monthly'
product.localizedDescription; // 'Premium subscription for 1 month'
product.price.amount; // 9.99 (double)
product.price.currencyCode; // 'USD'
product.price.localizedString; // '$9.99'
}Завершённая покупка
Этот метод вызывается, когда покупка завершается успешно, пользователь отменяет покупку или покупка оказывается в ожидании:
void paywallViewDidFinishPurchase(AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchaseResult) {
switch (purchaseResult) {
case AdaptyPurchaseResultSuccess(profile: final profile):
// successful purchase
break;
case AdaptyPurchaseResultPending():
// purchase is pending
break;
case AdaptyPurchaseResultUserCancelled():
// user cancelled the purchase
break;
default:
break;
}
}Примеры событий (нажмите, чтобы развернуть)
void paywallViewDidFinishPurchase(AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchaseResult) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
switch (purchaseResult) {
case AdaptyPurchaseResultSuccess(profile: final profile):
// profile — AdaptyProfile:
profile.accessLevels['premium']?.isActive; // true
profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
break;
case AdaptyPurchaseResultPending():
// no additional data
break;
case AdaptyPurchaseResultUserCancelled():
// no additional data
break;
}
}Мы рекомендуем закрывать экран в этом случае. Подробнее о закрытии экрана пейвола см. в разделе Реакция на действия кнопок.
Завершение навигации веб-платежа
Этот метод вызывается после попытки открыть веб-пейвол для конкретного продукта. Это включает как успешные, так и неудачные попытки навигации:
void paywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view,
AdaptyPaywallProduct? product,
AdaptyError? error) {
}Параметры:
| Параметр | Описание |
|---|---|
| product | AdaptyPaywallProduct — продукт, для которого открыт веб-пейвол. Может быть null. |
| error | Объект AdaptyError, если навигация по веб-пейволу завершилась с ошибкой; null, если навигация прошла успешно. |
Примеры событий (нажмите, чтобы развернуть)
void paywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view,
AdaptyPaywallProduct? product,
AdaptyError? error) {
// product — AdaptyPaywallProduct?:
product?.vendorProductId; // 'premium_monthly'
if (error == null) {
// navigation succeeded
} else {
// error — AdaptyError:
error.code; // AdaptyErrorCode.networkFailed (2005)
error.message; // 'Network request failed'
error.detail; // platform-specific underlying error, or null
}
}Неудачная покупка
Этот метод вызывается, когда покупка завершается ошибкой (например, из-за проблем с оплатой или сетевых ошибок). Он не срабатывает при отмене пользователем или незавершённых транзакциях — они обрабатываются через paywallViewDidFinishPurchase:
void paywallViewDidFailPurchase(AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyError error) {
}Пример события (нажмите, чтобы развернуть)
void paywallViewDidFailPurchase(AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyError error) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
// error — AdaptyError:
error.code; // AdaptyErrorCode.productPurchaseFailed (1006)
error.message; // 'Product purchase failed.'
error.detail; // platform-specific underlying error, or null
}Восстановление начато
Когда пользователь инициирует процесс восстановления покупок, вызывается этот метод:
void paywallViewDidStartRestore(AdaptyUIPaywallView view) {
}Успешное восстановление
Если восстановление покупки прошло успешно, будет вызван этот метод:
void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) {
}Пример события (нажмите, чтобы развернуть)
void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) {
// profile — AdaptyProfile:
profile.accessLevels['premium']?.isActive; // true
profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
profile.subscriptions['premium_monthly']?.isActive; // true
profile.subscriptions['premium_monthly']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
}Мы рекомендуем закрывать экран, если у пользователя есть нужный accessLevel. Обратитесь к разделу Статус подписки, чтобы узнать, как его проверить, и к разделу Реагирование на действия кнопок, чтобы узнать, как закрыть экран пейвола.
Ошибка восстановления
Если восстановление покупки завершится с ошибкой, будет вызван следующий метод:
void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) {
}Пример события (нажмите, чтобы развернуть)
void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) {
// error — AdaptyError:
error.code; // AdaptyErrorCode.receiveRestoredTransactionsFailed (1011)
error.message; // 'Error occurred in the process of restoring purchases.'
error.detail; // platform-specific underlying error, or null
}Получение данных и рендеринг
Ошибки загрузки продуктов
Если вы не передаёте массив продуктов при инициализации, AdaptyUI самостоятельно получит необходимые объекты с сервера. Если эта операция завершится ошибкой, AdaptyUI сообщит о ней, вызвав следующий метод:
void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) {
}Пример события (нажмите, чтобы развернуть)
void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) {
// error — AdaptyError:
error.code; // AdaptyErrorCode.productRequestFailed (1002)
error.message; // 'Unable to fetch available In-App Purchase products at the moment.'
error.detail; // platform-specific underlying error, or null
}Ошибки рендеринга
Если во время отображения интерфейса возникает ошибка, она сообщается путём вызова этого метода. По умолчанию (начиная с v3.15.2) пейвол автоматически закрывается при ошибке рендеринга, но при необходимости это поведение можно переопределить.
void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) {
// Default behavior: view.dismiss()
// Override with custom logic if needed, for example:
// - Log the error
// - Show an error message to the user
}Пример события (нажмите, чтобы развернуть)
void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) {
// error — AdaptyError:
error.code; // AdaptyErrorCode.jsException (4105)
error.message; // 'An exception was thrown from JS during AdaptyUI flow execution.'
error.detail; // platform-specific underlying error, or null
// Default behavior: view.dismiss()
}В нормальной ситуации такие ошибки возникать не должны, поэтому если вы столкнулись с одной из них, пожалуйста, сообщите нам.