Обработка событий флоу и пейвола - Capacitor
Этот гайд охватывает обработку событий для покупок, восстановлений, выбора продукта и отображения флоу. Вы также можете настроить обработку кнопок (закрытие флоу, открытие ссылок, пользовательские действия и т. д.). Подробнее см. в нашем гайде по обработке действий кнопок.
Флоу и пейволы, созданные с помощью Flow Builder, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют ряд событий, на которые ваше приложение может реагировать. К таким событиям относятся нажатия кнопок (кнопки закрытия, URL-ссылки, выбор продуктов и т. д.), а также уведомления о действиях, связанных с покупками в рамках флоу. Узнайте, как реагировать на эти события, ниже.
Чтобы управлять процессами, происходящими на экране флоу, или отслеживать их в своём мобильном приложении, реализуйте метод view.setEventHandlers:
Можно задать только один обработчик на каждое событие: повторный вызов setEventHandlers заменит ранее установленные обработчики для указанных событий, включая дефолтные. Обработчики, которые вы не задаёте, сохраняют поведение по умолчанию. setEventHandlers возвращает функцию отписки, а view.dismiss() удаляет все обработчики.
const view = await createFlowView(flow);
const unsubscribe = await view.setEventHandlers({
onCloseButtonPress() {
return true; // close the flow (default behavior)
},
onAndroidSystemBack() {
return true; // close the flow; by default, it stays open
},
onPurchaseCompleted(purchaseResult, product) {
return purchaseResult.type === 'success'; // close the flow on a successful purchase, keep it open for cancelled or pending purchases
},
onPurchaseStarted(product) { /***/ },
onPurchaseFailed(error, product) { /***/ },
onRestoreCompleted(profile) { /***/ },
onRestoreFailed(error) { /***/ },
onProductSelected(productId) { /***/ },
onError(error) { /***/ },
onLoadingProductsFailed(error) { /***/ },
onUrlPress(url, openIn) {
adapty.openWebUrl({ url, openIn }).catch(console.warn); // same as the SDK default
return false; // keep the flow open
},
onAppeared(appearedView) { /***/ },
onDisappeared() { /***/ },
onWebPaymentNavigationFinished() { /***/ },
});Примеры событий (нажмите, чтобы развернуть)
Примеры ниже показывают свойства, доступные в каждом обработчике, с иллюстративными значениями в комментариях.
// onUrlPress
url; // 'https://example.com/terms'
openIn; // 'browser_in_app' or 'browser_out_app'
// onCustomAction
actionId; // 'login'
// onProductSelected
productId; // 'premium_monthly'
// onAppeared
appearedView.id; // '3f8a1c7e-9b24-4d51-8e30-6c5b2a9f1d47'
appearedView.placementId; // 'onboarding_paywall'
appearedView.variationId; // 'd21c4b6a-57e8-4f39-b0a2-8c7e13f5d94b'
appearedView.locale; // 'es'
// onPurchaseStarted, onPurchaseCompleted, onPurchaseFailed
product.vendorProductId; // 'premium_monthly'
product.localizedTitle; // 'Premium Monthly'
product.localizedDescription; // 'Premium subscription for 1 month'
product.price?.amount; // 9.99
product.price?.currencyCode; // 'USD'
product.price?.localizedString; // '$9.99'
// onPurchaseCompleted
purchaseResult.type; // 'success', 'pending', or 'user_cancelled'
if (purchaseResult.type === 'success') {
purchaseResult.profile.accessLevels['premium']?.isActive; // true
}
// onRestoreCompleted
profile.accessLevels['premium']?.isActive; // true
// onPurchaseFailed, onRestoreFailed, onError, onLoadingProductsFailed
error.message; // 'Purchase failed due to insufficient funds'Вы можете зарегистрировать только нужные обработчики событий, пропустив остальные — лишние слушатели событий при этом не создаются. Обязательных обработчиков нет.
Обработчики событий возвращают булево значение. Если возвращается true, процесс отображения считается завершённым: экран флоу закрывается, а слушатели событий для этого представления удаляются.
У некоторых обработчиков событий есть поведение по умолчанию, которое при необходимости можно переопределить:
onCloseButtonPress: закрывает флоу при нажатии кнопки закрытия.onUrlPress: открывает нажатый URL в браузере черезadapty.openWebUrl, учитывая параметр Open in, заданный в билдере, и оставляет флоу открытым.onAndroidSystemBack: оставляет флоу открытым при нажатии кнопки Back. Вернитеtrue, чтобы закрыть его.onPurchaseCompleted: оставляет флоу открытым после завершения покупки. Вернитеtrue, чтобы закрыть его.onRestoreCompleted: оставляет флоу открытым после успешного восстановления покупок. Вернитеtrue, чтобы закрыть его.onError: закрывает флоу, если его рендеринг завершился ошибкой.
Обработчики событий
| Обработчик событий | Описание |
|---|---|
| onCustomAction | Вызывается, когда пользователь выполняет пользовательское действие, например нажимает кастомную кнопку. |
| onUrlPress | Вызывается, когда пользователь нажимает на URL во флоу. |
| onAndroidSystemBack | Вызывается, когда пользователь нажимает системную кнопку Android Back. По умолчанию флоу остаётся открытым; верните true, чтобы закрыть его. |
| onCloseButtonPress | Вызывается, когда кнопка закрытия видна и пользователь её нажимает. Рекомендуется закрывать экран флоу в этом обработчике. |
| onPurchaseCompleted | Вызывается при завершении покупки — независимо от того, была ли она успешной, отменена пользователем или ожидает подтверждения. В случае успешной покупки предоставляет обновлённый AdaptyProfile. Отмены пользователем и ожидающие платежи (например, требующие родительского одобрения) вызывают это событие, а не onPurchaseFailed. |
| onPurchaseStarted | Вызывается, когда пользователь нажимает кнопку действия «Купить» для начала процесса покупки. |
| onPurchaseFailed | Вызывается при сбое покупки из-за ошибок (например, ограничения платежей, недействительные продукты, сетевые сбои, ошибки верификации транзакций). Не вызывается при отмене пользователем или ожидающих платежах — они вызывают onPurchaseCompleted. |
| onRestoreStarted | Вызывается, когда пользователь начинает процесс восстановления покупок. |
| onRestoreCompleted | Вызывается при успешном восстановлении покупок и предоставляет обновлённый AdaptyProfile. Рекомендуется закрывать экран, если у пользователя есть необходимый accessLevel. Подробнее — в разделе Статус подписки. |
| onRestoreFailed | Вызывается при сбое процесса восстановления и предоставляет AdaptyError. |
| onProductSelected | Вызывается при выборе любого продукта во флоу, позволяя отслеживать, что пользователь выбирает перед покупкой. |
| onError | Вызывается при возникновении ошибки во время рендеринга и предоставляет AdaptyError. Такие ошибки не должны возникать, поэтому если вы с ней столкнулись — сообщите нам. |
| onLoadingProductsFailed | Вызывается при сбое загрузки продуктов и предоставляет AdaptyError. Если вы не установили prefetchProducts: true при создании вью, AdaptyUI самостоятельно получит необходимые объекты с сервера. |
| onAppeared | Вызывается, когда флоу отображается пользователю, и предоставляет появившееся вью — см. Аргумент view. На iOS также вызывается, когда пользователь нажимает кнопку веб-пейвола внутри флоу и веб-пейвол открывается во встроенном браузере. |
| onDisappeared | Вызывается, когда флоу закрывается пользователем. На iOS также вызывается, когда веб-пейвол, открытый из флоу во встроенном браузере, исчезает с экрана. |
| onWebPaymentNavigationFinished | Вызывается после попытки открыть веб-пейвол для покупки — независимо от того, успешной или нет. |
| onRequestAppReview | Зарезервирован для запросов оценки приложения из флоу. Флоу пока не инициируют запросы оценки, поэтому реализовывать его не нужно. |
| onAnalytics | Вызывается, когда флоу сообщает об аналитическом событии, например о просмотре экрана. См. События аналитики ниже. |
| onRequestPermission | Зарезервирован для запросов системных разрешений (например, push-уведомлений или доступа к камере) из флоу. Флоу пока не инициируют запросы разрешений, поэтому реализовывать его не нужно. |
| onObserverPurchaseInitiated | Только режим наблюдателя: вызывается, когда пользователь нажимает кнопку покупки во флоу. Adapty не совершает покупку — выполните её с помощью собственного кода, а затем сообщите о транзакции в Adapty. См. Обработка покупок в режиме наблюдателя ниже. |
| onObserverRestoreInitiated | Только режим наблюдателя: вызывается, когда пользователь нажимает кнопку восстановления во флоу. Adapty не выполняет восстановление — сделайте это самостоятельно, а затем сообщите о восстановленных транзакциях. См. Обработка покупок в режиме наблюдателя ниже. |
Аргумент view
Аргумент view доступен начиная с Capacitor SDK 4.0.2-beta.1. Из всех обработчиков флоу только onAppeared получает описание самого вью — объект FlowEventView со следующими полями:
| Поле | Описание |
|---|---|
| id | Идентификатор данного экземпляра представления. Является внутренним для SDK и не соответствует ничему в дашборде Adapty. |
| placementId | Плейсмент, для которого был получен флоу. |
| variationId | Вариант, к которому был определён флоу — для привязки вашей аналитики к A/B-тесту. |
| locale | Локализация флоу, с которой было создано представление. Отличается от запрошенной локали, если у флоу нет такой локализации. Представление, возвращённое функцией createFlowView, возвращает то же значение в свойстве locale. См. Использование локализаций и кодов локалей. |
Аналитические события
view.setEventHandlers({
onAnalytics(name, params) {
return false; // keep the flow open
},
});Флоу отправляет событие flow_screen_showed каждый раз, когда пользователь открывает один из его экранов. Adapty учитывает эти события в собственной аналитике флоу и также передаёт их в ваше приложение, чтобы вы могли построить такую же воронку в своей аналитике.
| Параметр | Описание |
|---|---|
instanceId | Идентификатор экрана, который открыл пользователь. |
screen_order | Порядковый номер экрана во флоу. |
is_last_screen | true, если у экрана нет следующего шага. Флоу с ветвлением может завершаться на нескольких разных экранах — каждый из них возвращает true. |
Оба поля isBackendEvent и isCustomerEvent равны true для этого события: Adapty продолжает его учитывать, и ваше приложение тоже его получает.
Подробнее о том, что делать с этими данными, читайте в разделе Отслеживание просмотров экранов флоу.
Обработка покупок в режиме наблюдателя
Если вы активировали SDK в режиме наблюдателя (observerMode: true) и показываете флоу, отрисованный Adapty, SDK не выполняет покупки самостоятельно. Когда пользователь нажимает кнопку покупки или восстановления, SDK вызывает onObserverPurchaseInitiated или onObserverRestoreInitiated, чтобы вы могли выполнить покупку или восстановление своим кодом. Подробная настройка описана в разделе Показ флоу в режиме наблюдателя.
Этот гайд охватывает обработку событий для покупок, восстановлений, выбора продуктов и отображения пейволов. Вам также необходимо реализовать обработку кнопок (закрытие пейвола, открытие ссылок и т. д.). Подробнее см. в нашем гайде по обработке действий кнопок.
Пейволы, созданные с помощью Paywall Builder, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют ряд событий, на которые ваше приложение может реагировать. К ним относятся нажатия кнопок (кнопки закрытия, URL, выбор продуктов и т. д.), а также уведомления о действиях, связанных с покупками на пейволе. Ниже описано, как обрабатывать эти события.
Чтобы управлять процессами на экране пейвола или отслеживать их в вашем мобильном приложении, реализуйте метод view.setEventHandlers:
const view = await createPaywallView(paywall);
const unsubscribe = view.setEventHandlers({
onCloseButtonPress() {
console.log('User closed paywall');
return true; // Allow the paywall to close
},
onAndroidSystemBack() {
console.log('User pressed back button');
return true; // Allow the paywall to close
},
onAppeared() {
console.log('Paywall appeared');
return false; // Don't close the paywall
},
onDisappeared() {
console.log('Paywall disappeared');
},
onPurchaseCompleted(purchaseResult, product) {
console.log('Purchase completed:', purchaseResult);
return purchaseResult.type !== 'user_cancelled'; // Close if not cancelled
},
onPurchaseStarted(product) {
console.log('Purchase started:', product);
return false; // Don't close the paywall
},
onPurchaseFailed(error, product) {
console.error('Purchase failed:', error);
return false; // Don't close the paywall
},
onRestoreCompleted(profile) {
console.log('Restore completed:', profile);
return true; // Close the paywall after successful restore
},
onRestoreFailed(error) {
console.error('Restore failed:', error);
return false; // Don't close the paywall
},
onProductSelected(productId) {
console.log('Product selected:', productId);
return false; // Don't close the paywall
},
onRenderingFailed(error) {
console.error('Rendering failed:', error);
return false; // Don't close the paywall
},
onLoadingProductsFailed(error) {
console.error('Loading products failed:', error);
return false; // Don't close the paywall
},
onUrlPress(url) {
window.open(url, '_blank');
return false; // Don't close the paywall
},
});Примеры событий (нажмите, чтобы раскрыть)
// onCloseButtonPress
{
"event": "close_button_press"
}
// onAndroidSystemBack
{
"event": "android_system_back"
}
// onAppeared
{
"event": "paywall_shown"
}
// onDisappeared
{
"event": "paywall_closed"
}
// onUrlPress
{
"event": "url_press",
"url": "https://example.com/terms"
}
// onCustomAction
{
"event": "custom_action",
"actionId": "login"
}
// onProductSelected
{
"event": "product_selected",
"productId": "premium_monthly"
}
// onPurchaseStarted
{
"event": "purchase_started",
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
// onPurchaseCompleted - Success
{
"event": "purchase_completed",
"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"
}
}
// onPurchaseCompleted - Cancelled
{
"event": "purchase_completed",
"purchaseResult": {
"type": "user_cancelled"
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
// onPurchaseFailed
{
"event": "purchase_failed",
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
}
}
// onRestoreCompleted
{
"event": "restore_completed",
"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"
}
]
}
}
// onRestoreFailed
{
"event": "restore_failed",
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
}
// onRenderingFailed
{
"event": "rendering_failed",
"error": {
"code": "rendering_failed",
"message": "Failed to render paywall interface",
"details": {
"underlyingError": "Invalid paywall configuration"
}
}
}
// onLoadingProductsFailed
{
"event": "loading_products_failed",
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
}Вы можете регистрировать только нужные обработчики событий, пропуская те, которые не нужны. В этом случае лишние слушатели событий созданы не будут. Обязательных обработчиков событий нет.
Обработчики событий возвращают булево значение. Если возвращается true, процесс отображения считается завершённым: экран пейвола закрывается, а слушатели событий для этого представления удаляются.
Некоторые обработчики событий имеют поведение по умолчанию, которое при необходимости можно переопределить:
onCloseButtonPress: закрывает пейвол при нажатии кнопки закрытия.onAndroidSystemBack: закрывает пейвол при нажатии кнопки Back.onRestoreCompleted: закрывает пейвол после успешного восстановления покупок.onPurchaseCompleted: закрывает пейвол, если пользователь не отменил покупку.onRenderingFailed: закрывает пейвол, если его отрисовка завершилась с ошибкой.onUrlPress: открывает URL в системном браузере и оставляет пейвол открытым.
Обработчики событий
| Обработчик событий | Описание |
|---|---|
| onCustomAction | Вызывается, когда пользователь выполняет пользовательское действие, например нажимает кастомную кнопку. |
| onUrlPress | Вызывается, когда пользователь нажимает на URL в пейволе. |
| onAndroidSystemBack | Вызывается, когда пользователь нажимает системную кнопку Android Back. |
| onCloseButtonPress | Вызывается, когда кнопка закрытия видима и пользователь нажимает её. Рекомендуется закрывать экран пейвола в этом обработчике. |
| onPurchaseCompleted | Вызывается при завершении покупки — независимо от того, была ли она успешной, отменена пользователем или ожидает подтверждения. В случае успешной покупки предоставляет обновлённый AdaptyProfile. Отмены пользователем и ожидающие платежи (например, требующие родительского подтверждения) тоже вызывают это событие, а не onPurchaseFailed. |
| onPurchaseStarted | Вызывается, когда пользователь нажимает кнопку «Купить», чтобы начать процесс покупки. |
| onPurchaseCancelled | Вызывается, когда пользователь инициирует процесс покупки и вручную прерывает его (отменяет диалог оплаты). |
| onPurchaseFailed | Вызывается, когда покупка завершается с ошибкой (например, ограничения платежей, недействительные продукты, сбои сети, ошибки верификации транзакции). Не вызывается при отменах пользователем или ожидающих платежах — для них срабатывает onPurchaseCompleted. |
| onRestoreStarted | Вызывается, когда пользователь начинает процесс восстановления покупок. |
| onRestoreCompleted | Вызывается при успешном восстановлении покупок и предоставляет обновлённый AdaptyProfile. Рекомендуется закрывать экран, если у пользователя есть нужный accessLevel. Подробнее о проверке статуса подписки — в разделе Статус подписки. |
| onRestoreFailed | Вызывается при сбое процесса восстановления и предоставляет AdaptyError. |
| onProductSelected | Вызывается, когда пользователь выбирает любой продукт в пейволе — позволяет отслеживать выбор до совершения покупки. |
| onAppeared | Вызывается, когда экран пейвола появляется на экране. На iOS также вызывается, когда пользователь нажимает кнопку веб-пейвола внутри пейвола и веб-пейвол открывается во встроенном браузере. |
| onDisappeared | Вызывается, когда экран пейвола исчезает с экрана. На iOS также вызывается, когда веб-пейвол, открытый из пейвола во встроенном браузере, исчезает с экрана. |
| onRenderingFailed | Вызывается при возникновении ошибки во время рендеринга представления и предоставляет AdaptyError. Такие ошибки не должны возникать, поэтому если вы столкнулись с подобной, пожалуйста, сообщите нам. |
| onLoadingProductsFailed | Вызывается при сбое загрузки продуктов и предоставляет AdaptyError. Если вы не указали prefetchProducts: true при создании представления, AdaptyUI самостоятельно загрузит необходимые объекты с сервера. |