Обработка событий флоу и пейвола - 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() { /***/ },
  onDisappeared() { /***/ },
  onWebPaymentNavigationFinished() { /***/ },
});
Примеры событий (нажмите, чтобы развернуть)

Примеры ниже показывают свойства, доступные в каждом обработчике, с иллюстративными значениями в комментариях.

// onUrlPress
url;    // 'https://example.com/terms'
openIn; // 'browser_in_app' or 'browser_out_app'

// onCustomAction
actionId; // 'login'

// onProductSelected
productId; // 'premium_monthly'

// 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Вызывается, когда флоу отображается пользователю. На iOS также вызывается, когда пользователь нажимает кнопку веб-пейвола внутри флоу и веб-пейвол открывается во встроенном браузере.
onDisappearedВызывается, когда пользователь закрывает флоу. На iOS также вызывается, когда веб-пейвол, открытый из флоу во встроенном браузере, исчезает с экрана.
onWebPaymentNavigationFinishedВызывается после попытки открыть веб-пейвол для покупки — независимо от того, была ли она успешной или завершилась ошибкой.
onRequestAppReviewЗарезервировано для запросов оценки приложения из флоу. Флоу пока не инициируют запросы оценки, поэтому реализовывать этот обработчик не нужно.
onAnalyticsЗарезервировано для пользовательских аналитических событий из флоу. Флоу пока не передают их в ваш код, поэтому реализовывать этот обработчик не нужно.
onRequestPermissionЗарезервировано для запросов системных разрешений (например, push-уведомлений или доступа к камере) из флоу. Флоу пока не инициируют запросы разрешений, поэтому реализовывать этот обработчик не нужно.
onObserverPurchaseInitiatedТолько для режима наблюдателя: вызывается, когда пользователь нажимает кнопку покупки в флоу. Adapty не выполняет покупку — выполните её собственным кодом, затем сообщите о транзакции в Adapty. См. раздел Обработка покупок в режиме наблюдателя ниже.
onObserverRestoreInitiatedТолько для режима наблюдателя: вызывается, когда пользователь нажимает кнопку восстановления в флоу. 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 самостоятельно загрузит необходимые объекты с сервера.