Обработка событий флоу и пейвола — React Native

Important

Этот гайд охватывает обработку событий для покупок, восстановлений, выбора продуктов и отображения флоу. Вы также можете настроить обработку кнопок (закрытие флоу, открытие ссылок, пользовательские действия и т. д.). Подробнее см. в нашем гайде по обработке действий кнопок.

Потоки и пейволы, созданные во Flow & Paywall Builder, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют события, на которые ваше приложение может реагировать. Эти события включают нажатия кнопок (кнопки закрытия, URL, выбор продуктов и т. д.), а также уведомления о действиях, связанных с покупками, происходящих в потоке. Узнайте, как реагировать на эти события, ниже.

Чтобы управлять процессами на экране флоу или отслеживать их в мобильном приложении, реализуйте обработчики событий:

Примеры событий (нажмите, чтобы развернуть)
// onCloseButtonPress
{
  //Record the event
}

// onAndroidSystemBack
{
  //Record the event
}

// onUrlPress
{
  "url": "https://example.com/terms"
}

// onCustomAction
{
  "actionId": "login"
}

// onProductSelected
{
  "productId": "premium_monthly"
}

// onPurchaseStarted
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Success
{
  "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",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Cancelled
{
  "purchaseResult": {
    "type": "user_cancelled"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseFailed
{
  "error": {
    "code": "purchase_failed",
    "message": "Purchase failed due to insufficient funds",
    "details": {
      "underlyingError": "Insufficient funds in account"
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onRestoreCompleted
{
  "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
{
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

// onError
{
  "error": {
    "code": "rendering_failed",
    "message": "Failed to render flow interface",
    "details": {
      "underlyingError": "Invalid flow configuration"
    }
  }
}

// onLoadingProductsFailed
{
  "error": {
    "code": "products_loading_failed",
    "message": "Failed to load products from the server",
    "details": {
      "underlyingError": "Network timeout"
    }
  }
}

// onAppeared
{
  "view": {
    "id": "3f8a1c7e-9b24-4d51-8e30-6c5b2a9f1d47",
    "placementId": "onboarding_paywall",
    "variationId": "d21c4b6a-57e8-4f39-b0a2-8c7e13f5d94b",
    "locale": "es"
  }
}

// onDisappeared
{
  //Record the event
}

// onWebPaymentNavigationFinished
{
  //Record the event
}

Вы можете зарегистрировать только нужные обработчики событий, а ненужные — пропустить. В этом случае лишние слушатели событий не создаются. Обязательных обработчиков событий нет.

Обработчики событий возвращают булево значение. Если возвращается true, процесс отображения считается завершённым: экран флоу закрывается, а слушатели событий для этого представления удаляются.

Некоторые обработчики событий имеют поведение по умолчанию, которое можно переопределить при необходимости:

  • onCloseButtonPress: закрывает флоу при нажатии кнопки закрытия.
  • onUrlPress: открывает нажатую ссылку и оставляет флоу открытым.
  • onAndroidSystemBack (только для модального отображения): оставляет флоу открытым при нажатии кнопки Back. Верните true, чтобы закрыть флоу.
  • onRestoreCompleted: оставляет флоу открытым после успешного восстановления покупок. Верните true, чтобы закрыть флоу.
  • onPurchaseCompleted: оставляет флоу открытым после завершения покупки. Верните true, чтобы закрыть флоу.
  • onError: закрывает флоу, если его отрисовка завершилась с ошибкой.

Обработчики событий

Обработчик событияОписание
onCustomActionВызывается, когда пользователь выполняет пользовательское действие, например нажимает кастомную кнопку.
onUrlPressВызывается, когда пользователь нажимает на URL во флоу.
onAndroidSystemBackТолько для модального представления: вызывается, когда пользователь нажимает системную кнопку Android Back.
onCloseButtonPressВызывается, когда кнопка закрытия видима и пользователь нажимает на неё. Рекомендуется закрывать экран флоу в этом обработчике.
onPurchaseCompletedВызывается при завершении покупки — успешном, отменённом пользователем или ожидающем подтверждения. В случае успешной покупки предоставляет обновлённый AdaptyProfile. Отмены пользователем и ожидающие платежи (например, требующие родительского подтверждения) вызывают это событие, а не onPurchaseFailed.
onPurchaseStartedВызывается, когда пользователь нажимает кнопку «Купить», чтобы начать процесс покупки.
onPurchaseFailedВызывается при сбое покупки из-за ошибок (например, ограничений платежей, недопустимых продуктов, сетевых сбоев, ошибок верификации транзакций). Не вызывается при отмене пользователем или ожидающих платежах — в этих случаях вызывается onPurchaseCompleted.
onRestoreStartedВызывается, когда пользователь начинает процесс восстановления покупок.
onRestoreCompletedВызывается при успешном восстановлении покупок и предоставляет обновлённый AdaptyProfile. Рекомендуется закрывать экран, если у пользователя есть необходимый accessLevel. Подробнее см. в разделе Статус подписки.
onRestoreFailedВызывается при сбое процесса восстановления и предоставляет AdaptyError.
onProductSelectedВызывается при выборе любого продукта во флоу, что позволяет отслеживать выбор пользователя до совершения покупки.
onErrorВызывается при возникновении ошибки в процессе рендеринга представления и предоставляет AdaptyError. Такие ошибки не должны возникать — если вы столкнулись с подобным, пожалуйста, сообщите нам.
onLoadingProductsFailedВызывается при сбое загрузки продуктов и предоставляет AdaptyError. Если вы не установили prefetchProducts: true при создании представления, AdaptyUI самостоятельно получит необходимые объекты с сервера.
onAppearedВызывается, когда флоу отображается пользователю, и предоставляет view, который появился — см. Аргумент view. На iOS также вызывается, когда пользователь нажимает кнопку веб-пейвола внутри флоу и веб-пейвол открывается во встроенном браузере.
onDisappearedТолько для модального представления: вызывается, когда флоу закрывается пользователем. На iOS также вызывается, когда веб-пейвол, открытый из флоу во встроенном браузере, исчезает с экрана.
onWebPaymentNavigationFinishedВызывается после попытки открыть веб-пейвол для покупки — успешной или неудачной.
onAnalyticsВызывается, когда флоу сообщает о событии аналитики, например о просмотре экрана. См. События аналитики ниже.
onRequestAppReviewЗарезервировано для запросов отзыва о приложении из флоу. Флоу пока не инициируют запросы отзывов, поэтому реализовывать этот обработчик не нужно.
onRequestPermissionЗарезервировано для запросов системных разрешений (например, push-уведомлений или доступа к камере) из флоу. Флоу пока не инициируют запросы разрешений, поэтому реализовывать этот обработчик не нужно.
onObserverPurchaseInitiatedТолько для режима наблюдателя: вызывается, когда пользователь нажимает кнопку покупки во флоу. Adapty не выполняет покупку — совершите её с помощью собственного кода, а затем сообщите о транзакции в Adapty. См. Обработка покупок в режиме наблюдателя ниже.
onObserverRestoreInitiatedТолько для режима наблюдателя: вызывается, когда пользователь нажимает кнопку восстановления во флоу. Adapty не выполняет восстановление — сделайте это самостоятельно, а затем сообщите о восстановленных транзакциях. См. Обработка покупок в режиме наблюдателя ниже.

Аргумент view

Аргумент view требует React Native SDK версии 4.0.3 или выше. Из всех обработчиков флоу только onAppeared получает описание самого вью — объект FlowEventView со следующими полями:

FieldDescription
idИдентификатор данного экземпляра представления. Он является внутренним для SDK и не соответствует ничему в дашборде Adapty.
placementIdПлейсмент, для которого был получен флоу.
variationIdВариант, к которому был определён флоу, для атрибуции вашей собственной аналитики к A/B-тесту.
localeЛокализация флоу, с которой было построено представление. Отличается от запрошенной вами локали, если у флоу нет такой локализации. Считывайте её, чтобы привести остальную часть вашего экрана в соответствие с языком, на котором отобразился флоу. См. Использование локализаций и кодов локалей.

События аналитики

const unsubscribe = view.setEventHandlers({
  onAnalytics(name, params) {
    return false; // keep the flow open
  },
});

Флоу отправляет событие flow_screen_showed каждый раз, когда пользователь открывает один из его экранов. Adapty учитывает эти события в собственной аналитике флоу и также передаёт их в ваше приложение, чтобы вы могли построить такую же воронку в своей аналитике.

ПараметрОписание
instanceIdИдентификатор экрана, который открыл пользователь.
screen_orderПорядковый номер экрана во флоу.
is_last_screentrue, если у экрана нет следующего шага. Флоу с ветвлением может завершаться на нескольких разных экранах — каждый из них возвращает true.

Оба поля isBackendEvent и isCustomerEvent равны true для этого события: Adapty продолжает его учитывать, и ваше приложение тоже его получает.

Подробнее о том, что с ними делать, — в разделе Отслеживание просмотров экранов флоу.

Флоу также передаёт значения, которые пользователи вводят и выбирают. Подробнее — в разделе Обработка данных из флоу.

Обработка покупок в режиме наблюдателя

Если вы активировали SDK в режиме наблюдателя (observerMode: true) и показываете флоу, отрендеренный Adapty, SDK не выполняет покупки самостоятельно. Когда пользователь нажимает кнопку покупки или восстановления, SDK вызывает onObserverPurchaseInitiated или onObserverRestoreInitiated. Выполните покупку или восстановление с помощью собственного кода, управляйте индикатором загрузки флоу через предоставленные колбэки и после этого сообщите о транзакции в Adapty.

const unsubscribe = view.setEventHandlers({
  onObserverPurchaseInitiated(product, onStartPurchase, onFinishPurchase) {
    onStartPurchase(); // show the flow's loading indicator
    myPurchaseApi(product.vendorProductId)
      .then((transactionId) => adapty.reportTransaction(transactionId))
      .finally(() => onFinishPurchase()); // hide the loading indicator
    return false; // keep the flow open; dismiss it yourself after success
  },
  onObserverRestoreInitiated(onStartRestore, onFinishRestore) {
    onStartRestore();
    myRestoreApi()
      .finally(() => onFinishRestore());
    return false;
  },
});
Important

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

Пейволы, настроенные с помощью Paywall Builder, не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют события, на которые ваше приложение может реагировать. К таким событиям относятся нажатия кнопок (кнопки закрытия, URL, выбор продуктов и т. д.), а также уведомления о действиях, связанных с покупками, совершённых на пейволе. Ниже описано, как реагировать на эти события.

Warning

Этот гайд охватывает только пейволы, созданные в старом конструкторе, для которых требуется Adapty SDK v3.0 или выше.

Для управления процессами на экране пейвола и мониторинга событий реализуйте обработчики событий:

Примеры событий (нажмите, чтобы развернуть)
// onCloseButtonPress
{
  //Record the event
}

// onAndroidSystemBack
{
  //Record the event
}

// onUrlPress
{
  "url": "https://example.com/terms"
}

// onCustomAction
{
  "actionId": "login"
}

// onProductSelected
{
  "productId": "premium_monthly"
}

// onPurchaseStarted
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Success
{
  "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",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Cancelled
{
  "purchaseResult": {
    "type": "user_cancelled"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseFailed
{
  "error": {
    "code": "purchase_failed",
    "message": "Purchase failed due to insufficient funds",
    "details": {
      "underlyingError": "Insufficient funds in account"
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onRestoreCompleted
{
  "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
{
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

// onRenderingFailed
{
  "error": {
    "code": "rendering_failed",
    "message": "Failed to render paywall interface",
    "details": {
      "underlyingError": "Invalid paywall configuration"
    }
  }
}

// onLoadingProductsFailed
{
  "error": {
    "code": "products_loading_failed",
    "message": "Failed to load products from the server",
    "details": {
      "underlyingError": "Network timeout"
    }
  }
}

// onPaywallShown
{
  //Record the event
}

// onPaywallClosed
{
  //Record the event
}

// onWebPaymentNavigationFinished
{
  //Record the event
}

Вы можете регистрировать только те обработчики событий, которые вам нужны, — остальные можно пропустить. Неиспользуемые обработчики событий при этом не создаются. Обязательных обработчиков нет.

Обработчики событий возвращают булево значение. Если возвращается true, процесс отображения считается завершённым: экран пейвола закрывается, а все слушатели событий для этого представления удаляются.

У некоторых обработчиков событий есть поведение по умолчанию, которое можно переопределить при необходимости:

  • onCloseButtonPress: закрывает пейвол при нажатии кнопки закрытия.
  • onUrlPress: открывает нажатый URL и оставляет пейвол открытым.
  • onAndroidSystemBack (только для модального представления): закрывает пейвол при нажатии кнопки Back.
  • onRestoreCompleted: закрывает пейвол после успешного восстановления.
  • onPurchaseCompleted: закрывает пейвол, если пользователь не отменил покупку.
  • onRenderingFailed: закрывает пейвол, если его рендеринг завершился с ошибкой.

Обработчики событий

Обработчик событийОписание
onCustomActionВызывается, когда пользователь выполняет пользовательское действие, например нажимает кастомную кнопку.
onUrlPressВызывается, когда пользователь нажимает на URL в вашем пейволе.
onAndroidSystemBackТолько для модального представления: вызывается, когда пользователь нажимает системную кнопку Android Back.
onCloseButtonPressВызывается, когда кнопка закрытия видима и пользователь нажимает её. Рекомендуется закрывать экран пейвола в этом обработчике.
onPurchaseCompletedВызывается по завершении покупки — успешной, отменённой пользователем или ожидающей подтверждения. В случае успешной покупки возвращает обновлённый AdaptyProfile. Отмены пользователем и отложенные платежи (например, требующие родительского разрешения) вызывают это событие, а не onPurchaseFailed.
onPurchaseStartedВызывается, когда пользователь нажимает кнопку действия «Купить», чтобы начать процесс покупки.
onPurchaseFailedВызывается, когда покупка завершается с ошибкой (например, ограничения платежей, недействительные продукты, сетевые сбои, ошибки верификации транзакций). Не вызывается при отмене пользователем или отложенных платежах — в этих случаях вызывается onPurchaseCompleted.
onRestoreStartedВызывается, когда пользователь запускает процесс восстановления покупок.
onRestoreCompletedВызывается при успешном восстановлении покупок и возвращает обновлённый AdaptyProfile. Рекомендуется закрывать экран, если у пользователя есть требуемый accessLevel. О том, как это проверить, читайте в разделе Статус подписки.
onRestoreFailedВызывается, когда процесс восстановления завершается с ошибкой, и возвращает AdaptyError.
onProductSelectedВызывается при выборе любого продукта в пейволе — позволяет отслеживать, что пользователь выбирает перед покупкой.
onRenderingFailedВызывается при возникновении ошибки во время рендеринга и возвращает AdaptyError. Такие ошибки не должны возникать, поэтому если вы столкнулись с ней — сообщите нам.
onLoadingProductsFailedВызывается при сбое загрузки продуктов и возвращает AdaptyError. Если при создании представления вы не задали prefetchProducts: true, AdaptyUI самостоятельно получит необходимые объекты с сервера.
onPaywallShownВызывается, когда пейвол отображается пользователю. На iOS также вызывается, когда пользователь нажимает кнопку веб-пейвола внутри пейвола и веб-пейвол открывается во встроенном браузере.
onPaywallClosedТолько для модального представления: вызывается, когда пользователь закрывает пейвол. На iOS также вызывается, когда веб-пейвол, открытый из пейвола во встроенном браузере, исчезает с экрана.
onWebPaymentNavigationFinishedВызывается после попытки открыть веб-пейвол для совершения покупки — независимо от того, успешной она была или нет.