### В момент входа или регистрации \{#during-loginsignup\}
Если вы идентифицируете пользователей после запуска приложения (например, после входа в аккаунт или регистрации), используйте метод `identify`, чтобы задать их customer user ID.
- Если вы **ещё не использовали этот customer user ID**, Adapty автоматически привяжет его к текущему профилю.
- Если вы **уже использовали этот customer user ID для идентификации пользователя**, Adapty переключится на работу с профилем, связанным с этим customer user ID.
:::important
Идентификаторы пользователей (customer user ID) должны быть уникальными для каждого пользователя. Если задать значение параметра жёстко в коде, все пользователи будут считаться одним.
:::
Дождитесь срабатывания колбэка завершения `identify`, прежде чем вызывать другие методы SDK. Параллельные вызовы могут попасть в анонимный профиль вместо идентифицированного. См. [Порядок вызовов в Android SDK](android-sdk-call-order).
По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Рекомендуем именно этот вариант — так пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильный интернет, рассмотрите вариант `.returnCacheDataElseLoad`: он возвращает кешированные данные, если они есть. В этом случае данные могут быть не самыми свежими, зато загрузка будет быстрее при любом качестве соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит флоу и пейволы локально в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Для ускорения загрузки используется CDN, а в случае его недоступности — отдельный резервный сервер. Такая архитектура обеспечивает получение актуальной версии данных и надёжность даже при слабом интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Ограничивает время ожидания для этого метода. По истечении таймаута возвращаются кешированные данные или локальный резервный пейвол.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения `loadTimeout`, поскольку операция может включать несколько запросов под капотом.
Для Android: объект `TimeInterval` можно создать с помощью функций-расширений (например, `5.seconds`, где `.seconds` из `import com.adapty.utils.seconds`) или через `TimeInterval.seconds(5)`. Чтобы не ограничивать время ожидания, используйте `TimeInterval.INFINITE`.
| Параметры ответа: | Параметр | Описание | | :-------- | :---------- | | Flow | Объект `AdaptyFlow`, содержащий плейсмент, идентификаторы (`id`, `variationId`), название, Remote Config и флаг `hasViewConfiguration`, указывающий, включает ли флоу конфигурацию отображения. Чтобы получить продукты для предзагрузки, кастомного UI или программных проверок, вызовите `getPaywallProducts(flow)`. | ## Получение конфигурации отображения \{#fetch-the-view-configuration\} После получения флоу или пейвола проверьте, содержит ли он конфигурацию отображения, с помощью `flow.hasViewConfiguration`. Этот флаг показывает, каким способом плейсмент был создан в дашборде Adapty: - **`true`** — плейсмент создан в **Flow Builder** (флоу) или **Paywall Builder** (пейвол). Adapty отрисовывает интерфейс за вас. Продолжайте выполнять шаги ниже, чтобы получить конфигурацию представления и [показать флоу или пейвол](android-present-paywalls). - **`false`** — плейсмент является пользовательским пейволом без интерфейса Builder. [Обработайте его как пейвол с Remote Config](present-remote-config-paywalls-android). :::important Убедитесь, что в Flow Builder включён переключатель **Show on device**. Если эта опция не активирована, конфигурация представления не будет доступна для получения. :::необязательный
по умолчанию: локаль устройства
| Идентификатор [локализации](add-paywall-locale-in-adapty-paywall-builder) в виде языкового кода с одним или двумя подтегами, разделёнными дефисом (например, `en`, `pt-br`). См. [Локализации и коды локалей](android-localizations-and-locale-codes). | | **loadTimeout** | по умолчанию: 5 сек | Ограничивает время ожидания для этого метода. По истечении таймаута возвращаются кешированные данные или локальный резервный вариант. Обратите внимание, что в редких случаях метод может завершиться чуть позже указанного в `loadTimeout` значения, так как операция может включать несколько внутренних запросов. |необязательный
по умолчанию: локаль устройства
| Идентификатор [локализации](add-paywall-locale-in-adapty-paywall-builder) в виде языкового кода с одним или двумя подтегами, разделёнными `-` (например, `en`, `pt-br`). См. [Локализации и коды языков](android-localizations-and-locale-codes). | | **loadTimeout** | по умолчанию: 5 сек | Ограничивает время ожидания для этого метода. Если таймаут истёк, будут возвращены кэшированные данные или локальный резервный вариант. Обратите внимание: в редких случаях метод может завершиться чуть позже указанного в `loadTimeout` значения, поскольку операция может состоять из нескольких запросов под капотом. |По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае сбоя. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кэшированные данные, если они есть. В таком случае пользователи могут получать не самые последние данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кэш сохраняется после перезапуска приложения и очищается только при переустановке или вручную.
| ## Настройка ассетов \{#customize-assets\} Чтобы настроить изображения и видео в своём флоу или пейволе, используйте пользовательские ассеты. Главные изображения и видео имеют предопределённые идентификаторы: `hero_image` и `hero_video`. В бандле пользовательских ассетов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение. Для остальных изображений и видео нужно [задать пользовательский идентификатор](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разное изображение или видео отдельным пользователям. - Показывать локальное превью-изображение, пока загружается основное удалённое изображение. - Показывать превью-изображение перед запуском видео. Вот пример того, как передавать пользовательские ресурсы через простой словарь: ```kotlin showLineNumbers val customAssets = AdaptyCustomAssets.of( "hero_image" to AdaptyCustomImageAsset.remote( url = "https://example.com/image.jpg", preview = AdaptyCustomImageAsset.file( FileLocation.fromAsset("images/hero_image_preview.png"), ) ), "hero_video" to AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), ), ) val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, ) ``` :::note Если ресурс не найден, флоу вернётся к внешнему виду по умолчанию. ::: Для видео можно дополнительно передать `resolution`, чтобы заранее зарезервировать место в макете и задать соотношение сторон (`width / height`) до загрузки видео: ```kotlin showLineNumbers AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), resolution = AdaptyCustomVideoAsset.Resolution(width = 1080, height = 1920), ) ```необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-paywall-locale-in-adapty-paywall-builder). Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` означает английский, `pt-br` — португальский (Бразилия).
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем именно этот вариант — он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad`: при наличии кеша будут возвращаться кешированные данные. В этом сценарии данные могут быть не самыми свежими, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии для сокращения количества сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или ручной очистке.
Adapty SDK хранит пейволы локально в двух слоях: описанный выше регулярно обновляемый кеш и [резервные пейволы](fallback-paywalls). Для ускорения загрузки пейволов также используется CDN, а на случай недоступности CDN — отдельный резервный сервер. Эта система гарантирует, что вы всегда получаете актуальную версию пейволов, сохраняя надёжность даже при нестабильном интернете.
| | **loadTimeout** | по умолчанию: 5 сек |Ограничивает время ожидания для этого метода. По истечении таймаута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения `loadTimeout`, поскольку операция может включать несколько внутренних запросов.
Для Android: создать `TimeInterval` можно с помощью функций-расширений (например, `5.seconds`, где `.seconds` из `import com.adapty.utils.seconds`) или через `TimeInterval.seconds(5)`. Чтобы отключить ограничение, используйте `TimeInterval.INFINITE`.
| Параметры ответа: | Параметр | Описание | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Объект [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) со списком идентификаторов продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение конфигурации отображения пейвола, созданного в Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Убедитесь, что в Paywall Builder включён переключатель **Show on device**. Если эта опция отключена, конфигурация отображения будет недоступна для получения. ::: После получения пейвола проверьте, содержит ли он `ViewConfiguration` — это означает, что он был создан с помощью Paywall Builder. Это подскажет вам, как отображать пейвол. Если `ViewConfiguration` присутствует, обработайте его как пейвол Paywall Builder; если нет — [обработайте его как пейвол с Remote Config](present-remote-config-paywalls).опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается код языка, состоящий из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут получить не самые свежие данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
| ## Настройка ассетов \{#customize-assets\} Чтобы настроить изображения и видео в пейволе, используйте кастомные ассеты. У hero-изображений и видео есть предустановленные ID: `hero_image` и `hero_video`. В пакете кастомных ассетов вы обращаетесь к этим элементам по их ID и настраиваете их поведение. Для остальных изображений и видео нужно [задать кастомный ID](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разные изображения или видео разным пользователям. - Показывать локальное превью, пока загружается основное удалённое изображение. - Показывать превью перед воспроизведением видео. :::important Чтобы использовать эту функцию, обновите Adapty Android SDK до версии 3.7.0 или выше. ::: Вот пример того, как можно передавать пользовательские ресурсы через простой словарь: ```kotlin showLineNumbers val customAssets = AdaptyCustomAssets.of( "hero_image" to AdaptyCustomImageAsset.remote( url = "https://example.com/image.jpg", preview = AdaptyCustomImageAsset.file( FileLocation.fromAsset("images/hero_image_preview.png"), ) ), "hero_video" to AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), ), ) val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, insets, customAssets, ) ``` :::note Если ассет не найден, пейвол вернётся к внешнему виду по умолчанию. :::Insets — это отступы вокруг флоу, которые не дают интерактивным элементам скрываться за системными панелями.
По умолчанию: `Unspecified` — Adapty автоматически подберёт отступы, что отлично работает для edge-to-edge флоу.
Если ваш флоу не является edge-to-edge, возможно, потребуется задать пользовательские отступы. Как это сделать — читайте в разделе [Изменение отступов флоу](android-present-paywalls#change-flow-insets) ниже.
| | **customAssets** | необязательный | Передайте объект `AdaptyCustomAssets`, чтобы заменить изображения и видео во флоу или пейволе во время выполнения. Подробнее см. в разделе [Настройка ресурсов](android-get-pb-paywalls#customize-assets). | | **tagResolver** | необязательный | Используйте `AdaptyUiTagResolver` для обработки пользовательских тегов в тексте флоу. Резолвер принимает тег и возвращает соответствующую строку. Подробнее см. в разделе «Пользовательские теги в Paywall Builder». | | **timerResolver** | необязательный | Передайте резолвер сюда, если планируете использовать пользовательскую функциональность таймера. | :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ## Изменение отступов флоу \{#change-flow-insets\} Отступы — это пространство вокруг флоу, которое не даёт кликабельным элементам скрываться за системными панелями. По умолчанию Adapty автоматически подстраивает отступы, что отлично работает для полноэкранных флоу. Если ваш флоу не занимает весь экран, возможно, вам потребуются собственные отступы: - Если ни строка состояния, ни панель навигации не перекрывают `AdaptyFlowView`, используйте `AdaptyFlowInsets.None`. - Для более тонкой настройки — например, если флоу перекрывается с верхней строкой состояния, но не с нижней панелью — можно задать только `bottomInset` равным `0`, как показано в примере ниже:Отступы вокруг пейвола, которые предотвращают перекрытие интерактивных элементов системными панелями.
По умолчанию: `UNSPECIFIED` — Adapty автоматически подбирает отступы, что отлично работает для пейволов на весь экран.
Если ваш пейвол не занимает весь экран, возможно, вам потребуется задать пользовательские отступы. Подробнее читайте в разделе [Изменение отступов пейвола](android-present-paywalls#change-paywall-insets) ниже.
| | **personalizedOfferResolver** | необязательный | Чтобы указать персонализированную цену ([подробнее](https://developer.android.com/google/play/billing/integrate#personalized-price)), реализуйте `AdaptyUiPersonalizedOfferResolver` и передайте собственную логику, которая возвращает `true` для `AdaptyPaywallProduct` с персонализированной ценой и `false` в противном случае. | | **tagResolver** | необязательный | Используйте `AdaptyUiTagResolver` для обработки пользовательских тегов в тексте пейвола. Резолвер принимает тег и возвращает соответствующую строку. Подробнее см. в разделе «Пользовательские теги в Paywall Builder». | | **timerResolver** | необязательный | Передайте резолвер, если планируете использовать пользовательский таймер. | :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ## Изменение отступов пейвола \{#change-paywall-insets\} Отступы — это пространство вокруг пейвола, которое не даёт интерактивным элементам скрыться за системными панелями. По умолчанию Adapty автоматически подбирает отступы, что отлично работает для пейволов во весь экран. Если ваш пейвол не занимает весь экран, можно задать отступы вручную: - Если ни строка состояния, ни панель навигации не перекрываются с `AdaptyPaywallView`, используйте `AdaptyPaywallInsets.NONE`. - Для более нестандартных случаев, например если пейвол перекрывается с верхней строкой состояния, но не с нижней панелью, можно установить только `bottomInset` в `0`, как показано в примере ниже:
## Число просмотров пейвола слишком велико \{#the-paywall-view-number-is-too-big\}
**Проблема**: счётчик просмотров пейвола показывает вдвое больше ожидаемого значения.
**Причина**: возможно, вы вызываете `logShowFlow` (Android SDK v4+) / `logShowPaywall` в своём коде, что дублирует счётчик просмотров, если вы используете Paywall Builder или Flow Builder. Для флоу и пейволов, созданных с помощью этих инструментов, аналитика отслеживается автоматически, поэтому использовать данный метод не нужно.
**Решение**: убедитесь, что вы не вызываете `logShowFlow` (Android SDK v4+) / `logShowPaywall` в своём коде, если используете Paywall Builder или Flow Builder.
## Другие проблемы \{#other-issues\}
**Проблема**: У вас возникают другие проблемы, связанные с Paywall Builder, не описанные выше.
**Решение**: При необходимости обновите SDK до последней версии, следуя [гайдам по миграции](android-sdk-migration-guides). Многие проблемы уже исправлены в новых версиях SDK.
---
# File: android-quickstart-manual
---
---
title: "Включение покупок в кастомном пейволе в Android SDK"
description: "Интегрируйте Adapty SDK в свои кастомные Android пейволы для поддержки встроенных покупок."
---
В этом гайде описано, как интегрировать Adapty в кастомные пейволы. Вы сохраняете полный контроль над реализацией пейвола, а Adapty SDK берёт на себя получение продуктов, обработку новых покупок и восстановление предыдущих.
:::important
**Этот гайд предназначен для разработчиков, которые реализуют кастомные пейволы.** Если вы хотите подключить покупки самым простым способом, используйте [Adapty Flow Builder](android-quickstart-paywalls). С Flow Builder вы создаёте флоу в визуальном редакторе без кода, Adapty берёт на себя всю логику покупок, а тестировать разные дизайны можно без повторной публикации приложения.
:::
## Перед началом работы \{#before-you-start\}
### Настройка продуктов \{#set-up-products\}
Чтобы включить встроенные покупки, нужно разобраться с тремя ключевыми понятиями:
- [**Продукты**](product) – всё, что пользователи могут купить (подписки, расходуемые покупки, пожизненный доступ)
- [**Пейволы**](paywalls) – конфигурации, определяющие, какие продукты предлагать. В Adapty пейволы — единственный способ получить продукты, но такой подход позволяет менять продукты, цены и офферы без обновления кода приложения.
- [**Плейсменты**](placements) – где и когда показывать пейволы в приложении (например, `main`, `onboarding`, `settings`). Вы настраиваете пейволы для плейсментов в дашборде, а затем запрашиваете их по идентификатору плейсмента в коде. Это упрощает проведение A/B-тестов и показ разных пейволов разным пользователям.
Убедитесь, что вы понимаете эти концепции, даже если используете собственный пейвол. По сути, это просто способ управлять продуктами, которые вы продаёте в приложении.
Чтобы реализовать собственный пейвол, вам нужно создать **пейвол** и добавить его в **плейсмент**. Это позволит вам получать ваши продукты. Чтобы разобраться, что нужно сделать в дашборде, следуйте [quickstart-гайду](quickstart).
### Управление пользователями \{#manage-users\}
Вы можете работать как с серверной аутентификацией, так и без неё.
Adapty SDK по-разному обрабатывает анонимных и идентифицированных пользователей. Прочитайте [гайд по идентификации](android-quickstart-identify), чтобы разобраться в деталях и корректно работать с пользователями.
## Шаг 1. Получите продукты \{#step-1-get-products\}
Чтобы получить продукты для вашего кастомного пейвола, необходимо:
1. Получить объект `flow`, передав ID [плейсмента](placements) в метод `getFlow`.
2. Получить массив продуктов для этого флоу с помощью метода `getPaywallProducts`.
По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае неудачи. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad`: он возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит флоу и пейволы в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](android-use-fallback-paywalls). Также используется CDN для более быстрой загрузки флоу и пейволов, а также отдельный резервный сервер на случай недоступности CDN.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает тайм-аут метода. При его истечении будут возвращены кешированные данные или локальный фолбэк.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения `loadTimeout`, поскольку операция может включать несколько запросов.
| Не задавайте product ID жёстко в коде! Так как флоу настраиваются удалённо, набор доступных продуктов, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код учитывает эти сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать эти 2 продукта. Но если позже вы получите 3 продукта, приложение должно показать все 3 без каких-либо изменений в коде. Единственное, что нужно задать жёстко, — это ID плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Объект `AdaptyFlow`, содержащий плейсмент, идентификаторы (`id`, `variationId`), название, массив `remoteConfigs` (по одной записи на каждую настроенную локаль) и флаг `hasViewConfiguration`. Чтобы получить продукты для флоу, вызовите `getPaywallProducts(flow)`. | :::note В версии v4 параметр `locale` переехал из `getFlow` в `getFlowConfiguration` (используется только при отображении через AdaptyUI). Для кастомных пейволов все доступные локали возвращаются вместе в `flow.remoteConfigs` — выберите ту, которая соответствует языку устройства пользователя или настройке вашего приложения. ::: ## Получение продуктов \{#fetch-products\} Получив флоу, вы можете запросить массив продуктов, соответствующих ему:По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, зато загрузка будет быстрее вне зависимости от качества связи. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при переустановке или вручную.
|необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается в виде языкового кода, состоящего из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](android-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если ваши пользователи часто сталкиваются с нестабильным интернетом, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит пейволы в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](android-use-fallback-paywalls). Для ускорения загрузки пейволов также используется CDN, а в случае его недоступности — отдельный резервный сервер. Такая система гарантирует, что вы всегда получаете актуальную версию пейволов, обеспечивая надёжность даже при слабом интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Ограничивает тайм-аут выполнения метода. По истечении тайм-аута будут возвращены кешированные данные или локальный резервный пейвол.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeout`, поскольку операция может включать несколько запросов под капотом.
| Не прописывайте идентификаторы продуктов в коде! Поскольку пейволы настраиваются удалённо, набор доступных продуктов, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться. Убедитесь, что ваш код учитывает эти сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать 2 продукта. Но если позже вы получите 3 продукта, приложение должно показать все 3 — без каких-либо изменений в коде. Единственное, что нужно прописать в коде, — это идентификатор плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Объект [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) содержит: список идентификаторов продуктов, идентификатор пейвола, Remote Config и ряд других свойств. | ## Получение продуктов \{#fetch-products\} Получив пейвол, вы можете запросить список продуктов, связанных с ним:опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается языковой код, состоящий из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию — в разделе [Локализации и коды локалей](android-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильный интернет, рассмотрите использование `.returnCacheDataElseLoad` для возврата кешированных данных при их наличии. В этом случае данные могут быть не самыми свежими, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
|В случае успешного запроса ответ содержит этот объект. Объект [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/) предоставляет исчерпывающую информацию об уровнях доступа, подписках и разовых покупках пользователя в приложении.
Проверьте статус уровня доступа, чтобы определить, есть ли у пользователя необходимый доступ к приложению.
| :::warning **Примечание:** если вы используете Apple StoreKit версии ниже 2.0 и Adapty SDK версии ниже 2.9.0, вам необходимо указать [общий секрет Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret) вместо этого. Данный метод в настоящее время устарел и не рекомендуется Apple. ::: ## Смена подписки при покупке \{#change-subscription-when-making-a-purchase\} Когда пользователь выбирает новую подписку вместо продления текущей, поведение зависит от стора. В Google Play подписка не обновляется автоматически — вам нужно обработать переключение в коде мобильного приложения, как описано ниже. Чтобы заменить подписку другой на Android, вызовите метод `.makePurchase()` с дополнительным параметром:Объект [`AdaptyProfile`](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). Содержит информацию об уровнях доступа, подписках и разовых покупках.
Проверьте **статус уровня доступа**, чтобы определить, есть ли у пользователя доступ к приложению.
| :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: --- # File: implement-observer-mode-android --- --- title: "Реализация режима Observer в Android SDK" description: "Реализуйте режим Observer в Adapty для отслеживания событий подписки пользователей в Android SDK." --- Если у вас уже есть собственная инфраструктура для покупок и вы не готовы полностью переходить на Adapty, вы можете воспользоваться [режимом Observer](observer-vs-full-mode). В базовом варианте режим Observer обеспечивает расширенную аналитику и бесшовную интеграцию с системами атрибуции и аналитики. Если это вам подходит, нужно сделать всего два шага: 1. Включить его при настройке Adapty SDK, установив параметр `observerMode` в `true`. Следуйте инструкциям по настройке для [Android](sdk-installation-android#activate-adapty-module-of-adapty-sdk). 2. [Передать транзакции](report-transactions-observer-mode-android) из вашей существующей инфраструктуры покупок в Adapty. ## Настройка режима Observer \{#observer-mode-setup\} Включите режим Observer, если вы самостоятельно обрабатываете покупки и управляете статусом подписки, а Adapty используете только для отправки событий подписки и аналитики. :::important В режиме Observer Adapty SDK не закрывает транзакции, поэтому убедитесь, что вы обрабатываете их самостоятельно. :::1. Реализуйте `AdaptyUiObserverModeHandler`. Событие `onPurchaseInitiated` сообщает о том, что пользователь инициировал покупку. В ответ на этот коллбэк вы можете запустить собственный флоу покупки:
1. Реализуйте `AdaptyUiObserverModeHandler`. Событие `onPurchaseInitiated` уведомит вас о том, что пользователь инициировал покупку. В ответ на этот колбэк вы можете запустить свой кастомный флоу покупки:
Для iOS, StoreKit 1: объект [`SKPaymentTransaction`](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Для iOS, StoreKit 2: объект [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Для Android: строковый идентификатор (`purchase.getOrderId()`) покупки, где покупка является экземпляром класса [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) из библиотеки биллинга.
|Для iOS, StoreKit 1: объект [`SKPaymentTransaction`](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Для iOS, StoreKit 2: объект [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Для Android: строковый идентификатор (`purchase.getOrderId()`) покупки, где покупка — экземпляр класса [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) из библиотеки биллинга.
| Для полноэкранного режима, в котором системные панели перекрывают часть интерфейса, получайте отступы следующим образом:phoneNumber
firstName
lastName
| String | | gender | Enum, допустимые значения: `female`, `male`, `other` | | birthday | Date | ### Пользовательские атрибуты \{#custom-user-attributes\} Вы можете задавать собственные атрибуты, обычно связанные с использованием вашего приложения. Например, для фитнес-приложений это может быть количество тренировок в неделю, а для приложений по изучению языков — уровень знаний пользователя. Такие атрибуты можно использовать в сегментах для создания таргетированных пейволов и офферов, а также в аналитике для выявления продуктовых метрик, которые больше всего влияют на выручку.Объект [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). Как правило, для определения наличия у пользователя премиум-доступа достаточно проверить только статус уровня доступа профиля.
Метод `.getProfile` возвращает наиболее актуальные данные, поскольку всегда пытается обратиться к API. Если по какой-либо причине (например, из-за отсутствия интернета) SDK Adapty не может получить данные с сервера, возвращаются данные из кэша. Важно также отметить, что SDK Adapty регулярно обновляет кэш `AdaptyProfile`, чтобы поддерживать информацию в актуальном состоянии.
| Метод `.getProfile()` возвращает профиль пользователя, из которого можно получить статус уровня доступа. В приложении может быть несколько уровней доступа. Например, в новостном приложении с независимыми подписками на разные тематики можно создать уровни доступа «sports» и «science». Однако в большинстве случаев достаточно одного уровня доступа — тогда можно просто использовать уровень доступа «premium» по умолчанию. Вот пример проверки уровня доступа «premium» по умолчанию:опциональный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Пример: `en` — английский, `pt-br` — португальский (Бразилия).
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если ваши пользователи часто работают при нестабильном интернете, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кешированные данные при их наличии. В этом случае пользователи могут получить не самые последние данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии для сокращения сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или ручной очистке.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные онбординги. Также используется CDN для ускорения загрузки онбордингов и отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает получение последней версии онбордингов при надёжной работе даже при нестабильном интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Ограничивает время ожидания для данного метода. По истечении таймаута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения `loadTimeout`, так как операция может включать несколько запросов под капотом.
Для Android: создать `TimeInterval` можно с помощью функций-расширений (например, `5.seconds`, где `.seconds` берётся из `import com.adapty.utils.seconds`) или `TimeInterval.seconds(5)`. Чтобы снять ограничение, используйте `TimeInterval.INFINITE`.
| Параметры ответа: | Параметр | Описание | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Объект [`AdaptyOnboarding`](https://android.adapty.io/adapty/com.adapty.models/-adapty-onboarding/) со следующими полями: идентификатор и конфигурация онбординга, Remote Config и ряд других свойств. | ## Ускорьте загрузку онбординга с помощью онбординга для аудитории по умолчанию \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Как правило, онбординги загружаются почти мгновенно, так что беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и онбордингов, а пользователи работают с медленным интернетом, загрузка онбординга может занять дольше, чем хотелось бы. В таких случаях имеет смысл показывать онбординг по умолчанию — это обеспечит плавный пользовательский опыт вместо полного отсутствия онбординга. Чтобы решить эту проблему, воспользуйтесь методом `getOnboardingForDefaultAudience`, который получает онбординг указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать онбординг через метод `getOnboarding`, как описано в разделе [Получение онбординга](#fetch-onboarding) выше. :::warning Рекомендуем использовать `getOnboarding` вместо `getOnboardingForDefaultAudience`, так как у последнего есть существенные ограничения: - **Проблемы совместимости**: могут возникнуть при поддержке нескольких версий приложения — придётся либо делать обратно совместимые дизайны, либо мириться с некорректным отображением в старых версиях. - **Без персонализации**: показывает контент только для аудитории «All Users», то есть таргетинг по стране, атрибуции или пользовательским атрибутам недоступен. Если для вашего случая скорость загрузки важнее этих недостатков, используйте `getOnboardingForDefaultAudience`, как показано ниже. В противном случае используйте `getOnboarding`, как описано [выше](#fetch-onboarding). ::: ```kotlin Adapty.getOnboardingForDefaultAudience("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val onboarding = result.value // Handle successful onboarding retrieval } is AdaptyResult.Error -> { val error = result.error // Handle error case } } } ``` Параметры: | Параметр | Наличие | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указываете при создании плейсмента в дашборде Adapty. | | **locale** |необязательный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локализации и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, зато время загрузки будет меньше вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные онбординги. Для более быстрой загрузки мы также используем CDN и отдельный резервный сервер на случай недоступности CDN. Эта система гарантирует, что вы всегда получаете актуальную версию онбордингов, обеспечивая надёжность даже при нестабильном интернет-соединении.
| --- # File: android-present-onboardings --- --- title: "Отображение онбордингов в Android SDK" description: "Узнайте, как отображать онбординги на Android для эффективного вовлечения пользователей." --- :::tip **Начиная с SDK v4**, вы можете использовать [флоу](android-get-pb-paywalls) как более мощную альтернативу онбордингам. В отличие от онбордингов, которые работают внутри WebView, флоу рендерятся нативно на устройстве — это обеспечивает плавную анимацию, привычный внешний вид Android, быструю загрузку и отсутствие зависимости от WebView. Подробнее: [Получение флоу и пейволов](android-get-pb-paywalls) и [Отображение флоу и пейволов](android-present-paywalls). ::: Прежде чем начать, убедитесь, что: 1. Вы установили [Adapty Android SDK](sdk-installation-android) версии 3.8.0 или выше. 2. Вы [создали онбординг](create-onboarding). 3. Вы добавили онбординг в [плейсмент](placements). Если вы настроили онбординг с помощью Onboarding Builder, вам не нужно беспокоиться о его рендеринге в коде мобильного приложения для отображения пользователю. Такой онбординг содержит как то, что должно быть показано, так и то, как это должно быть показано. Чтобы отобразить визуальный онбординг на экране устройства, его необходимо сначала настроить. Для этого вызовите метод `AdaptyUI.getOnboardingView()` или создайте `OnboardingView` напрямую:
Например, если пользователь нажмёт кастомную кнопку — скажем, **Login** или **Allow notifications**, — будет вызван метод делегата `onCustomAction` с ID действия из билдера. Вы можете задавать собственные ID, например "allowNotifications".
```kotlin showLineNumbers
class YourActivity : AppCompatActivity() {
private val eventListener = object : AdaptyOnboardingEventListener {
override fun onCustomAction(action: AdaptyOnboardingCustomAction, context: Context) {
when (action.actionId) {
"allowNotifications" -> {
// Request notification permissions
}
}
}
override fun onError(error: AdaptyOnboardingError, context: Context) {
// Handle errors
}
// ... other required delegate methods
}
}
```
JSON резервного пейвола некорректен.
Исправьте дефолтный английский пейвол, затем замените некорректные локальные пейволы. Подробнее об исправлении пейвола — в разделе [Настройка пейвола с помощью Remote Config](customize-paywall-with-remote-config), о замене локальных пейволов — в разделе [Определение резервных пейволов](fallback-paywalls).
| |CURRENT_SUBSCRIPTION_TO_UPDATE
\_NOT_FOUND_IN_HISTORY
| Исходная подписка, которую нужно заменить, не найдена в активных подписках. | | [BILLING_SERVICE_TIMEOUT](https://developer.android.com/google/play/billing/errors#service_timeout_error_code_-3) | Запрос достиг максимального таймаута до того, как Google Play успел ответить. Причиной может быть, например, задержка при выполнении действия, запрошенного вызовом Play Billing Library. | | [FEATURE_NOT_SUPPORTED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#FEATURE_NOT_SUPPORTED()) | Запрошенная функция не поддерживается Play Store на данном устройстве. | | [BILLING_SERVICE_DISCONNECTED](https://developer.android.com/google/play/billing/errors#service_disconnected_error_code_-1) | Соединение клиентского приложения с сервисом Google Play Store через `BillingClient` разорвано. | | [BILLING_SERVICE_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#service_unavailable_error_code_2) | Сервис Google Play Billing в данный момент недоступен. В большинстве случаев причиной является проблема с сетевым соединением между клиентским устройством и серверами Google Play Billing. | | [BILLING_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) |Ошибка биллинга в процессе покупки. Возможные причины:
1. Приложение Play Store на устройстве отсутствует или устарело.
2. Пользователь находится в неподдерживаемой стране.
3. Пользователь входит в корпоративный аккаунт, в котором администратор отключил покупки.
4. Google Play не смог списать средства со способа оплаты пользователя (например, истёк срок действия карты).
5. Пользователь не авторизован в приложении Play Store.
| | [DEVELOPER_ERROR](https://developer.android.com/google/play/billing/errors#developer_error) | API используется некорректно. | | [BILLING_ERROR](https://developer.android.com/google/play/billing/errors#error_error_code_6) | Внутренняя ошибка самого Google Play. | | [ITEM_ALREADY_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_ALREADY_OWNED()) | Продукт уже куплен. | | [ITEM_NOT_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_NOT_OWNED()) | Запрошенное действие с товаром не выполнено, так как он не принадлежит пользователю. | | [BILLING_NETWORK_ERROR](https://developer.android.com/google/play/billing/errors#network_error_error_code_12) | Проблема с сетевым соединением между устройством и серверами Play. | | NO_PRODUCT_IDS_FOUND |Ни один из продуктов пейвола недоступен в сторе.
Если вы столкнулись с этой ошибкой, выполните следующие шаги:
Если код истёк до того, как вы авторизовались, или если вы нажали **Deny**, запустите команду снова, чтобы начать процесс заново:
```bash
adapty auth login
```
## Управление аутентификацией \{#manage-authentication\}
### Проверка статуса аутентификации \{#check-authentication-status\}
Чтобы узнать текущий статус аутентификации, выполните:
```bash
adapty auth status
```
При успешной аутентификации вывод показывает ваш email, маскированный префикс токена и путь к локальному конфигурационному файлу:
```
Email: you@example.com
Token: abcd1234****
Config: ~/.config/adapty/config.json
```
Если вы не аутентифицированы:
```
Not authenticated. Run `adapty auth login`.
```
### Проверка токена \{#verify-your-token\}
Чтобы убедиться, что токен действителен, и посмотреть данные аккаунта, выполните:
```bash
adapty auth whoami
```
В отличие от `adapty auth status`, эта команда делает живой запрос к серверу для проверки токена.
### Выход \{#log-out\}
Чтобы удалить сохранённые учётные данные локально, выполните:
```bash
adapty auth logout
```
Это очистит `~/.config/adapty/config.json`. Токен останется действительным на стороне сервера до истечения срока действия — если нужно немедленно его аннулировать, используйте `adapty auth revoke`.
### Отзыв токена \{#revoke-your-token\}
Чтобы аннулировать токен на сервере и удалить его локально, выполните:
```bash
adapty auth revoke
```
Используйте это, когда нужно полностью аннулировать токен — например, если ваши учётные данные могли быть скомпрометированы. После отзыва запустите `adapty auth login` для повторной аутентификации.
## Ошибки токена \{#token-errors\}
Если токен отозван или стал недействительным, команды CLI возвращают ошибку 401. Чтобы пройти аутентификацию заново, выполните:
```bash
adapty auth login
```
---
# File: developer-cli-reference
---
---
title: "Полный справочник по Adapty Developer CLI"
description: "Полный справочник по всем командам Adapty Developer CLI."
---
:::link
Используете ИИ-ассистент? Доступен [навык Adapty CLI](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) для работы с CLI через LLM.
:::
В этой статье перечислены все команды Adapty CLI с их аргументами, флагами и допустимыми значениями.
:::link
Для настройки аутентификации и управления токенами см. [Аутентификация](developer-cli-authentication).
:::
## Глобальные флаги \{#global-flags\}
Эти флаги доступны для всех команд.
| Флаг | Описание |
|---|---|
| `--json` | Вывод в формате JSON вместо форматированного текста |
| `--help` | Показать справку по команде |
Все команды `list` также принимают флаги пагинации:
| Флаг | По умолчанию | Описание |
|---|---|---|
| `--page` | `1` | Номер страницы |
| `--page-size` | `20` | Элементов на странице (макс.: 100) |
## Приложения \{#apps\}
Управляйте приложениями в вашем аккаунте Adapty. Для настройки через дашборд см. [App settings](general).
### adapty apps list
Вывести список всех приложений в вашем аккаунте Adapty.
```bash
adapty apps list
```
Принимает [флаги пагинации](#global-flags).
### adapty apps get
Получить сведения о конкретном приложении.
```bash
adapty apps get
:::note Для отслеживания событий подписки используйте интеграцию [Webhook](webhook) в Adapty или интегрируйтесь напрямую с вашим существующим сервисом. ::: ::: ## Случай 1: синхронизация подписчиков между вебом и мобильным приложением \{#case-1-sync-subscribers-between-web-and-mobile\} Если вы используете веб-провайдеры платежей, например Stripe, ChargeBee или другие, вы можете легко синхронизировать своих подписчиков. Вот как это сделать: 1.
Adapty profile ID пользователя. Отображается в поле **Adapty ID** на странице [Adapty Dashboard -> **Profiles**](https://app.adapty.io/profiles/users) -> конкретный профиль.
Взаимозаменяем с **adapty-customer-user-id** — используйте любой из них.
| | **adapty-customer-user-id** |ID пользователя в вашей системе. Отображается в поле **Customer user ID** на странице [Adapty Dashboard -> **Profiles**](https://app.adapty.io/profiles/users) -> конкретный профиль.
Взаимозаменяем с **adapty-profile-id** — используйте любой из них.
⚠️ Работает только если вы
### В момент входа или регистрации \{#during-loginsignup\}
Если вы идентифицируете пользователей после запуска приложения (например, после входа в аккаунт или регистрации), используйте метод `identify`, чтобы задать их customer user ID.
- Если вы **раньше не использовали этот customer user ID**, Adapty автоматически привяжет его к текущему профилю.
- Если вы **уже использовали этот customer user ID для идентификации пользователя**, Adapty переключится на работу с профилем, связанным с этим customer user ID.
:::tip
При создании customer user ID сохраните его вместе с данными пользователя, чтобы отправлять тот же ID при входе с новых устройств или переустановке приложения.
:::
Всегда используйте `await` для `identify` перед вызовом других методов SDK. Конкурентные вызовы приводят к ошибке `#3006 profileWasChanged` или обращаются к анонимному профилю. См. [Порядок вызовов в Capacitor SDK](capacitor-sdk-call-order).
```typescript showLineNumbers
try {
await adapty.identify({ customerUserId: "YOUR_USER_ID" });
// successfully identified
} catch (error) {
// handle the error
}
```
### При активации SDK \{#during-the-sdk-activation\}
Если вы уже знаете customer user ID на момент активации SDK, можно передать его сразу в методе `activate` — тогда отдельно вызывать `identify` не нужно.
Если customer user ID известен, но вы задаёте его только после активации, при инициализации Adapty создаст новый пустой профиль и переключится на существующий только после вызова `identify`.
Вы можете передать как существующий customer user ID (тот, что использовался раньше), так и новый. Если передать новый, созданный при активации профиль автоматически привяжется к этому customer user ID.
:::tip
Чтобы исключить созданные пустые профили из аналитики дашборда, перейдите в **App settings** и настройте [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```typescript showLineNumbers
await adapty.activate({
apiKey: "YOUR_PUBLIC_SDK_KEY",
params: {
customerUserId: "YOUR_USER_ID"
}
});
```
### Выход пользователей из системы \{#log-users-out\}
Если в приложении есть кнопка выхода, используйте метод `logout`. При этом для пользователя создаётся новый анонимный ID профиля.
```typescript showLineNumbers
try {
await adapty.logout();
// successful logout
} catch (error) {
// handle the error
}
```
:::info
Для повторного входа пользователя в приложение используйте метод `identify`.
:::
### Разрешение покупок без входа в систему \{#allow-purchases-without-login\}
Если пользователи могут совершать покупки как до, так и после входа в приложение, никаких дополнительных настроек не требуется:
Вот как это работает:
1. Когда незалогиненный пользователь совершает покупку, Adapty привязывает её к анонимному идентификатору профиля.
2. Когда пользователь входит в аккаунт, Adapty переключается на работу с его идентифицированным профилем.
- Если customer user ID уже существует (уже привязан к профилю), Adapty автоматически синхронизирует транзакции.
- Если customer user ID новый (например, покупка была сделана до регистрации), Adapty присваивает его текущему профилю, сохраняя всю историю покупок.
---
# File: adapty-sdk-integration-skill-capacitor
---
---
title: "Интеграция Adapty в приложение Capacitor с помощью навыка SDK integration"
description: "Используйте навык adapty-sdk-integration для сквозной интеграции SDK Adapty в ваше приложение Capacitor с помощью AI-инструмента для написания кода."
---
[Скилл adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) автоматизирует интеграцию Adapty от начала до конца: настройку дашборда, установку SDK, пейвол и проверку на каждом этапе. Он автоматически определяет вашу платформу и подгружает нужную документацию Adapty на каждом шаге.
**Поддерживаемые инструменты**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Для установки выберите команду для своего инструмента. Полный список — в [README скилла](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex или любой другой инструмент** — используйте [skills CLI](https://skills.sh) (обратите внимание, что скиллы, установленные таким способом, не обновляются автоматически):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Либо клонируйте репозиторий и скопируйте `skills/adapty-sdk-integration/` в директорию скиллов вашего инструмента.
После установки запустите скилл в вашем проекте:
```
/adapty-sdk-integration
```
Скилл задаст несколько вопросов по настройке, а затем проведёт через настройку дашборда, установку SDK, пейвол и проверку.
:::important
Навык находится в бета-версии. Если он зависнет или будет вести себя неожиданно, воспользуйтесь [пошаговым гайдом по интеграции](adapty-cursor-capacitor) — он проведёт ваш AI-инструмент через каждый этап с нужной документацией.
:::
[Скилл adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) автоматизирует интеграцию Adapty от начала до конца: настройку дашборда, установку SDK, пейвол и проверку на каждом этапе. Он автоматически определяет вашу платформу и подгружает нужную документацию Adapty на каждом шаге.
**Поддерживаемые инструменты**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Для установки выберите команду для своего инструмента. Полный список — в [README скилла](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex или любой другой инструмент** — используйте [skills CLI](https://skills.sh) (обратите внимание, что скиллы, установленные таким способом, не обновляются автоматически):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Либо клонируйте репозиторий и скопируйте `skills/adapty-sdk-integration/` в директорию скиллов вашего инструмента.
После установки запустите скилл в вашем проекте:
```
/adapty-sdk-integration
```
Скилл задаст несколько вопросов по настройке, а затем проведёт через настройку дашборда, установку SDK, пейвол и проверку.
---
# File: adapty-cursor-capacitor
---
---
title: "Интеграция Adapty в Capacitor-приложение с помощью ИИ"
description: "Пошаговый гайд по интеграции Adapty в Capacitor-приложение с использованием Cursor, Context7, ChatGPT, Claude и других ИИ-инструментов."
---
Этот гайд поможет вам шаг за шагом интегрировать Adapty в ваше Capacitor-приложение с помощью инструмента AI-кодинга — нужно лишь подавать ему нужную документацию Adapty в правильном порядке.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Перед началом: настройка дашборда \{#before-you-start-dashboard-setup\}
Adapty требует предварительной настройки дашборда перед написанием кода SDK. Это можно сделать с помощью интерактивного LLM-навыка или вручную через дашборд.
### Подход с использованием skill (рекомендуется) \{#skill-approach-recommended\}
Skill Adapty CLI позволяет вашему LLM настраивать приложение, продукты, уровни доступа, пейволы и плейсменты напрямую — без необходимости открывать дашборд на каждом шаге. Вам нужно только [подключить сторы](integrate-payments) в дашборде.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
После добавления skill запустите `/adapty-cli` в вашем агенте. Он проведёт вас через каждый шаг — включая момент, когда нужно открыть дашборд для подключения сторов.
### Подход через дашборд \{#dashboard-approach\}
Если вы предпочитаете настраивать всё вручную, вот что нужно сделать до написания кода. Ваша языковая модель не сможет найти значения из дашборда — их нужно предоставить самостоятельно.
1. **Подключите сторы**: В дашборде Adapty перейдите в **App settings → General**. Подключите App Store и Google Play, если ваше приложение на Capacitor поддерживает обе платформы. Это обязательно для работы покупок.
[Подключить сторы](integrate-payments)
2. **Скопируйте публичный SDK-ключ**: В дашборде Adapty перейдите в **App settings → General** и найдите раздел **API keys**. В коде это строка, которую вы передаёте в `adapty.activate()`.
3. **Создайте хотя бы один продукт**: В дашборде Adapty перейдите на страницу **Products**. Ссылаться на продукты напрямую в коде не нужно — Adapty передаёт их через пейволы.
[Добавить продукты](quickstart-products)
4. **Создайте пейвол и плейсмент**: В дашборде Adapty создайте пейвол на странице **Paywalls**, затем привяжите его к плейсменту на странице **Placements**. В коде идентификатор плейсмента — это строка, которую вы передаёте в `adapty.getFlow()`.
[Создать пейвол](quickstart-paywalls)
5. **Настройте уровни доступа**: В дашборде Adapty настройте каждый продукт на странице **Products**. В коде строка проверяется как `profile.accessLevels['premium']?.isActive`. Уровень доступа `premium` по умолчанию подходит большинству приложений. Если платящие пользователи получают доступ к разным функциям в зависимости от продукта (например, план `basic` и план `pro`), [создайте дополнительные уровни доступа](assigning-access-level-to-a-product) до начала разработки.
:::tip
Когда у вас есть все пять элементов, можно приступать к написанию кода. Скажите своему LLM: «Мой публичный SDK-ключ — X, мой ID плейсмента — Y» — и он сгенерирует правильный код инициализации и получения флоу.
:::
### Настройте, когда будете готовы \{#set-up-when-ready\}
Это не обязательно для начала разработки, но пригодится по мере развития интеграции:
- **A/B-тесты**: Настраиваются на странице **Placements**. Изменения кода не требуются.
[A/B-тесты](ab-tests)
- **Дополнительные пейволы и плейсменты**: Добавьте больше вызовов `getPaywall` с разными идентификаторами плейсментов.
- **Интеграции аналитики**: Настраиваются на странице **Integrations**. Процесс настройки зависит от интеграции. См. [интеграции аналитики](analytics-integration) и [интеграции атрибуции](attribution-integration).
## Загрузите документацию Adapty в свою LLM \{#feed-adapty-docs-to-your-llm\}
### Используйте Context7 (рекомендуется) \{#use-context7-recommended\}
[Context7](https://context7.com) — это MCP-сервер, который даёт вашей LLM прямой доступ к актуальной документации Adapty. LLM автоматически подтягивает нужные доки в зависимости от вашего запроса — никакого ручного копирования ссылок.
Context7 работает с **Cursor**, **Claude Code**, **Windsurf** и другими MCP-совместимыми инструментами. Для настройки выполните:
```
npx ctx7 setup
```
Команда определит ваш редактор и настроит сервер Context7. Для ручной настройки см. [репозиторий Context7 на GitHub](https://github.com/upstash/context7).
После настройки обращайтесь к библиотеке Adapty в своих промптах:
```
Use the adaptyteam/adapty-docs library to look up how to install the Capacitor SDK
```
:::warning
Несмотря на то что Context7 избавляет от необходимости вставлять ссылки на документацию вручную, порядок внедрения имеет значение. Следуйте [пошаговому руководству по внедрению](#implementation-walkthrough) ниже — шаг за шагом, чтобы всё работало корректно.
:::
### Используйте документацию в виде обычного текста \{#use-plain-text-docs\}
Любую страницу документации Adapty можно получить в виде обычного текста Markdown. Для этого добавьте `.md` в конец URL или нажмите **Copy for LLM** под заголовком статьи. Например: [adapty-cursor-capacitor.md](https://adapty.io/docs/ru/adapty-cursor-capacitor.md).
Каждый этап [пошагового руководства по интеграции](#implementation-walkthrough) ниже содержит блок «Отправьте это в свой LLM» со ссылками `.md` для копирования.
Чтобы получить сразу несколько страниц документации, воспользуйтесь [индексными файлами и наборами для конкретных платформ](#plain-text-doc-index-files) ниже.
## Пошаговая реализация \{#implementation-walkthrough\}
Дальше в этом гайде — интеграция Adapty в порядке реализации. Для каждого этапа указаны документы, которые нужно передать LLM, что должно получиться в итоге и типичные проблемы.
### Планирование интеграции \{#plan-your-integration\}
Прежде чем переходить к коду, попросите LLM проанализировать ваш проект и составить план реализации. Если ваш AI-инструмент поддерживает режим планирования (например, план-режим в Cursor или Claude Code), используйте его — так LLM сможет изучить структуру вашего проекта и документацию Adapty до написания кода.
Укажите LLM, какой подход к покупкам вы используете — от этого зависит, какие гайды ему нужно применять:
- [**Adapty Flow Builder**](adapty-flow-builder): Вы создаёте флоу в визуальном редакторе Adapty, а SDK отображает их автоматически.
- [**Вручную созданные пейволы**](capacitor-making-purchases): Вы сами строите UI пейвола в коде, но используете Adapty для получения продуктов и обработки покупок.
- [**Режим Observer**](observer-vs-full-mode): Вы сохраняете существующую инфраструктуру покупок и используете Adapty только для аналитики и интеграций.
Не знаете, что выбрать? Прочитайте [таблицу сравнения в быстром старте](capacitor-quickstart-paywalls).
### Установка и настройка SDK \{#install-and-configure-the-sdk\}
Добавьте зависимость Adapty SDK через npm и активируйте её с помощью публичного ключа SDK. Это основа — без неё ничто остальное работать не будет.
**Гайд:** [Установка и настройка Adapty SDK](sdk-installation-capacitor)
:::info
Это руководство описывает Adapty Capacitor SDK v4 (beta) — API, с которым работает [quickstart](capacitor-quickstart-paywalls). v4 — предрелизная версия, поэтому убедитесь, что ваш LLM указывает точную версию (`npm install @adapty/capacitor@4.0.0-beta.2`), а не устанавливает последнюю стабильную 3.x. См. [раздел установки SDK 4.0](sdk-installation-capacitor#adapty-sdk-40-beta) и [руководство по миграции](migration-to-capacitor-sdk-v4).
:::
Отправьте это в свой LLM:
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/ru/sdk-installation-capacitor.md
```
:::tip[Checkpoint]
- **Ожидаемый результат:** Приложение собирается и запускается на iOS и Android. В консоли отображается лог активации Adapty.
- **Частая проблема:** «Public API key is missing» → проверьте, что заменили плейсхолдер реальным ключом из **App settings**.
:::
### Показ пейволов и обработка покупок \{#show-paywalls-and-handle-purchases\}
Получите пейвол по ID плейсмента, отобразите его и обработайте события покупок. Нужные вам гайды зависят от того, как вы обрабатываете покупки.
Тестируйте каждую покупку в песочнице по мере работы — не откладывайте это на конец. Инструкции по настройке см. в разделе [Тестирование покупок в песочнице](test-purchases-in-sandbox).
Передаётся внутри опционального объекта `params`. По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если вы считаете, что у ваших пользователей нестабильный интернет, рассмотрите использование `'return_cache_data_else_load'` — тогда кеш будет возвращаться, если он существует. В этом случае пользователи могут не получить самые последние данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии во избежание лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при переустановке или вручную.
Adapty SDK хранит пейволы локально в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Для более быстрой загрузки пейволов также используется CDN, а при недоступности CDN — отдельный резервный сервер. Такая система гарантирует, что вы всегда получаете актуальную версию пейволов, обеспечивая надёжность даже при слабом интернет-соединении.
| | **loadTimeoutMs** | по умолчанию: 5 сек |Передаётся внутри опционального объекта `params`. Это значение ограничивает тайм-аут данного метода. По истечении тайм-аута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeoutMs`, поскольку операция может включать несколько запросов под капотом.
| **Не хардкодьте идентификаторы продуктов.** Единственный ID, который стоит хардкодить, — это ID плейсмента. Флоу и пейволы настраиваются удалённо, поэтому количество продуктов и доступных офферов может меняться в любой момент. Ваше приложение должно обрабатывать эти изменения динамически: если сегодня пейвол возвращает два продукта, а завтра три — отображайте все без изменений в коде. Параметры ответа: | Параметр | Описание | | :-------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | Объект `AdaptyFlow` с идентификаторами флоу (`id`, `variationId`), названием, плейсментом, вариантами пейволов (`paywalls`) и Remote Config (`remoteConfigs`). | ## Получение конфигурации представления \{#fetch-the-view-configuration\} :::important Убедитесь, что в билдере включён переключатель **Show on device**. Если эта опция отключена, конфигурация представления не будет доступна для получения. ::: Если плейсмент создан в **Flow Builder** или **Paywall Builder**, Adapty самостоятельно отрисовывает UI. Создайте представление с помощью `createFlowView`, затем [покажите флоу или пейвол](capacitor-present-paywalls). Если плейсмент — это кастомный пейвол без UI в билдере, [обработайте его как пейвол с Remote Config](present-remote-config-paywalls-capacitor). В Capacitor SDK вызывайте `createFlowView` напрямую — предварительно получать конфигурацию представления не нужно. :::warning Результат метода `createFlowView` можно использовать только один раз. Если он понадобится снова, вызовите `createFlowView` заново. Повторный вызов без пересоздания может привести к ошибке. ::: ```typescript showLineNumbers try { const view = await createFlowView(flow); } catch (error) { // handle the error } ``` Параметры: | Параметр | Наличие | Описание | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | обязательный | Объект `AdaptyFlow` для получения контроллера нужного флоу/пейвола. | | **customTags** | необязательный | Словарь пользовательских тегов и их значений. Теги служат плейсхолдерами в контенте и динамически заменяются конкретными строками для персонализации контента во флоу/пейволе. Подробнее см. в разделе о пользовательских тегах в Paywall Builder. | | **prefetchProducts** | необязательный | Включите для оптимизации времени отображения продуктов на экране. При значении `true` AdaptyUI автоматически загружает нужные продукты. По умолчанию: `true`. | | **android.enableSafeArea** | необязательный | Только для Android (игнорируется на iOS). Указывается в ключе `android`. При значении `true` представление флоу применяет отступы безопасной зоны. По умолчанию: `true`. Значение по умолчанию подходит для большинства случаев. | :::note Если вы используете несколько языков, узнайте, как добавить [локализацию флоу](add-paywall-locale-in-adapty-paywall-builder) и как правильно использовать коды локалей [здесь](capacitor-localizations-and-locale-codes). ::: Когда вью готово, [отобразите флоу/пейвол](capacitor-present-paywalls). ## Получите флоу или пейвол для дефолтной аудитории, чтобы загрузить его быстрее \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} Как правило, флоу и пейволы загружаются практически мгновенно, так что беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и плейсментов, а пользователи работают при слабом интернет-соединении, загрузка флоу или пейвола может занять больше времени, чем хотелось бы. В таких ситуациях имеет смысл показывать дефолтный флоу или пейвол, чтобы обеспечить комфортный пользовательский опыт вместо пустого экрана. Чтобы решить эту проблему, можно воспользоваться методом `getFlowForDefaultAudience`, который получает флоу или пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать флоу или пейвол с помощью метода `getFlow`, как описано в разделе [Получение флоу/пейвола](#fetch-flowpaywall) выше. :::warning Почему мы рекомендуем использовать `getFlow` Метод `getFlowForDefaultAudience` имеет ряд существенных недостатков: - **Потенциальные проблемы с обратной совместимостью**: если вам нужно показывать разные пейволы для разных версий приложения (текущей и будущих), могут возникнуть сложности. Придётся либо проектировать пейволы с поддержкой текущей (устаревшей) версии, либо смириться с тем, что пользователи этой версии могут столкнуться с проблемами при отображении пейволов. - **Потеря таргетинга**: все пользователи будут видеть один и тот же пейвол, настроенный для аудитории **All Users**, — а значит, вы теряете персонализированный таргетинг (в том числе по странам, маркетинговой атрибуции или собственным пользовательским атрибутам). Если вы готовы принять эти недостатки ради более быстрого получения флоу или пейвола, используйте метод `getFlowForDefaultAudience` следующим образом. В противном случае используйте `getFlow`, описанный [выше](#fetch-flowpaywall). ::: ```typescript showLineNumbers try { const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', }); // the requested flow/paywall } catch (error) { // handle the error } ``` | Параметр | Наличие | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **fetchPolicy** | по умолчанию: `'reload_revalidating_cache_data'` |Передаётся внутри необязательного объекта `params`. По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `'return_cache_data_else_load'` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут получить не самые последние данные, зато загрузка будет быстрее вне зависимости от качества связи. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии для снижения количества сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при переустановке или вручную.
| ## Настройка ресурсов \{#customize-assets\} Чтобы настроить изображения и видео в вашем флоу/пейволе, реализуйте пользовательские ресурсы. Hero-изображения и видео имеют предопределённые идентификаторы: `hero_image` и `hero_video`. В бандле пользовательских ресурсов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение. Для остальных изображений и видео необходимо [задать пользовательский идентификатор](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разные изображения или видео разным пользователям. - Показывать локальное превью-изображение, пока загружается основное удалённое. - Показывать превью-изображение перед воспроизведением видео. Вот пример того, как можно передать пользовательские ресурсы через простой словарь: ```typescript showLineNumbers const customAssets: Recordнеобязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-paywall-locale-in-adapty-paywall-builder). Ожидается, что этот параметр будет представлять собой код языка из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локализации и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **params** | необязательный | Дополнительные параметры для получения пейвола. | **Не хардкодьте идентификаторы продуктов.** Единственный ID, который стоит хардкодить — это ID плейсмента. Пейволы настраиваются удалённо, поэтому количество продуктов и доступных офферов может меняться в любой момент. Ваше приложение должно обрабатывать эти изменения динамически: если сегодня пейвол возвращает два продукта, а завтра три — отображайте все без изменений в коде. Параметры ответа: | Параметр | Описание | | :-------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Объект [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall) со списком ID продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение конфигурации представления пейвола, созданного в Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Убедитесь, что включён переключатель **Show on device** в Paywall Builder. Если эта опция не активирована, конфигурация представления не будет доступна для получения. ::: После получения пейвола проверьте, содержит ли он `ViewConfiguration` — это означает, что пейвол был создан с помощью Paywall Builder. Это поможет вам определить, как отображать пейвол. Если `ViewConfiguration` присутствует, обрабатывайте его как пейвол Paywall Builder; если нет — [обработайте его как пейвол с Remote Config](present-remote-config-paywalls-capacitor). В Capacitor SDK вызывайте метод `createPaywallView` напрямую, без предварительного получения конфигурации представления вручную. :::warning Результат метода `createPaywallView` можно использовать только один раз. Если вам нужно использовать его снова, вызовите метод `createPaywallView` заново. ::: ```typescript showLineNumbers if (paywall.hasViewConfiguration) { try { const view = await createPaywallView(paywall); } catch (error) { // handle the error } } else { // use your custom logic } ``` Параметры: | Параметр | Наличие | Описание | | :------------------- | :------- | :----------------------------------------------------------- | | **paywall** | обязательный | Объект `AdaptyPaywall` для получения контроллера нужного пейвола. | | **customTags** | необязательный | Словарь пользовательских тегов и их значений. Пользовательские теги служат плейсхолдерами в содержимом пейвола и динамически заменяются конкретными строками для персонализации контента. Подробнее см. в разделе «Пользовательские теги в Paywall Builder». | | **prefetchProducts** | необязательный | Включите, чтобы оптимизировать время отображения продуктов на экране. При значении `true` AdaptyUI автоматически загружает необходимые продукты. По умолчанию: `false`. | :::note Если вы используете несколько языков, узнайте, как добавить [локализацию Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) и как правильно использовать коды локалей [здесь](capacitor-localizations-and-locale-codes). ::: Когда у вас есть представление, [отобразите пейвол](capacitor-present-paywalls). ## Получите пейвол для аудитории по умолчанию, чтобы ускорить загрузку \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Как правило, пейволы загружаются почти мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и пейволов, а пользователи работают при слабом интернет-соединении, загрузка пейвола может занять больше времени, чем хотелось бы. В таких случаях имеет смысл показывать пейвол по умолчанию — это обеспечит плавный пользовательский опыт вместо того, чтобы не показывать пейвол вовсе. Чтобы решить эту задачу, используйте метод `getPaywallForDefaultAudience`, который получает пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать пейвол через метод `getPaywall`, как описано в разделе [Получение информации о пейволе](#fetch-paywall-designed-with-paywall-builder) выше. :::warning Почему мы рекомендуем использовать `getPaywall` У метода `getPaywallForDefaultAudience` есть несколько существенных недостатков: - **Потенциальные проблемы с обратной совместимостью**: если нужно показывать разные пейволы для разных версий приложения (текущей и будущих), придётся либо проектировать пейволы с поддержкой текущей (legacy) версии, либо мириться с тем, что у пользователей текущей (legacy) версии пейволы могут не отображаться. - **Потеря таргетинга**: все пользователи будут видеть один и тот же пейвол, настроенный для аудитории **All Users**, — а значит, вы теряете персонализированный таргетинг (в том числе по странам, маркетинговой атрибуции или собственным пользовательским атрибутам). Если вы готовы принять эти недостатки ради более быстрого получения пейвола, используйте метод `getPaywallForDefaultAudience` следующим образом. В противном случае используйте `getPaywall`, описанный [выше](#fetch-paywall-designed-with-paywall-builder). ::: ```typescript showLineNumbers try { const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', }); // the requested paywall } catch (error) { // handle the error } ``` | Параметр | Обязательность | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **locale** |необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается языковой код, состоящий из одного или нескольких подтегов, разделённых символом «минус» (**-**). Первый подтег — язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](capacitor-localizations-and-locale-codes).
| | **params** | необязательный | Дополнительные параметры для получения пейвола. | ## Настройка ассетов \{#customize-assets\} Чтобы кастомизировать изображения и видео в пейволе, используйте пользовательские ассеты. У hero-изображений и видео есть предопределённые идентификаторы: `hero_image` и `hero_video`. В бандле пользовательских ассетов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение. Для остальных изображений и видео нужно [задать пользовательский идентификатор](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разные изображения или видео разным пользователям. - Показывать локальное превью, пока загружается основное удалённое изображение. - Показывать изображение-превью перед воспроизведением видео. Вот пример того, как можно передать пользовательские ресурсы через простой словарь: ```typescript showLineNumbers const customAssets: Recordопциональный
по умолчанию: `'reload_revalidating_cache_data'`
|По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `'return_cache_data_else_load'` для возврата кэшированных данных, если они существуют. В этом случае пользователи могут не получить самые последние данные, но время загрузки будет меньше вне зависимости от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание, что кэш сохраняется при перезапуске приложения и очищается только при переустановке или ручной очистке.
Adapty SDK хранит флоу и пейволы в двух слоях: регулярно обновляемый кэш, описанный выше, и [резервные пейволы](capacitor-use-fallback-paywalls). Также используется CDN для более быстрой загрузки флоу и пейволов, а также отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает получение актуальной версии флоу и надёжность даже при слабом интернет-соединении.
| | **params.loadTimeoutMs** |опциональный
по умолчанию: 5000 мс
|Это значение ограничивает таймаут (в миллисекундах) для данного метода. По истечении таймаута будут возвращены кэшированные данные или локальный резервный вариант.
Обратите внимание, что в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeoutMs`, так как операция может включать несколько запросов под капотом.
| :::note В версии 4 метод `getFlow` больше не принимает параметр `locale`. Для кастомных пейволов все доступные локали возвращаются в Remote Config флоу (`flow.remoteConfigs`) — выберите ту, которая соответствует языку устройства или настройкам приложения. ::: Не хардкодьте ID продуктов! Поскольку флоу настраиваются удалённо, доступные продукты, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код учитывает эти сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать их. Но если позднее вы получите 3 продукта, приложение должно показать все 3 без каких-либо изменений в коде. Единственное, что нужно хардкодить, — это ID плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Объект `AdaptyFlow`, содержащий плейсмент, идентификаторы (`id`, `variationId`), название, вариации пейвола (`paywalls`) и массив `remoteConfigs` (по одной записи на каждую настроенную локаль). Чтобы получить продукты для флоу, вызовите `getPaywallProducts({ flow })`. | ## Получение продуктов \{#fetch-products\} После того как вы получили флоу, можно запросить массив продуктов, соответствующих ему: ```typescript showLineNumbers try { const products = await adapty.getPaywallProducts({ flow }); // the requested products list } catch (error) { console.error('Failed to fetch products:', error); } ``` Параметры ответа: | Параметр | Описание | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Список объектов [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) с идентификатором продукта, названием, ценой, валютой, длительностью подписки и рядом других свойств. | При реализации собственного дизайна пейвола вам, скорее всего, понадобятся свойства объекта [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct). Ниже приведены наиболее часто используемые свойства; полный список доступных свойств см. в связанной документации. | Свойство | Описание | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Чтобы отобразить название продукта, используйте `product.localizedTitle`. Обратите внимание: локализация основана на стране стора, выбранной пользователем, а не на локали устройства. | | **Price** | Чтобы отобразить цену в локализованном формате, используйте `product.price?.localizedString`. Локализация основана на локали устройства. Также можно получить цену как число через `product.price?.amount` — значение будет в местной валюте. Для получения символа валюты используйте `product.price?.currencySymbol`. | | **Subscription Period** | Чтобы отобразить период (например, неделя, месяц, год и т. д.), используйте `product.subscription?.localizedSubscriptionPeriod`. Локализация основана на локали устройства. Для программного получения периода подписки используйте `product.subscription?.subscriptionPeriod`. Оттуда можно обратиться к свойству `unit`, чтобы получить единицу периода (`'day'`, `'week'`, `'month'`, `'year'` или `'unknown'`). Свойство `numberOfUnits` даёт количество единиц периода. Например, для квартальной подписки в `unit` будет `'month'`, а в `numberOfUnits` — `3`. | | **Introductory Offer** | Чтобы показать значок или другой индикатор наличия introductory offer у подписки, проверьте свойство `product.subscription?.offer?.phases`. Это список, который может содержать до двух фаз скидки: фазу бесплатного пробного периода и фазу вводной цены. Каждый объект фазы содержит следующие полезные свойства:опциональный
по умолчанию: `'reload_revalidating_cache_data'`
|По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные при сбое. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если вы предполагаете, что у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `'return_cache_data_else_load'`: в этом случае возвращаются кешированные данные, если они есть. Пользователи могут не получить самые свежие данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при переустановке или ручной очистке.
|опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается код языка, состоящий из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](capacitor-localizations-and-locale-codes).
| | **params.fetchPolicy** |опциональный
по умолчанию: `'reload_revalidating_cache_data'`
|По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `'return_cache_data_else_load'` — оно возвращает кешированные данные, если они существуют. В этом случае пользователи могут получать не самые свежие данные, но загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание, что кеш сохраняется после перезапуска приложения и очищается только при его переустановке или вручную.
| | **params.loadTimeoutMs** |опциональный
по умолчанию: 5000 мс
|Это значение ограничивает таймаут (в миллисекундах) для данного метода. При достижении таймаута будут возвращены кешированные данные или локальный резервный пейвол.
Обратите внимание, что в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeoutMs`, поскольку операция может включать несколько запросов под капотом.
| **Не прописывайте идентификаторы продуктов в коде.** Единственный ID, который нужно хардкодить, — это ID плейсмента. Пейволы настраиваются удалённо, поэтому количество продуктов и доступных предложений может измениться в любой момент. Приложение должно обрабатывать эти изменения динамически — если сегодня пейвол возвращает два продукта, а завтра три, все они должны отображаться без изменений в коде. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Объект [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall), содержащий: список идентификаторов продуктов, идентификатор пейвола, Remote Config и ряд других свойств. | ## Получение продуктов \{#fetch-products\} Получив пейвол, вы можете запросить массив продуктов, который ему соответствует: ```typescript showLineNumbers try { const products = await adapty.getPaywallProducts({ paywall }); // the requested products list } catch (error) { console.error('Failed to fetch products:', error); } ``` Параметры ответа: | Параметр | Описание | | :-------- |:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Список объектов [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) с идентификатором продукта, названием, ценой, валютой, длительностью подписки и рядом других свойств. | При реализации собственного дизайна пейвола вам, скорее всего, понадобятся свойства объекта [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct). Ниже приведены наиболее часто используемые из них, однако полный список всех доступных свойств можно найти в документации по ссылке. | Свойство | Описание | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Чтобы отобразить название продукта, используйте `product.localizedTitle`. Локализация основана на выбранной пользователем стране стора, а не на локали устройства. | | **Price** | Чтобы отобразить цену в локализованном формате, используйте `product.price?.localizedString`. Локализация основана на локали устройства. Цену как число можно получить через `product.price?.amount` — значение будет в местной валюте. Символ валюты доступен через `product.price?.currencySymbol`. | | **Subscription Period** | Чтобы отобразить период (например, неделя, месяц, год и т. д.), используйте `product.subscription?.localizedSubscriptionPeriod`. Локализация основана на локали устройства. Для программного получения периода подписки используйте `product.subscription?.subscriptionPeriod`. Через свойство `unit` можно узнать единицу периода: `'day'`, `'week'`, `'month'`, `'year'` или `'unknown'`. Свойство `numberOfUnits` возвращает количество таких единиц. Например, для квартальной подписки в `unit` будет `'month'`, а в `numberOfUnits` — `3`. | | **Introductory Offer** | Чтобы отобразить бейдж или другой индикатор наличия introductory offer, используйте свойство `product.subscription?.offer?.phases`. Это список, который может содержать до двух фаз скидки: фазу бесплатного пробного периода и фазу вводной цены. Каждый объект фазы содержит следующие полезные свойства:необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается языковой код, состоящий из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Пример: `en` — английский язык, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](capacitor-localizations-and-locale-codes).
| | **params.fetchPolicy** |необязательный
по умолчанию: `'reload_revalidating_cache_data'`
|По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае неудачи. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `'return_cache_data_else_load'` — он возвращает кешированные данные, если они есть. В этом случае данные могут быть не самыми свежими, зато загрузка будет быстрее вне зависимости от качества связи. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или ручной очистке.
|необязательный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минуса (**-**). Первый подтег — язык, второй — регион.
Например: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **params.fetchPolicy** |необязательный
по умолчанию: `'reload_revalidating_cache_data'`
|По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `'return_cache_data_else_load'` — он возвращает кэшированные данные, если они есть. В таком случае пользователи могут получать не самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
| | **params.loadTimeoutMs** |необязательный
по умолчанию: 5000 мс
|Ограничивает таймаут (в миллисекундах) для этого метода. По истечении таймаута будут возвращены кэшированные данные или локальный резервный пейвол.
Обратите внимание: в редких случаях метод может завершиться чуть позже указанного в `loadTimeoutMs` значения, так как операция может включать несколько запросов под капотом.
| Параметры ответа: | Параметр | Описание | |:----------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onboarding** | Объект [`AdaptyOnboarding`](https://capacitor.adapty.io/interfaces/adaptyonboarding) со следующими свойствами: идентификатор и конфигурация онбординга, Remote Config и ряд других параметров. | ## Ускорьте загрузку онбординга с помощью онбординга для аудитории по умолчанию \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Как правило, онбординги загружаются почти мгновенно, так что беспокоиться об этом не стоит. Однако если у вас много аудиторий и онбордингов, а у пользователей слабое интернет-соединение, загрузка онбординга может занять больше времени, чем хотелось бы. В таких случаях имеет смысл показывать онбординг по умолчанию — это обеспечит плавный пользовательский опыт вместо полного отсутствия экрана. Чтобы решить эту проблему, используйте метод `getOnboardingForDefaultAudience`, который получает онбординг указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать онбординг с помощью метода `getOnboarding`, как описано в разделе [Получить онбординг](#fetch-onboarding) выше. :::warning Рекомендуем использовать `getOnboarding` вместо `getOnboardingForDefaultAudience`, поскольку у последнего есть важные ограничения: - **Проблемы совместимости**: Могут возникнуть трудности при поддержке нескольких версий приложения — придётся либо делать обратно совместимые дизайны, либо мириться с тем, что в старых версиях отображение будет некорректным. - **Отсутствие персонализации**: Показывает контент только для аудитории «All Users», без таргетинга по стране, атрибуции или пользовательским атрибутам. Если для вашего случая скорость загрузки важнее этих недостатков, используйте `getOnboardingForDefaultAudience`, как показано ниже. В противном случае используйте `getOnboarding`, как описано [выше](#fetch-onboarding). ::: ```typescript showLineNumbers try { const onboarding = await adapty.getOnboardingForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data' // Загрузка с сервера, фолбэк на кэш } }); console.log('Default audience onboarding fetched successfully'); } catch (error) { console.error('Failed to fetch default audience onboarding:', error); } ``` Параметры: | Параметр | Наличие | Описание | |---------|--------|-----------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указываете при создании плейсмента в дашборде Adapty. | | **locale** |необязательный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код из одного или двух подтегов, разделённых дефисом (**-**). Первый подтег — язык, второй — регион.
Пример: `en` — английский язык, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **params.fetchPolicy** |необязательный
по умолчанию: `'reload_revalidating_cache_data'`
|По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае неудачи. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `'return_cache_data_else_load'`: он возвращает кэшированные данные, если они есть. В этом случае пользователи могут не получить самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
| --- # File: capacitor-present-onboardings --- --- title: "Отображение онбордингов в Capacitor SDK" description: "Узнайте, как отображать онбординги в Capacitor для повышения конверсии и дохода." --- :::warning **Онбординги устарели в SDK v4 и будут удалены в одном из следующих релизов.** Они больше не получают исправлений и улучшений. Используйте [флоу](capacitor-get-pb-paywalls) вместо них: в отличие от онбордингов, которые работают внутри WebView, флоу рендерятся нативно на устройстве — это обеспечивает более плавные анимации, единообразный нативный вид, быструю загрузку и отсутствие зависимости от WebView. См. [Получение флоу и пейволов](capacitor-get-pb-paywalls) и [Отображение флоу и пейволов](capacitor-present-paywalls), чтобы начать. ::: Если вы настроили онбординг с помощью конструктора, вам не нужно беспокоиться о его отрисовке в коде мобильного приложения для отображения пользователю. Такой онбординг содержит как то, что должно быть показано, так и то, как именно это должно быть показано. Прежде чем начать, убедитесь, что: 1. Вы [создали онбординг](create-onboarding). 2. Вы добавили онбординг в [плейсмент](placements). ## Показ онбординга \{#present-onboarding\} Чтобы отобразить онбординг, вызовите метод `view.present()` на объекте `view`, созданном методом `createOnboardingView`. Каждый `view` можно использовать только один раз. Если нужно показать онбординг повторно, снова вызовите `createOnboardingView`, чтобы создать новый экземпляр `view`. :::warning Повторное использование одного и того же `view` без его пересоздания может привести к ошибке. ::: ```typescript showLineNumbers try { const view = await createOnboardingView(onboarding); view.setEventHandlers({ onClose: (actionId, meta) => { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, onCustom: (actionId, meta) => { console.log('Custom action:', actionId); return false; // Don't close the onboarding } }); await view.present(); console.log('Onboarding presented successfully'); } catch (error) { console.error('Failed to present onboarding:', error); } ``` ## Настройка стиля отображения на iOS \{#configure-ios-presentation-style\} Настройте способ отображения онбординга на iOS, передав параметр `iosPresentationStyle` в метод `present()`. Параметр принимает значения `'full_screen'` (по умолчанию) или `'page_sheet'`. ```typescript showLineNumbers await view.present({ iosPresentationStyle: 'page_sheet' }); ``` ## Настройте открытие ссылок в онбординге \{#customize-how-links-open-in-onboardings\} :::important Настройка открытия ссылок в онбординге поддерживается начиная с Adapty SDK v3.15. ::: По умолчанию ссылки в онбординге открываются во встроенном браузере. Это обеспечивает удобный пользовательский опыт: веб-страницы отображаются прямо внутри приложения, не требуя переключения между приложениями. Если вы хотите открывать ссылки во внешнем браузере, задайте параметру `openIn` значение `browser_out_app`: ```typescript showLineNumbers await view.present({ openIn: 'browser_out_app' }); // default — browser_in_app ``` ## Дальнейшие шаги \{#next-steps\} После отображения онбординга вам потребуется [обрабатывать действия пользователя и события](capacitor-handling-onboarding-events). Узнайте, как работать с событиями онбординга, чтобы реагировать на действия пользователей и отслеживать аналитику. --- # File: capacitor-handling-onboarding-events --- --- title: "Обработка событий онбординга в Capacitor SDK" description: "Обрабатывайте события, связанные с онбордингом, в Capacitor с помощью Adapty." --- :::warning **Онбординги объявлены устаревшими в SDK v4 и будут удалены в одном из следующих релизов.** Они больше не получают исправлений и улучшений. Используйте [флоу](capacitor-get-pb-paywalls): в отличие от онбордингов, которые работают внутри WebView, флоу рендерятся нативно на устройстве — обеспечивая более плавные анимации, единый нативный внешний вид, быструю загрузку и отсутствие зависимости от WebView. Подробнее: [Получение флоу и пейволов](capacitor-get-pb-paywalls) и [Отображение флоу и пейволов](capacitor-present-paywalls). ::: Онбординги, настроенные с помощью билдера, генерируют события, на которые может реагировать ваше приложение. Используйте метод `setEventHandlers` для обработки этих событий при самостоятельном отображении экранов. Прежде чем начать, убедитесь, что: 1. Вы [создали онбординг](create-onboarding). 2. Вы добавили онбординг в [плейсмент](placements). ## Настройка обработчиков событий \{#set-up-event-handlers\} Для обработки событий онбордингов используйте метод `view.setEventHandlers`: ```typescript showLineNumbers try { const view = await createOnboardingView(onboarding); view.setEventHandlers({ onAnalytics(event, meta) { console.log('Analytics event:', event); }, onClose(actionId, meta) { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, onCustom(actionId, meta) { console.log('Custom action:', actionId); return false; // Don't close the onboarding }, onPaywall(actionId, meta) { console.log('Paywall action:', actionId); view.dismiss().then(() => { openPaywall(actionId); }); }, onStateUpdated(action, meta) { console.log('State updated:', action); }, onFinishedLoading(meta) { console.log('Onboarding finished loading'); }, onError(error) { console.error('Onboarding error:', error); }, }); await view.present(); } catch (error) { console.error('Failed to present onboarding:', error); } ``` ## Типы событий \{#event-types\} В следующих разделах описаны различные типы событий, которые можно обрабатывать. ### Обработка пользовательских действий \{#handle-custom-actions\} В конструкторе вы можете добавить к кнопке действие типа **custom** и задать ему идентификатор.
Затем вы можете использовать этот ID в своём коде и обрабатывать его как кастомное действие. Например, если пользователь нажимает кастомную кнопку — **Login** или **Allow notifications** — обработчик события срабатывает с параметром `actionId`, который соответствует **Action ID** из билдера. Вы можете задавать собственные ID, например `"allowNotifications"`.
```typescript showLineNumbers
view.setEventHandlers({
onCustom(actionId, meta) {
switch (actionId) {
case 'login':
console.log('Login action triggered');
break;
case 'allow_notifications':
console.log('Allow notifications action triggered');
break;
}
return false; // Don't close the onboarding
},
});
```
:::important
Обратите внимание, что вам нужно самостоятельно обрабатывать закрытие онбординга. Например, необходимо скрыть сам экран онбординга.
:::
```typescript showLineNumbers
view.setEventHandlers({
onClose(actionId, meta) {
console.log('Onboarding closed:', actionId);
return true; // Allow the onboarding to close
},
});
```
Пользователь отменил запрос на оплату.
Действий не требуется, но с точки зрения бизнес-логики можно предложить пользователю скидку или напомнить о покупке позже.
| | paymentInvalid | 3 | Один из параметров платежа не был распознан стором. | | paymentNotAllowed | 4 |Пользователю не разрешено авторизовывать платежи. Возможные причины:
- Платежи не поддерживаются в стране пользователя.
- Пользователь является несовершеннолетним.
| | storeProductNotAvailable | 5 | Запрошенный продукт отсутствует в App Store. Убедитесь, что продукт доступен для нужной страны. | | cloudServicePermissionDenied | 6 | Пользователь не разрешил доступ к информации облачного сервиса. | | cloudServiceNetworkConnectionFailed | 7 | Устройству не удалось подключиться к сети. | | cloudServiceRevoked | 8 | Пользователь отозвал разрешение на использование облачного сервиса. | | privacyAcknowledgementRequired | 9 | Пользователь ещё не ознакомился с политикой конфиденциальности стора. | | unauthorizedRequestData | 10 | Запрос сформирован некорректно. | | invalidOfferIdentifier | 11 |Идентификатор офера недействителен. Возможные причины:
- Офер с таким идентификатором не настроен в App Store.
- Офер был отозван.
- Идентификатор офера указан с опечаткой.
| | invalidSignature | 12 | Подпись в платёжной скидке недействительна. Убедитесь, что заполнено поле **In-app purchase Key ID** и загружен файл **In-App Purchase Private Key**. Подробнее — в разделе [Настройка интеграции с App Store](app-store-connection-configuration). | | missingOfferParams | 13 |Проблема с интеграцией Adapty или с оферами.
Подробнее — в разделах [Настройка интеграции с App Store](app-store-connection-configuration) и [Оферы](offers).
| | invalidOfferPrice | 14 | Указанная в сторе цена больше не действительна. Оферы всегда должны предоставлять скидку относительно обычной цены. | ## Пользовательские коды Android \{#custom-android-codes\} | Ошибка | Код | Описание | |-----|----|-----------| | adaptyNotInitialized | 20 | Необходимо правильно настроить SDK Adapty с помощью метода `Adapty.activate`. Узнайте, как это сделать [для React Native](sdk-installation-reactnative). | | productNotFound | 22 | Запрошенный для покупки продукт недоступен в сторе. | | invalidJson | 23 | JSON пейвола недействителен. Исправьте его в дашборде Adapty. Подробнее — в разделе [Настройка пейвола с помощью Remote Config](customize-paywall-with-remote-config). | | currentSubscriptionToUpdateNotFoundInHistory | 24 | Исходная подписка, которую необходимо обновить, не найдена. | | pendingPurchase | 25 | Покупка находится в статусе ожидания, а не завершена. Подробнее — на странице [Обработка отложенных транзакций](https://developer.android.com/google/play/billing/integrate#pending) в документации Android Developer. | | billingServiceTimeout | 97 | Запрос превысил максимальное время ожидания до получения ответа от Google Play. Причиной может быть, например, задержка при выполнении действия, запрошенного вызовом Play Billing Library. | | featureNotSupported | 98 | Запрошенная функция не поддерживается Play Store на текущем устройстве. | | billingServiceDisconnected | 99 | Критическая ошибка: соединение клиентского приложения с сервисом Google Play Store через `BillingClient` разорвано. | | billingServiceUnavailable | 102 | Временная ошибка: сервис Google Play Billing сейчас недоступен. В большинстве случаев это означает проблему с сетевым подключением между клиентским устройством и сервисами Google Play Billing. | | billingUnavailable | 103 |Ошибка выставления счёта пользователю в процессе покупки. Примеры ситуаций, в которых это может произойти:
1. Приложение Play Store на устройстве пользователя устарело.
2. Пользователь находится в неподдерживаемой стране.
3. Пользователь является корпоративным, и администратор отключил для него возможность совершать покупки.
4. Google Play не может списать средства с платёжного метода пользователя. Например, срок действия кредитной карты истёк.
5. Пользователь не авторизован в приложении Play Store.
| | developerError | 105 | Критическая ошибка: некорректное использование API. | | billingError | 106 | Критическая ошибка: внутренняя проблема самого Google Play. | | itemAlreadyOwned | 107 | Расходуемая покупка уже была приобретена. | | itemNotOwned | 108 | Запрошенное действие с элементом завершилось неудачей, так как он не принадлежит пользователю. | ## Пользовательские коды StoreKit \{#custom-storekit-codes\} | Ошибка | Код | Описание | |-----|----|-----------| | noProductIDsFound | 1000 |Ни один из продуктов пейвола не доступен в сторе.
Если вы столкнулись с этой ошибкой, выполните следующие шаги для её устранения:
1. Убедитесь, что все продукты добавлены в дашборд Adapty.
2. Проверьте, что Bundle ID приложения совпадает с указанным в Apple Connect.
3. Убедитесь, что идентификаторы продуктов из стора совпадают с теми, что добавлены в дашборд. Обратите внимание: идентификаторы не должны содержать Bundle ID, если только он уже не включён в идентификатор в сторе.
4. Убедитесь, что статус оплаты приложения активен в налоговых настройках Apple. Проверьте актуальность налоговой информации и действительность сертификатов.
5. Проверьте, привязан ли к приложению банковский счёт — это необходимо для монетизации.
6. Проверьте доступность продуктов во всех регионах. Убедитесь, что продукты находятся в статусе **"Ready to Submit"**.
| | productRequestFailed | 1002 |Не удаётся получить доступные продукты в данный момент. Возможная причина:
- Кэш ещё не создан, и одновременно отсутствует подключение к интернету.
| | cantMakePayments | 1003 | Встроенные покупки не разрешены на этом устройстве. | | noPurchasesToRestore | 1004 | Google Play не нашёл покупку для восстановления. | | cantReadReceipt | 1005 |На устройстве нет действительного чека. Это может быть проблемой при тестировании в песочнице.
Действий не требуется, но с точки зрения бизнес-логики можно предложить пользователю скидку или напомнить о покупке позже.
| | productPurchaseFailed | 1006 | Не удалось выполнить покупку продукта. Эта ошибка оборачивает базовую ошибку StoreKit — прочитайте вложенную ошибку (или включите подробные логи для просмотра в консоли), чтобы узнать реальную причину. Вложенная ошибка, как правило, соответствует одному из кодов StoreKit 0–14 из таблицы выше — чаще всего `paymentCancelled`, `paymentInvalid`, `paymentNotAllowed` или `invalidOfferPrice`. Если определить конкретную причину не удаётся, попробуйте создать новый [профиль песочницы](test-purchases-in-sandbox); если проблема сохраняется, обратитесь в поддержку Apple. | | refreshReceiptFailed | 1010 | Чек не был получен. Применимо только к StoreKit 1. | | receiveRestoredTransactionsFailed | 1011 | Не удалось восстановить покупки. | ## Пользовательские сетевые коды \{#custom-network-codes\} | Ошибка | Код | Описание | | :------------------- | :--- | :----------------------------------------------------------- | | notActivated | 2002 | Необходимо правильно настроить SDK Adapty с помощью метода `Adapty.activate`. Узнайте, как это сделать [для React Native](sdk-installation-reactnative). | | badRequest | 2003 | Некорректный запрос. | | serverError | 2004 | Ошибка сервера. | | networkFailed | 2005 | Сетевой запрос не выполнен. | | decodingFailed | 2006 | Ошибка декодирования ответа. | | encodingFailed | 2009 | Ошибка кодирования запроса. | | analyticsDisabled | 3000 | Невозможно обработать аналитические события, так как вы отключили их сбор. Подробнее — в разделе [Интеграция аналитики](analytics-integration). | | wrongParam | 3001 | Один или несколько параметров некорректны: пустые там, где это недопустимо, или имеют неверный тип. | | activateOnceError | 3005 | Метод `.activate` нельзя вызывать более одного раза. | | profileWasChanged | 3006 | Профиль пользователя был изменён во время операции. | | fetchTimeoutError | 3101 | Пейвол не удалось загрузить в установленный срок. Чтобы избежать этой ситуации, [настройте локальные резервные пейволы](fetch-paywalls-and-products). | | operationInterrupted | 9000 | Операция была прервана системой. | --- # File: capacitor-sdk-migration-guides --- --- title: "Руководства по миграции Capacitor SDK" description: "Руководства по миграции для версий Adapty Capacitor SDK." --- На этой странице собраны все руководства по миграции для Adapty Capacitor SDK. Выберите версию, на которую хотите перейти, чтобы получить подробные инструкции: - **[Миграция на v4.0 (beta)](migration-to-capacitor-sdk-v4)** - [**Миграция на v3.16**](migration-to-capacitor-316) --- # File: migration-to-capacitor-sdk-v4 --- --- title: "Перенос Adapty Capacitor SDK на версию 4.0" description: "Перейдите на Adapty Capacitor SDK v4.0 (beta): замените paywall API на flow API, совместимые с Flow Builder и Paywall Builder." --- Adapty Capacitor SDK 4.0 (beta) вводит флоу и переименовывает paywall API соответствующим образом. Новые API работают как с новым Flow Builder, так и с существующим Paywall Builder — никаких изменений в настройках дашборда Adapty не требуется. ## Краткий справочник \{#quick-reference\} | v3 | v4 | |---|---| | `adapty.getPaywall({ placementId, locale?, params? })` | `adapty.getFlow({ placementId, params? })` | | `adapty.getPaywallForDefaultAudience({ placementId, locale?, params? })` | `adapty.getFlowForDefaultAudience({ placementId, params? })` | | `adapty.getPaywallProducts({ paywall })` | `adapty.getPaywallProducts({ flow })` | | `adapty.logShowPaywall({ paywall })` | `adapty.logShowFlow({ flow })` | | `AdaptyPaywall` (тип) | `AdaptyFlow` + `AdaptyFlowPaywall` | | `createPaywallView(paywall, params?)` | `createFlowView(flow, params?)` | | `PaywallViewController` | `FlowViewController` | | `EventHandlers` (тип) | `FlowEventHandlers` | | `CreatePaywallViewParamsInput` | `CreateFlowViewParamsInput` | | `onRenderingFailed` | `onError` | `AdaptyPaywallProduct` сохраняет своё название — продукты по-прежнему принадлежат флоу, и `getPaywallProducts` тоже сохраняет название, теперь принимая `AdaptyFlow`. Методы `getFlow` и `getFlowForDefaultAudience` больше не принимают параметр `locale`. API покупок и профиля (`makePurchase`, `restorePurchases`, `getProfile`, `identify`, `updateProfile`) и резервные пейволы через `setFallback` остались без изменений. Методы отображения `present`, `dismiss`, `setEventHandlers` и `showDialog`, а также обработчики событий `onCloseButtonPress`, `onUrlPress`, `onCustomAction`, `onProductSelected`, `onPurchaseStarted`, `onPurchaseCompleted`, `onPurchaseFailed`, `onRestoreStarted`, `onRestoreCompleted`, `onRestoreFailed`, `onLoadingProductsFailed`, `onWebPaymentNavigationFinished` и `onAndroidSystemBack` сохраняют те же названия, что и в v3. Методы онбординга по-прежнему работают, но объявлены устаревшими — см. [Устаревание Onboarding API](#onboarding-api-deprecation). Некоторые стандартные поведения изменились — см. [Изменения стандартного поведения](#default-behavior-changes). ## Минимальные версии \{#minimum-versions\} Требования к среде выполнения не изменились по сравнению с v3.16+: **iOS 15.0**, **Android minSdk 24** и **Capacitor 8**. Изменения deployment target не требуются. Появилось одно новое требование к сборке: **Xcode 26 или новее** — нативный Adapty iOS SDK 4.0.0-beta.2, входящий в этот релиз, использует Swift tools 6.2. v4 включает нативные Adapty SDK: iOS 4.0.0-beta.2 и Android BOM 4.0.0-beta.1. ## Установка \{#installation\} ### Обновление пакета \{#update-the-package\} v4.0 — предрелизная версия, поэтому укажите точную версию: npm не выбирает предрелизные версии через диапазоны с `^` или `~`: ```bash showLineNumbers npm install @adapty/capacitor@4.0.0-beta.2 ``` Затем синхронизируйте нативные проекты: ```bash showLineNumbers npx cap sync ``` ### iOS: только Swift Package Manager \{#ios-swift-package-manager-only\} [Репозиторий спецификаций CocoaPods станет доступен только для чтения в декабре 2026 года](https://blog.cocoapods.org/CocoaPods-Specs-Repo/), поэтому начиная с v4 файл `AdaptyCapacitor.podspec` удалён, и SDK устанавливается на iOS **только через Swift Package Manager (SPM)**. iOS-проект вашего приложения должен использовать интеграцию Capacitor с SPM: - Новые приложения: добавьте iOS-платформу с менеджером пакетов SPM: ```bash showLineNumbers npx cap add ios --packagemanager SPM ``` - Для существующих приложений на базе CocoaPods: перенесите iOS-проект, следуя [руководству Capacitor по использованию SPM в существующем проекте](https://capacitorjs.com/docs/ios/spm#using-spm-in-an-existing-capacitor-project). Подробнее об установке см. в [Установке Adapty SDK](sdk-installation-capacitor). ## Получение флоу \{#fetching-flows\} ### getPaywall → getFlow Возвращаемый тип изменяется с `AdaptyPaywall` на `AdaptyFlow`, а опция `locale` убрана — при рендеринге флоу локаль определяется автоматически; для кастомных пейволов все локали возвращаются в `flow.remoteConfigs`: ```diff showLineNumbers - const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' }); + const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); ``` `getPaywallForDefaultAudience` переименовывается аналогично: ```diff showLineNumbers - const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' }); + const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID' }); ``` ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` сохраняет своё название, но теперь принимает `AdaptyFlow`: ```diff showLineNumbers - const products = await adapty.getPaywallProducts({ paywall }); + const products = await adapty.getPaywallProducts({ flow }); ``` ## Модель данных \{#data-model\} `getFlow` возвращает `AdaptyFlow` вместо `AdaptyPaywall`, и структура объекта изменилась: | Поле `AdaptyPaywall` (v3) | Поле `AdaptyFlow` (v4) | Действие | |---|---|---| | `remoteConfig?` (одно) | `remoteConfigs?: AdaptyRemoteConfig[]` (массив) | Флоу содержит один Remote Config на каждый настроенный язык. Получите нужный для пользователя: `flow.remoteConfigs?.find((c) => c.lang === 'en')`. | | `products` | `flow.paywalls[i].productIdentifiers` | Идентификаторы продуктов теперь хранятся в каждом варианте флоу, а не в самом флоу. | | `webPurchaseUrl?` | `flow.paywalls[i].webPurchaseUrl` | Перенесено из флоу в каждый вариант пейвола. | | `version?: number` | `flowVersionId?: string` | Переименовано, тип изменён с `number` на `string`. | | `hasViewConfiguration` | удалено | Удалите все проверки `hasViewConfiguration` из кода — теперь `createFlowView` выбрасывает исключение (см. [Отображение флоу](#displaying-flows)). | | `requestLocale` | удалено | Локаль больше не является частью модели. | | _(новое)_ | `paywalls: AdaptyFlowPaywall[]` | Каждый элемент — один вариант пейвола во флоу. | | _(новое)_ | `responseCreatedAt: number` | Временная метка ответа сервера в миллисекундах. | `hasViewConfiguration` и `requestLocale` остаются на `AdaptyOnboarding` — только модель флоу их убирает. Идентификаторы продуктов перенесены из флоу в каждый вариант: ```diff showLineNumbers - const ids = paywall.products; + const ids = flow.paywalls[0].productIdentifiers; ``` ## Методы веб-пейвола \{#web-paywall-methods\} `openWebPaywall` и `createWebPaywallUrl` сохраняют свои названия, но опция `paywallOrProduct` теперь принимает `AdaptyFlowPaywall` (вариант флоу) вместо `AdaptyPaywall`. По-прежнему можно передать `AdaptyPaywallProduct`. Перед обращением к первому элементу убедитесь, что `flow.paywalls` не пустой: ```diff showLineNumbers const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); - await adapty.openWebPaywall({ paywallOrProduct: paywall }); + await adapty.openWebPaywall({ paywallOrProduct: flow.paywalls[0] }); ``` ## Отслеживание просмотров флоу \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` переименован в `logShowFlow` и теперь принимает `AdaptyFlow`. Событие по-прежнему фиксируется для той же вариации, поэтому метрики воронки и A/B-тестов продолжат работать без изменений в дашборде. ```diff showLineNumbers - await adapty.logShowPaywall({ paywall }); + await adapty.logShowFlow({ flow }); ``` Как и в v3, вызывать этот метод при отображении флоу или пейволов, созданных с помощью [Flow Builder](adapty-flow-builder) или [Paywall Builder](adapty-paywall-builder), не нужно — Adapty отслеживает эти просмотры автоматически. ## Отображение флоу \{#displaying-flows\} ### createPaywallView → createFlowView Переименуйте фабричную функцию и передайте `AdaptyFlow`. Возвращаемый контроллер переименован с `PaywallViewController` на `FlowViewController`, но его методы (`present`, `dismiss`, `setEventHandlers`, `showDialog`) остались прежними. Тип параметров переименован с `CreatePaywallViewParamsInput` на `CreateFlowViewParamsInput`: ```diff showLineNumbers - import { createPaywallView } from '@adapty/capacitor'; + import { createFlowView } from '@adapty/capacitor'; - const view = await createPaywallView(paywall); + const view = await createFlowView(flow); await view.present(); ``` `createFlowView` выбрасывает `AdaptyError`, если для флоу не настроено представление — это заменяет проверку `hasViewConfiguration` из v3: ```diff showLineNumbers - if (paywall.hasViewConfiguration) { - const view = await createPaywallView(paywall); - await view.present(); - } + try { + const view = await createFlowView(flow); + await view.present(); + } catch (error) { + // the flow has no view configured, or view creation failed + } ``` :::note Представление флоу одноразовое: после вызова `dismiss()` оно уничтожается и обработчики событий очищаются — чтобы снова показать флоу, вызовите `createFlowView` заново. ::: ### Безопасные отступы Android \{#android-safe-area-paddings\} `CreateFlowViewParamsInput` добавляет один новый параметр: `enableSafeArea`, который управляет безопасными отступами Android во время выполнения. Он находится под ключом `android` и по умолчанию равен `true`: ```typescript showLineNumbers const view = await createFlowView(flow, { android: { enableSafeArea: true }, }); ``` ## Обработка событий \{#handling-events\} Интерфейс обработчика событий переименован с `EventHandlers` на `FlowEventHandlers`, а один из коллбэков тоже переименован. Тела существующих обработчиков менять не нужно — просто переименуйте: ```diff showLineNumbers - onRenderingFailed: (error) => { /* … */ }, + onError: (error) => { /* … */ }, ``` Все остальные обработчики событий сохраняют свои названия. Два из них также получают второй аргумент: `onPurchaseCompleted` теперь принимает `(purchaseResult, product)`, а `onPurchaseFailed` — `(error, product)`, где `product` — это задействованный `AdaptyPaywallProduct`. Полный список см. в [Обработка событий флоу и пейвола](capacitor-handling-events). В v4 также добавлено несколько возможностей, которые можно подключить по желанию: - Методы `adapty.openWebUrl({ url, openIn })` и `adapty.requestAppReview()` — они обеспечивают работу стандартных обработчиков `onUrlPress` и `onRequestAppReview`, поэтому URL-адреса и запросы на оценку приложения обрабатываются нативно «из коробки». Вызывайте их напрямую только если переопределяете эти обработчики. - Обработка покупок в режиме Observer внутри флоу через новые обработчики `onObserverPurchaseInitiated` / `onObserverRestoreInitiated`. См. [Показ флоу в режиме Observer](capacitor-present-flows-in-observer-mode). ## Изменения в поведении по умолчанию \{#default-behavior-changes\} Эти изменения не вызывают ошибок компиляции, поэтому проверяйте их во время выполнения: - **`onAndroidSystemBack`**: По умолчанию поведение изменилось: вместо закрытия вью теперь она остаётся открытой. Чтобы вернуть прежнее поведение, верните `true` из обработчика. - **`onPurchaseCompleted`**: По умолчанию поведение изменилось: вместо закрытия вью (если пользователь не отменил покупку) теперь она всегда остаётся открытой. Чтобы вернуть прежнее поведение, верните `purchaseResult.type !== 'user_cancelled'` из обработчика. - **`onRestoreCompleted`**: По умолчанию поведение изменилось: вместо закрытия вью после успешного восстановления она теперь остаётся открытой. Чтобы вернуть прежнее поведение, верните `true` из обработчика. - **`onUrlPress`**: Теперь по умолчанию URL открывается через нативный слой с учётом настройки встроенного или внешнего браузера из дашборда. Переопределите обработчик, чтобы открывать URL самостоятельно. - **Вью одноразовые**: после вызова `dismiss()` вью уничтожается. Чтобы снова показать флоу, вызовите `createFlowView` заново. ## Удалённые API \{#removed-apis\} ### Удалённые экспорты Эти символы больше не экспортируются из `@adapty/capacitor`. Удалите их из импортов: - **`AdaptyPaywall`**: Используйте `AdaptyFlow` и `AdaptyFlowPaywall` вместо них. - **`ProductReference`**: Используйте `AdaptyProductIdentifier`, доступный в `flow.paywalls[i].productIdentifiers`. - **`AdaptyPaywallBuilder`**: Удалён. Флоу и пейволы рендерятся нативно. - **`AdaptyAndroidSubscriptionUpdateParameters`**: Используйте вложенную структуру параметров покупки `android` (см. ниже). ### activate: lockMethodsUntilReady `lockMethodsUntilReady` (уже устаревший no-op в v3) удалён. Уберите его из вызова `activate` — с ним код больше не компилируется: ```diff showLineNumbers - await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY', params: { lockMethodsUntilReady: true } }); + await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY' }); ``` ### makePurchase: параметры Android \{#makepurchase-android-parameters\} Устаревший плоский Android-формат `MakePurchaseParamsInput` удалён — теперь используется только вложенная форма. Перенесите все параметры Android-покупки в `params: { android: { ... } }`. Полный пример см. в разделе [Совершение покупок](capacitor-making-purchases). ## Устаревший API онбординга \{#onboarding-api-deprecation\} Устаревший API онбординга объявлен устаревшим в v4.0 в пользу [Flow Builder](adapty-flow-builder). Он по-прежнему работает, но будет удалён в одном из будущих релизов — запланируйте перенос ваших онбордингов во Flow Builder. Устаревшие символы: `getOnboarding`, `getOnboardingForDefaultAudience`, `createOnboardingView` и `OnboardingViewController`. --- # File: migration-to-capacitor-316 --- --- title: "Миграция Adapty Capacitor SDK на v3.16" description: "Мигрируйте на Adapty Capacitor SDK v3.16 для повышения производительности и новых функций монетизации." --- Начиная с Adapty SDK v3.16.0, требуется Capacitor 8. Если вам нужен Capacitor 7, используйте Adapty SDK v3.15. Чтобы обновиться до Capacitor SDK v3.16, убедитесь, что ваш проект использует Capacitor 8. Если вы всё ещё используете Capacitor 7, у вас есть два варианта: 1. **Обновитесь до Capacitor 8**: следуйте [официальному руководству по миграции Capacitor](https://capacitorjs.com/docs/updating/8-0), чтобы обновить проект, затем установите Adapty SDK v3.16. 2. **Оставайтесь на Adapty SDK v3.15**: если обновление до Capacitor 8 нецелесообразно, продолжайте использовать Adapty SDK v3.15, который поддерживает Capacitor 7. --- # End of Documentation _Generated on: 2026-07-24T13:01:12.730Z_ _Successfully processed: 45/45 files_ # FLUTTER - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: ru Generated on: 2026-07-24T13:01:12.733Z Total files: 44 --- # File: sdk-installation-flutter --- --- title: "Установка и настройка Flutter SDK" description: "Пошаговое руководство по установке Adapty SDK на Flutter для приложений с подписками." --- SDK Adapty включает два ключевых модуля для бесшовной интеграции в ваше Flutter-приложение: - **Core Adapty**: Основной SDK, необходимый для работы Adapty в вашем приложении. - **AdaptyUI**: Этот модуль нужен, если вы используете [Adapty Paywall Builder](adapty-paywall-builder) — удобный no-code инструмент для создания кросс-платформенных пейволов. :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Загляните в наше [демо-приложение](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example): оно демонстрирует полную настройку, включая отображение пейволов, совершение покупок и другие базовые функции. ::: ## Требования \{#requirements\} Adapty SDK поддерживает iOS 13.0+, но для корректной работы пейволов, созданных в Paywall Builder, требуется iOS 15.0+. Adapty Flutter SDK 4.0 — с поддержкой [Flow Builder](adapty-flow-builder) — повышает минимальные требования до **iOS 15.0+**, **Xcode 26+** и **Flutter 3.32.0+** (Dart 3.8.0+). Подробности об установке см. в разделе [Adapty SDK 4.0](#adapty-sdk-40-swift-package-manager) ниже. :::info Adapty совместима с Google Play Billing Library версий до 8.x включительно. По умолчанию Adapty работает с Google Play Billing Library v7.0.0, но если вам нужна более поздняя версия, вы можете вручную [добавить зависимость](https://developer.android.com/google/play/billing/integrate#dependency). ::: :::info Установка SDK — это шаг 5 настройки Adapty. Прежде чем покупки заработают в вашем приложении, вам также нужно подключить приложение к сторам, а затем создать продукты, пейвол и плейсмент в дашборде Adapty. [Гайд по быстрому старту](quickstart) описывает все необходимые шаги. ::: ## Установка Adapty SDK \{#install-adapty-sdk\} [](https://github.com/adaptyteam/AdaptySDK-Flutter/releases) :::important Шаги ниже устанавливают последнюю стабильную версию SDK (3.x). Если вам нужна v4 — необходимая для [Flow Builder](adapty-flow-builder) и используемая в [быстром старте](flutter-quickstart-paywalls) — следуйте инструкции [Adapty SDK 4.0: Swift Package Manager](#adapty-sdk-40-swift-package-manager) ниже. ::: 1. Добавьте Adapty в файл `pubspec.yaml`: ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter: ^
### При входе/регистрации \{#during-loginsignup\}
Если вы идентифицируете пользователей после запуска приложения (например, после входа в аккаунт или регистрации), используйте метод `identify`, чтобы задать их customer user ID.
- Если **этот customer user ID ещё не использовался**, Adapty автоматически привяжет его к текущему профилю.
- Если **этот customer user ID уже использовался для идентификации пользователя**, Adapty переключится на работу с профилем, связанным с этим customer user ID.
:::important
Идентификаторы пользователей (Customer User ID) должны быть уникальными для каждого пользователя. Если указать одно и то же значение, все пользователи будут считаться одним.
:::
Всегда используйте `await` для `identify` перед вызовом других методов SDK. Параллельные вызовы приводят к ошибке `#3006 profileWasChanged` или работе с анонимным профилем. См. [Порядок вызовов во Flutter SDK](flutter-sdk-call-order).
```dart showLineNumbers
try {
await Adapty().identify(customerUserId); // Уникален для каждого пользователя
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
}
```
### При активации SDK \{#during-the-sdk-activation\}
Если вы уже знаете customer user ID в момент активации SDK, передайте его прямо в метод `activate` — вызывать `identify` отдельно не нужно.
Если вы знаете customer user ID, но передаёте его только после активации, это значит, что при активации Adapty создаст новый анонимный профиль и переключится на существующий лишь после вызова `identify`.
Вы можете передать как существующий customer user ID (ранее уже использованный), так и новый. Если передать новый, то профиль, созданный при активации, будет автоматически привязан к этому customer user ID.
:::note
По умолчанию создание анонимных профилей не влияет на дашборды аналитики, так как установки считаются по идентификаторам устройств.
Идентификатор устройства соответствует одной установке приложения из стора и пересоздаётся только после переустановки.
Он не зависит от того, является ли установка первой или повторной, и от того, используется ли существующий пользовательский идентификатор.
Создание профиля (при активации SDK или выходе из системы), вход в систему или обновление приложения без переустановки не генерируют дополнительные события установки.
Если вы хотите считать установки по уникальным пользователям, а не по устройствам, перейдите в **App settings** и настройте [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```dart showLineNumbers"
try {
await Adapty().activate(
configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY')
..withCustomerUserId(YOUR_CUSTOMER_USER_ID) // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one.
);
} catch (e) {
// handle the error
}
```
### Выход пользователей из системы \{#log-users-out\}
Если в вашем приложении есть кнопка выхода, используйте метод `logout`.
:::important
Выход из системы создаёт новый анонимный профиль для пользователя.
:::
```dart showLineNumbers
try {
await Adapty().logout();
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
// handle unknown error
}
```
:::info
Чтобы снова авторизовать пользователя в приложении, используйте метод `identify`.
:::
### Разрешить покупки без входа \{#allow-purchases-without-login\}
Если ваши пользователи могут совершать покупки как до, так и после входа в приложение, необходимо убедиться, что после входа они сохранят доступ:
1. Когда неавторизованный пользователь совершает покупку, Adapty привязывает её к анонимному идентификатору профиля.
2. Когда пользователь входит в аккаунт, Adapty переключается на работу с идентифицированным профилем.
- Если это новый customer user ID (например, покупка была совершена до регистрации), Adapty присваивает customer user ID текущему профилю, и вся история покупок сохраняется.
- Если это существующий customer user ID (customer user ID уже привязан к профилю), после смены профиля нужно получить актуальный уровень доступа. Для этого можно либо вызвать [`getProfile`](flutter-check-subscription-status) сразу после идентификации, либо [подписаться на обновления профиля](flutter-check-subscription-status), чтобы данные синхронизировались автоматически.
## Дальнейшие шаги \{#next-steps\}
Поздравляем! Вы реализовали логику встроенных покупок в своём приложении! Желаем вам успехов в монетизации!
Чтобы получить от Adapty ещё больше пользы, изучите эти темы:
- [**Тестирование**](troubleshooting-test-purchases): Убедитесь, что всё работает как ожидается
- [**Онбординги**](flutter-onboardings): Вовлекайте пользователей с помощью онбордингов и повышайте удержание
- [**Интеграции**](configuration): Интегрируйтесь с сервисами маркетинговой атрибуции и аналитики всего в одну строку кода
- [**Настройка пользовательских атрибутов профиля**](flutter-setting-user-attributes): Добавляйте пользовательские атрибуты к профилям, создавайте сегменты и запускайте A/B-тесты или показывайте разные пейволы разным пользователям
---
# File: adapty-sdk-integration-skill-flutter
---
---
title: "Интеграция Adapty в Flutter-приложение с помощью навыка SDK integration"
description: "Используйте навык adapty-sdk-integration для полноценной интеграции Adapty SDK в ваше Flutter-приложение с помощью AI-инструмента для написания кода."
---
[Скилл adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) автоматизирует интеграцию Adapty от начала до конца: настройку дашборда, установку SDK, пейвол и проверку на каждом этапе. Он автоматически определяет вашу платформу и подгружает нужную документацию Adapty на каждом шаге.
**Поддерживаемые инструменты**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Для установки выберите команду для своего инструмента. Полный список — в [README скилла](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex или любой другой инструмент** — используйте [skills CLI](https://skills.sh) (обратите внимание, что скиллы, установленные таким способом, не обновляются автоматически):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Либо клонируйте репозиторий и скопируйте `skills/adapty-sdk-integration/` в директорию скиллов вашего инструмента.
После установки запустите скилл в вашем проекте:
```
/adapty-sdk-integration
```
Скилл задаст несколько вопросов по настройке, а затем проведёт через настройку дашборда, установку SDK, пейвол и проверку.
:::important
Навык находится в бета-версии. Если он зависает или ведёт себя непредсказуемо, воспользуйтесь [пошаговым руководством по интеграции](adapty-cursor-flutter) — оно проведёт ваш AI-инструмент через каждый этап с нужной документацией.
:::
[Скилл adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) автоматизирует интеграцию Adapty от начала до конца: настройку дашборда, установку SDK, пейвол и проверку на каждом этапе. Он автоматически определяет вашу платформу и подгружает нужную документацию Adapty на каждом шаге.
**Поддерживаемые инструменты**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Для установки выберите команду для своего инструмента. Полный список — в [README скилла](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex или любой другой инструмент** — используйте [skills CLI](https://skills.sh) (обратите внимание, что скиллы, установленные таким способом, не обновляются автоматически):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Либо клонируйте репозиторий и скопируйте `skills/adapty-sdk-integration/` в директорию скиллов вашего инструмента.
После установки запустите скилл в вашем проекте:
```
/adapty-sdk-integration
```
Скилл задаст несколько вопросов по настройке, а затем проведёт через настройку дашборда, установку SDK, пейвол и проверку.
---
# File: adapty-cursor-flutter
---
---
title: "Интеграция Adapty во Flutter-приложение с помощью ИИ"
description: "Пошаговое руководство по интеграции Adapty во Flutter-приложение с использованием Cursor, Context7, ChatGPT, Claude и других ИИ-инструментов."
---
Этот гайд поможет шаг за шагом интегрировать Adapty в Flutter-приложение с помощью инструмента AI-кодинга — вы подаёте ему нужную документацию Adapty в нужном порядке.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Прежде чем начать: настройка дашборда \{#before-you-start-dashboard-setup\}
Adapty требует некоторой настройки в дашборде до того, как вы напишете какой-либо код SDK. Это можно сделать с помощью интерактивного LLM-навыка или вручную через дашборд.
### Подход через skill (рекомендуется) \{#skill-approach-recommended\}
Skill Adapty CLI позволяет LLM настроить приложение, продукты, уровни доступа, пейволы и плейсменты напрямую — без открытия дашборда на каждом шаге. Нужно только [подключить сторы](integrate-payments) в дашборде.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
После добавления skill запустите `/adapty-cli` в агенте. Он проведёт вас через каждый шаг — в том числе подскажет, когда нужно открыть дашборд для подключения сторов.
### Подход через дашборд
Если вы предпочитаете настраивать всё вручную, вот что нужно сделать до написания кода. Ваша LLM не может самостоятельно найти значения в дашборде — вам придётся предоставить их самостоятельно.
1. **Подключите сторы**: В дашборде Adapty перейдите в **App settings → General**. Подключите App Store и Google Play, если ваше Flutter-приложение поддерживает обе платформы. Это обязательное условие для работы покупок.
[Подключить сторы](integrate-payments)
2. **Скопируйте публичный SDK-ключ**: В дашборде Adapty перейдите в **App settings → General** и найдите раздел **API keys**. В коде это строка, которую вы передаёте в конфигурацию Adapty.
3. **Создайте хотя бы один продукт**: В дашборде Adapty перейдите на страницу **Products**. В коде продукты не указываются напрямую — Adapty передаёт их через пейволы.
[Добавить продукты](quickstart-products)
4. **Создайте пейвол и плейсмент**: в дашборде Adapty создайте пейвол на странице **Paywalls**, затем назначьте его на плейсмент на странице **Placements**. В коде идентификатор плейсмента — это строка, которую вы передаёте в `Adapty().getPaywall()`.
[Создать пейвол](quickstart-paywalls)
5. **Настройте уровни доступа**: В дашборде Adapty настройте каждый продукт на странице **Products**. В коде проверяйте строку `profile.accessLevels['premium']?.isActive`. Уровень доступа `premium` по умолчанию подходит для большинства приложений. Если платящие пользователи получают доступ к разным функциям в зависимости от продукта (например, план `basic` и план `pro`), [создайте дополнительные уровни доступа](assigning-access-level-to-a-product) до начала разработки.
:::tip
Когда у вас есть все пять, можно писать код. Скажите своему LLM: «Мой публичный SDK-ключ — X, идентификатор плейсмента — Y», чтобы он сгенерировал корректный код инициализации и получения пейвола.
:::
### Настройте по мере готовности \{#set-up-when-ready\}
Это не обязательно для начала разработки, но пригодится по мере развития интеграции:
- **A/B-тесты**: настраиваются на странице **Placements**. Изменения в коде не нужны.
[A/B-тесты](ab-tests)
- **Дополнительные пейволы и плейсменты**: добавьте больше вызовов `getPaywall` с разными идентификаторами плейсментов.
- **Интеграции аналитики**: настраиваются на странице **Integrations**. Процесс настройки зависит от конкретной интеграции. См. [интеграции аналитики](analytics-integration) и [интеграции атрибуции](attribution-integration).
## Передайте документацию Adapty своей LLM \{#feed-adapty-docs-to-your-llm\}
### Используйте Context7 (рекомендуется) \{#use-context7-recommended\}
[Context7](https://context7.com) — это MCP-сервер, который даёт вашей LLM прямой доступ к актуальной документации Adapty. LLM автоматически загружает нужные документы исходя из вашего запроса — никаких ручных вставок ссылок.
Context7 работает с **Cursor**, **Claude Code**, **Windsurf** и другими MCP-совместимыми инструментами. Чтобы настроить, запустите:
```
npx ctx7 setup
```
Команда определит ваш редактор и настроит сервер Context7. Для ручной настройки см. [репозиторий Context7 на GitHub](https://github.com/upstash/context7).
После настройки ссылайтесь на библиотеку Adapty в своих запросах:
```
Use the adaptyteam/adapty-docs library to look up how to install the Flutter SDK
```
:::warning
Несмотря на то что Context7 избавляет от необходимости вставлять ссылки на документацию вручную, порядок реализации важен. Следуйте [пошаговому руководству](#implementation-walkthrough) ниже, выполняя шаги строго по порядку.
:::
### Используйте документацию в формате обычного текста \{#use-plain-text-docs\}
Любую документацию Adapty можно открыть как обычный текст в формате Markdown. Добавьте `.md` в конец URL или нажмите **Copy for LLM** под заголовком статьи. Например: [adapty-cursor-flutter.md](https://adapty.io/docs/ru/adapty-cursor-flutter.md).
Каждый шаг [пошагового руководства по интеграции](#implementation-walkthrough) ниже содержит блок «Отправьте это своему LLM» со ссылками `.md` для вставки.
Чтобы получить сразу несколько документов, смотрите [индексные файлы и платформенные подборки](#plain-text-doc-index-files) ниже.
## Пошаговое руководство по интеграции \{#implementation-walkthrough\}
В этом гайде мы разберём интеграцию Adapty в порядке реализации. Для каждого этапа указаны нужные документы для передачи LLM, ожидаемый результат и типичные проблемы.
### Планирование интеграции \{#plan-your-integration\}
Прежде чем переходить к коду, попросите LLM проанализировать ваш проект и составить план реализации. Если ваш AI-инструмент поддерживает режим планирования (например, план-режим в Cursor или Claude Code), используйте его — так LLM сможет изучить и структуру вашего проекта, и документацию Adapty до того, как начнёт писать код.
Сообщите LLM, какой подход к покупкам вы используете — это определяет, какими гайдами он должен руководствоваться:
- [**Adapty Paywall Builder**](adapty-paywall-builder): вы создаёте пейволы в no-code редакторе Adapty, а SDK отображает их автоматически.
- [**Пейволы, созданные вручную**](flutter-making-purchases): вы строите собственный интерфейс пейвола в коде, но всё равно используете Adapty для получения продуктов и обработки покупок.
- [**Режим Observer**](observer-vs-full-mode): вы сохраняете существующую инфраструктуру покупок и используете Adapty только для аналитики и интеграций.
Не знаете, что выбрать? Прочитайте [сравнительную таблицу в разделе быстрого старта](flutter-quickstart-paywalls).
### Установка и настройка SDK \{#install-and-configure-the-sdk\}
Добавьте зависимость Adapty SDK с помощью `flutter pub add` и активируйте её с вашим публичным ключом SDK. Это основа — без неё ничего не работает.
**Гайд:** [Установка и настройка Adapty SDK](sdk-installation-flutter)
Отправьте это в ваш LLM:
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/ru/sdk-installation-flutter.md
```
:::tip[Checkpoint]
- **Ожидаемый результат:** Приложение собирается и запускается на iOS и Android. В консоли отладки есть лог активации Adapty.
- **Частая проблема:** «Public API key is missing» → проверьте, что вы заменили плейсхолдер на реальный ключ из **App settings**.
:::
### Показ пейволов и обработка покупок \{#show-paywalls-and-handle-purchases\}
Получите пейвол по ID плейсмента, отобразите его и обработайте события покупок. Нужные гайды зависят от того, как вы обрабатываете покупки.
Тестируйте каждую покупку в песочнице по мере работы — не откладывайте на конец. Инструкции по настройке см. в разделе [Тестирование покупок в песочнице](test-purchases-in-sandbox).
По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad`, чтобы возвращать кэшированные данные, если они существуют. В этом случае пользователи могут не получать самые последние данные, но загрузка будет быстрее вне зависимости от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при его переустановке или ручной очистке.
Adapty SDK хранит пейволы локально в двух слоях: регулярно обновляемый кэш, описанный выше, и [резервные пейволы](fallback-paywalls). Для более быстрой загрузки пейволов также используется CDN и отдельный резервный сервер на случай недоступности CDN. Такая система гарантирует, что вы всегда получаете актуальную версию пейволов, обеспечивая надёжность даже при слабом интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |`Duration`, ограничивающий таймаут этого метода. При достижении таймаута будут возвращены кэшированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с задержкой относительно значения, указанного в `loadTimeout`, поскольку операция может включать несколько запросов под капотом.
| ## Параметры ответа \{#response-parameters\} | Параметр | Описание | | :-------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | Объект `AdaptyFlow` с идентификаторами флоу (`instanceIdentity`, `variationId`), именем, плейсментом, вариантами пейволов (`paywalls`) и Remote Config (`remoteConfigs`). | ## Получение конфигурации экрана \{#fetch-the-view-configuration\} :::important Убедитесь, что в конструкторе включён переключатель **Show on device**. Если он не активирован, конфигурация экрана не будет доступна для получения. ::: Если плейсмент был создан в **Flow Builder** или **Paywall Builder**, Adapty самостоятельно отрисовывает UI — свойство `hasViewConfiguration` полученного флоу равно `true`. Создайте представление с помощью `createFlowView`, затем [отобразите флоу или пейвол](flutter-present-paywalls). Если плейсмент — это кастомный пейвол без UI Builder (`hasViewConfiguration` равно `false`), [обработайте его как пейвол с Remote Config](present-remote-config-paywalls-flutter). :::warning Результат метода `createFlowView` можно использовать для отображения только один раз. Если нужно показать его снова, вызовите метод `createFlowView` заново. ::: ```dart showLineNumbers try { final view = await AdaptyUI().createFlowView(flow: flow); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` Параметры: | Параметр | Наличие | Описание | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | обязательный | Объект `AdaptyFlow` для получения представления нужного флоу/пейвола. | | **customTags** | необязательный | Задайте карту пользовательских тегов и их значений. Пользовательские теги служат плейсхолдерами в контенте и динамически заменяются конкретными строками для персонализации контента во флоу/пейволе. Подробнее см. в разделе [Пользовательские теги в Paywall Builder](custom-tags-in-paywall-builder). | | **preloadProducts** | необязательный | Включите, чтобы оптимизировать время отображения продуктов на экране. При значении `true` AdaptyUI автоматически загрузит необходимые продукты. По умолчанию: `false`. | | **loadTimeout** | необязательный | Значение типа `Duration`, ограничивающее время загрузки конфигурации представления. При истечении таймаута будут использованы кешированные данные или локальный резервный вариант. | :::note Если вы используете несколько языков, узнайте, как добавить [локализацию флоу](add-paywall-locale-in-adapty-paywall-builder) и как правильно использовать коды локалей [здесь](flutter-localizations-and-locale-codes). ::: После того как вы получили представление, [отобразите флоу/пейвол](flutter-present-paywalls). ## Получение флоу или пейвола для аудитории по умолчанию ради ускорения загрузки \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} Как правило, флоу и пейволы загружаются почти мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и плейсментов, а у пользователей слабое интернет-соединение, загрузка флоу или пейвола может занять больше времени, чем хотелось бы. В таких ситуациях имеет смысл показывать флоу или пейвол по умолчанию — это обеспечит плавный пользовательский опыт вместо пустого экрана. Чтобы решить эту проблему, используйте метод `getFlowForDefaultAudience`, который получает флоу или пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать флоу или пейвол через метод `getFlow`, как описано в разделе [Получение флоу/пейвола](#fetch-flowpaywall) выше. :::warning Почему мы рекомендуем использовать `getFlow` Метод `getFlowForDefaultAudience` имеет ряд существенных недостатков: - **Потенциальные проблемы обратной совместимости**: если вам нужно показывать разные пейволы для разных версий приложения (текущей и будущих), могут возникнуть сложности. Придётся либо проектировать пейволы с поддержкой текущей (устаревшей) версии, либо мириться с тем, что пользователи этой версии могут столкнуться с нерендеренными пейволами. - **Потеря таргетинга**: все пользователи будут видеть один и тот же пейвол, настроенный для аудитории **All Users**, — это означает потерю персонализированного таргетинга (в том числе по странам, маркетинговой атрибуции или собственным пользовательским атрибутам). Если вы готовы принять эти недостатки ради более быстрой загрузки флоу или пейвола, используйте метод `getFlowForDefaultAudience` следующим образом. В противном случае используйте `getFlow`, описанный [выше](#fetch-flowpaywall). ::: ```dart showLineNumbers try { final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); // the requested flow/paywall } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` | Параметр | Наличие | Описание | |---------|--------|-----------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае неудачи. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если вы считаете, что у ваших пользователей нестабильный интернет, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кэшированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, зато загрузка будет быстрее, независимо от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии для сокращения числа сетевых запросов.
Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при его переустановке или при ручной очистке.
| ## Настройка ассетов \{#customize-assets\} Чтобы настроить изображения и видео в своём флоу/пейволе, используйте кастомные ассеты. У изображений-героев и видео-героев есть предопределённые ID: `hero_image` и `hero_video`. В бандле кастомных ассетов вы обращаетесь к этим элементам по их ID и настраиваете их поведение. Для остальных изображений и видео необходимо [задать кастомный ID](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разное изображение или видео отдельным пользователям. - Показывать локальное превью-изображение, пока загружается основное удалённое изображение. - Показывать превью-изображение перед воспроизведением видео. Вот пример того, как можно передать пользовательские ресурсы через простой словарь: ```dart final customAssets = { // Show a local image using a custom ID 'custom_image': AdaptyCustomAsset.localImageAsset( assetId: 'assets/images/image_name.png', ), // Show a local video with a preview image 'hero_video': AdaptyCustomAsset.localVideoAsset( assetId: 'assets/videos/custom_video.mp4', ), }; try { final view = await AdaptyUI().createFlowView( flow: flow, customAssets: customAssets, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note Если ресурс не найден, флоу/пейвол вернётся к внешнему виду по умолчанию. ::: ## Настройка таймеров, определяемых разработчиком \{#set-up-developer-defined-timers\} Чтобы использовать кастомные таймеры в мобильном приложении, передайте карту `customTimers` в метод `createFlowView`. Каждый ключ карты — это идентификатор таймера, а значение — объект `DateTime`, определяющий момент окончания таймера. Пример: ```dart showLineNumbers try { final view = await AdaptyUI().createFlowView( flow: flow, customTimers: { 'CUSTOM_TIMER_6H': DateTime.now().add(const Duration(seconds: 3600 * 6)), 'CUSTOM_TIMER_NY': DateTime(2027, 1, 1), // New Year 2027 }, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` В этом примере `CUSTOM_TIMER_NY` и `CUSTOM_TIMER_6H` — это **Timer ID** таймеров, заданных разработчиком в дашборде Adapty. Словарь `customTimers` обеспечивает динамическое обновление каждого таймера с нужным значением. Например: - `CUSTOM_TIMER_NY`: время, оставшееся до конца отсчёта таймера, например до Нового года. - `CUSTOM_TIMER_6H`: время, оставшееся в 6-часовом периоде, который начался, когда пользователь открыл флоу.опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-paywall-locale-in-adapty-paywall-builder). Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег указывает язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](flutter-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное соединение, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кешированные данные при их наличии. В этом случае пользователи могут не получить самые свежие данные, но загрузка будет заметно быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в рамках сессии для сокращения числа сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при переустановке или ручной очистке.
Adapty SDK хранит пейволы локально в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Для ускорения загрузки используется CDN, а при его недоступности — отдельный резервный сервер. Такая система обеспечивает получение актуальных пейволов и надёжность даже при нестабильном интернете.
| | **loadTimeout** | по умолчанию: 5 сек |Ограничивает таймаут для этого метода. При истечении таймаута возвращаются кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения `loadTimeout`, так как операция может включать несколько запросов под капотом.
Для Android: `TimeInterval` можно создать с помощью функций-расширений (например, `5.seconds`, где `.seconds` импортируется из `import com.adapty.utils.seconds`) или через `TimeInterval.seconds(5)`. Чтобы убрать ограничение, используйте `TimeInterval.INFINITE`.
| Параметры ответа: | Параметр | Описание | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Объект [`AdaptyPaywall`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) со списком идентификаторов продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение конфигурации отображения пейвола, созданного в Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Убедитесь, что в Paywall Builder включён переключатель **Show on device**. Если эта опция не активирована, конфигурация отображения не будет доступна для получения. ::: После получения пейвола проверьте, содержит ли он `ViewConfiguration` — это означает, что пейвол был создан с помощью Paywall Builder. Это подскажет вам, как отображать пейвол. Если `ViewConfiguration` присутствует, обрабатывайте его как пейвол Paywall Builder; если нет, [обрабатывайте его как пейвол с Remote Config](present-remote-config-paywalls-flutter). ```dart showLineNumbers try { final view = await AdaptyUI().createPaywallView( paywall: paywall, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` Когда представление готово, [покажите пейвол](flutter-present-paywalls). ## Получение пейвола для аудитории по умолчанию для более быстрой загрузки \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Как правило, пейволы загружаются практически мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и пейволов, а интернет-соединение у пользователей нестабильное, загрузка пейвола может занять больше времени, чем хотелось бы. В таких случаях имеет смысл показывать пейвол для аудитории по умолчанию — это обеспечит плавный пользовательский опыт вместо ситуации, когда пейвол не отображается вовсе. Чтобы решить эту задачу, вы можете использовать метод `getPaywallForDefaultAudience`, который загружает пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — загружать пейвол методом `getPaywall`, как описано в разделе [Получение информации о пейволе](flutter-get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) выше. :::warning Почему мы рекомендуем использовать `getPaywall` Метод `getPaywallForDefaultAudience` имеет ряд существенных недостатков: - **Возможные проблемы обратной совместимости**: если вам нужно показывать разные пейволы для разных версий приложения (текущей и будущих), могут возникнуть трудности. Придётся либо создавать пейволы, совместимые с текущей (устаревшей) версией, либо смириться с тем, что пользователи на текущей (устаревшей) версии могут столкнуться с нерендерящимися пейволами. - **Потеря таргетинга**: все пользователи будут видеть один и тот же пейвол, созданный для аудитории **All Users**, — то есть вы теряете персонализированный таргетинг (включая таргетинг по странам, маркетинговой атрибуции или собственным пользовательским атрибутам). Если вы готовы принять эти ограничения ради более быстрой загрузки пейвола, используйте метод `getPaywallForDefaultAudience` следующим образом. В противном случае придерживайтесь метода `getPaywall`, описанного [выше](#fetch-paywall-designed-with-paywall-builder). ::: ```dart showLineNumbers try { final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` :::note Метод `getPaywallForDefaultAudience` доступен начиная с Flutter SDK версии 3.2.0. ::: | Параметр | Наличие | Описание | |---------|--------|-----------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение, которое вы указали при создании плейсмента в дашборде Adapty. | | **locale** |опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается, что этот параметр будет языковым кодом, состоящим из одного или нескольких подтегов, разделённых символом минуса (**-**). Первый подтег — язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — оно вернёт кэшированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, но загрузка будет быстрее независимо от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание, что кэш сохраняется при перезапуске приложения и очищается только при переустановке приложения или вручную.
| ## Настройка ресурсов \{#customize-assets\} Чтобы настроить изображения и видео на пейволе, реализуйте пользовательские ресурсы. Для изображений-заголовков и видео-заголовков есть предопределённые идентификаторы: `hero_image` и `hero_video`. В пакете пользовательских ресурсов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение. Для других изображений и видео нужно [задать пользовательский идентификатор](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разные изображения или видео разным пользователям. - Показывать локальное превью, пока загружается основное удалённое изображение. - Показывать превью перед запуском видео. :::important Чтобы использовать эту функцию, обновите Flutter SDK Adapty до версии 3.8.0 или выше. ::: Вот пример того, как можно передавать пользовательские ресурсы через простой словарь: ```dart final customAssets = { // Show a local image using a custom ID 'custom_image': AdaptyCustomAsset.localImageAsset( assetId: 'assets/images/image_name.png', ), // Show a local video with a preview image 'hero_video': AdaptyCustomAsset.localVideoAsset( assetId: 'assets/videos/custom_video.mp4', ), }; try { final view = await AdaptyUI().createPaywallView( paywall: paywall, customAssets: customAssets, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note Если ресурс не найден, пейвол вернётся к внешнему виду по умолчанию. ::: ## Настройка таймеров, определяемых разработчиком \{#set-up-developer-defined-timers\} Чтобы использовать пользовательские таймеры в мобильном приложении, передайте словарь `customTimers` в метод `createPaywallView`. Каждый ключ словаря — это идентификатор таймера, а значение — объект `DateTime`, определяющий момент окончания таймера. Пример: ```dart showLineNumbers try { final view = await AdaptyUI().createPaywallView( paywall: paywall, customTimers: { 'CUSTOM_TIMER_6H': DateTime.now().add(const Duration(seconds: 3600 * 6)), 'CUSTOM_TIMER_NY': DateTime(2025, 1, 1), // New Year 2025 }, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` В этом примере `CUSTOM_TIMER_NY` и `CUSTOM_TIMER_6H` — это **Timer ID** пользовательских таймеров, которые вы задали в дашборде Adapty. Словарь `customTimers` гарантирует, что приложение динамически обновит каждый таймер с нужным значением. Например: - `CUSTOM_TIMER_NY`: время до окончания таймера, например до Нового года. - `CUSTOM_TIMER_6H`: оставшееся время в 6-часовом периоде, который начался, когда пользователь открыл пейвол.
## Число просмотров пейвола слишком велико \{#the-paywall-view-number-is-too-big\}
**Проблема**: Счётчик просмотров пейвола показывает число вдвое больше ожидаемого.
**Причина**: Возможно, вы вызываете `logShowFlow` (Flutter SDK v4+) / `logShowPaywall` в своём коде, что дублирует счётчик просмотров, если вы используете Paywall Builder или Flow Builder. Для флоу и пейволов, созданных с помощью этих инструментов, аналитика отслеживается автоматически, поэтому использовать этот метод не нужно.
**Решение**: Убедитесь, что вы не вызываете `logShowFlow` (Flutter SDK v4+) / `logShowPaywall` в своём коде, если используете Paywall Builder или Flow Builder.
## Другие проблемы \{#other-issues\}
**Проблема**: У вас возникают другие проблемы, связанные с Paywall Builder, которые не описаны выше.
**Решение**: При необходимости обновите SDK до последней версии, следуя [гайдам по миграции](flutter-sdk-migration-guides). Многие проблемы уже исправлены в новых версиях SDK.
---
# File: flutter-present-flows-in-observer-mode
---
---
title: "Показ флоу в режиме Observer в Flutter SDK"
description: "Показывайте флоу и пейволы Paywall Builder в режиме Observer в вашем Flutter-приложении, обрабатывая покупки собственным кодом."
---
Если вы настроили флоу или пейвол с помощью билдера, вам не нужно беспокоиться об их рендеринге в коде мобильного приложения для отображения пользователю. Такой флоу или пейвол уже содержит и то, что нужно показать, и то, как именно это должно выглядеть.
:::warning
Этот раздел относится только к [режиму Observer](observer-vs-full-mode). Если вы не работаете в режиме Observer, обратитесь к разделу [Отображение флоу и пейволов](flutter-present-paywalls).
:::
:::info
Эта функция доступна начиная с Adapty Flutter SDK 4.0 — ранее она была доступна только в нативных SDK для iOS и Android. Ознакомьтесь с [руководством по миграции](migration-to-flutter-sdk-v4), чтобы выполнить обновление.
:::
По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если вы считаете, что у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad`, который возвращает кешированные данные, если они существуют. В этом случае пользователи могут не получать самые последние данные, но время загрузки будет меньше независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание, что кеш сохраняется при перезапуске приложения и очищается только при его переустановке или ручной очистке.
Adapty SDK хранит пейволы в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](flutter-use-fallback-paywalls). Также используется CDN для более быстрой загрузки пейволов и отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает актуальность пейволов и их доступность даже при нестабильном интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут данного метода. При истечении таймаута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание, что в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeout`, поскольку операция может включать несколько запросов.
| :::note В v4 метод `getFlow` не принимает параметр `locale`. Для кастомных пейволов все доступные локализации возвращаются в Remote Config флоу (`flow.remoteConfigs`) — выберите ту, которая соответствует языку устройства или настройкам приложения. См. [Локализации и коды локалей](flutter-localizations-and-locale-codes). ::: Параметры ответа: | Parameter | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Объект `AdaptyFlow` с идентификаторами флоу (`instanceIdentity`, `variationId`), именем, плейсментом, вариантами пейволов (`paywalls`) и Remote Config-ами (`remoteConfigs`). | ## Получение продуктов \{#fetch-products\} Получив флоу, вы можете запросить массив продуктов, соответствующих ему: ```dart showLineNumbers try { final products = await Adapty().getPaywallProducts(flow: flow); // the requested products array } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` Параметры ответа: | Параметр | Описание | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Список объектов [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) с: идентификатором продукта, названием продукта, ценой, валютой, длительностью подписки и рядом других свойств. | При реализации собственного дизайна пейвола вам, скорее всего, понадобится доступ к свойствам объекта [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html). Ниже приведены наиболее часто используемые свойства; полный список доступных свойств см. в документации по ссылке. | Свойство | Описание | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Чтобы отобразить название продукта, используйте `product.localizedTitle`. Обратите внимание, что локализация основана на стране стора, выбранной пользователем, а не на локали самого устройства. | | **Price** | Чтобы отобразить локализованную цену, используйте `product.price.localizedString`. Эта локализация основана на данных локали устройства. Цену в числовом виде можно получить через `product.price.amount`. Значение будет указано в местной валюте. Чтобы получить соответствующий символ валюты, используйте `product.price.currencySymbol`. | | **Subscription Period** | Чтобы отобразить период (например, неделя, месяц, год и т.д.), используйте `product.subscription?.localizedPeriod`. Эта локализация основана на локали устройства. Чтобы получить период подписки программно, используйте `product.subscription?.period`. Оттуда можно обратиться к перечислению `unit`, чтобы получить длину периода (day, week, month, year или unknown). Значение `numberOfUnits` возвращает количество единиц периода. Например, для квартальной подписки в свойстве unit будет `AdaptyPeriodUnit.month`, а в numberOfUnits — `3`. | | **Introductory Offer** | Чтобы отобразить значок или другой индикатор наличия introductory offer у подписки, проверьте свойство `product.subscription?.offer?.phases`. Это список, который может содержать до двух фаз скидки: фазу бесплатного пробного периода и фазу вводной цены. Каждый объект фазы содержит следующие полезные свойства:По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильный интернет, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, зато контент будет загружаться быстро вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому использовать его в течение сессии для сокращения сетевых запросов вполне безопасно.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
|опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается, что этот параметр будет языковым кодом, состоящим из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Например: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](flutter-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут не получать самые свежие данные, зато время загрузки будет минимальным вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в рамках сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит пейволы в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](flutter-use-fallback-paywalls). Также используется CDN для ускорения загрузки пейволов и отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает актуальность пейволов и надёжность даже при нестабильном интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает тайм-аут для данного метода. По истечении тайм-аута будут возвращены кешированные данные или локальный резервный пейвол.
Обратите внимание: в редких случаях метод может завершиться с тайм-аутом чуть позже указанного в `loadTimeout` значения, поскольку операция может состоять из нескольких запросов под капотом.
| Не хардкодьте идентификаторы продуктов! Поскольку пейволы настраиваются удалённо, набор доступных продуктов, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код корректно обрабатывает подобные сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать именно 2 продукта. Но если позже вы получите 3 продукта, приложение должно показать все 3 без каких-либо изменений в коде. Единственное, что нужно захардкодить, — это идентификатор плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Объект [`AdaptyPaywall`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) со списком идентификаторов продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение продуктов \{#fetch-products\} Получив пейвол, вы можете запросить массив продуктов, соответствующих ему: ```dart showLineNumbers try { final products = await Adapty().getPaywallProducts(paywall: paywall); // the requested products array } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Параметры ответа: | Параметр | Описание | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Список объектов [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) со следующими свойствами: идентификатор продукта, название продукта, цена, валюта, длительность подписки и ряд других параметров. | При реализации собственного дизайна пейвола вам, скорее всего, потребуется доступ к свойствам объекта [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html). Ниже приведены наиболее часто используемые свойства; полный список доступных свойств см. в документации по ссылке. | Свойство | Описание | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Чтобы отобразить название продукта, используйте `product.localizedTitle`. Локализация основана на выбранной пользователем стране в сторе, а не на локали устройства. | | **Price** | Чтобы отобразить цену в локализованном формате, используйте `product.price.localizedString`. Локализация основана на локали устройства. Также можно получить цену как число через `product.price.amount` — значение будет в местной валюте. Чтобы получить символ валюты, используйте `product.price.currencySymbol`. | | **Subscription Period** | Чтобы отобразить период (например, неделю, месяц, год и т. д.), используйте `product.subscription?.localizedPeriod`. Локализация основана на локали устройства. Чтобы получить период подписки программно, используйте `product.subscription?.period`. Оттуда можно обратиться к enum `unit`, чтобы получить единицу длительности (день, неделя, месяц, год или unknown). Значение `numberOfUnits` вернёт количество единиц периода. Например, для квартальной подписки в свойстве unit будет `AdaptyPeriodUnit.month`, а в numberOfUnits — `3`. | | **Introductory Offer** | Чтобы отобразить бейдж или другой индикатор наличия introductory offer у подписки, проверьте свойство `product.subscription?.offer?.phases`. Это список, который может содержать до двух фаз скидки: фазу бесплатного пробного периода и фазу вводной цены. Каждый объект фазы содержит следующие полезные свойства:необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается, что этот параметр будет представлять собой языковой код, состоящий из одного или нескольких субтегов, разделённых символом минус (**-**). Первый субтег обозначает язык, второй — регион.
Например: `en` означает английский язык, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](flutter-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если вы считаете, что у ваших пользователей нестабильное интернет-соединение, попробуйте использовать `.returnCacheDataElseLoad` — он возвращает кэшированные данные, если они есть. В таком случае пользователи могут не получать самые свежие данные, но зато загрузка будет быстрой вне зависимости от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание, что кэш сохраняется при перезапуске приложения и очищается только при его переустановке или при ручной очистке.
|Если запрос выполнен успешно, ответ содержит этот объект. Объект [AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html) предоставляет исчерпывающую информацию об уровнях доступа пользователя, подписках и разовых покупках в приложении.
Проверьте статус уровня доступа, чтобы убедиться, что пользователь имеет необходимый доступ к приложению.
| :::warning **Примечание:** если вы используете Apple StoreKit версии ниже v2.0 и Adapty SDK версии ниже v2.9.0, вам нужно указать [общий секрет Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret). Этот метод в настоящее время устарел и не рекомендуется Apple. ::: ## Смена подписки при совершении покупки \{#change-subscription-when-making-a-purchase\} Когда пользователь выбирает новую подписку вместо продления текущей, поведение зависит от стора: - В App Store подписка обновляется автоматически в рамках группы подписок. Если пользователь покупает подписку из одной группы, уже имея активную из другой, обе подписки будут активны одновременно. - В Google Play подписка не обновляется автоматически. Переключение нужно реализовать в коде вашего приложения, как описано ниже. Чтобы заменить подписку на другую в Android, вызовите метод `.makePurchase()` с дополнительным параметром: ```dart showLineNumbers try { final subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters( 'OLD_PRODUCT_ID', AdaptyAndroidSubscriptionUpdateReplacementMode.immediateWithTimeProration, ); final result = await Adapty().makePurchase( product: product, parameters: AdaptyPurchaseParameters( subscriptionUpdateParams: subscriptionUpdateParams, ), ); // successful cross-grade } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } ``` Дополнительный параметр запроса: | Параметр | Наличие | Описание | | :--------------------------- | :------- |:--------------------------------------------------------------------------------------------------------| | **parameters** | обязательный | объект `AdaptyPurchaseParameters` с полем `subscriptionUpdateParams`, установленным в объект [`AdaptyAndroidSubscriptionUpdateParameters`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyAndroidSubscriptionUpdateParameters-class.html). | Подробнее о подписках и режимах замены можно прочитать в документации Google для разработчиков: - [О режимах замены](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Рекомендации Google по режимам замены](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Режим замены [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Примечание: этот метод доступен только для повышения уровня подписки. Понижение уровня не поддерживается. - Режим замены [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Примечание: реальное изменение подписки произойдёт только по окончании текущего расчётного периода. ## Активация промокодов в iOS \{#redeem-offer-codes-in-ios\}Объект [`AdaptyProfile`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html). Эта модель содержит информацию об уровнях доступа, подписках и разовых покупках.
Проверьте **статус уровня доступа**, чтобы определить, есть ли у пользователя доступ к приложению.
| :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: --- # File: implement-observer-mode-flutter --- --- title: "Реализация Observer mode во Flutter SDK" description: "Реализуйте Observer mode в Adapty для отслеживания событий подписки пользователей во Flutter SDK." --- Если у вас уже есть собственная инфраструктура покупок и вы не готовы полностью переходить на Adapty, можно воспользоваться [Observer mode](observer-vs-full-mode). В базовом варианте Observer Mode предоставляет расширенную аналитику и бесшовную интеграцию с системами атрибуции и аналитики. Если это подходит вам, нужно лишь: 1. Включить этот режим при настройке SDK, установив параметр `observerMode` в значение `true`. Следуйте инструкциям по настройке для [Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk). 2. [Передавать транзакции](report-transactions-observer-mode-flutter) из вашей существующей инфраструктуры покупок в Adapty. ## Настройка режима Observer \{#observer-mode-setup\} Включите режим Observer, если вы самостоятельно обрабатываете покупки и статус подписки, а Adapty используете только для отправки событий подписки и аналитики. :::important В режиме Observer SDK Adapty не закрывает транзакции самостоятельно — позаботьтесь об этом в своём коде. ::: ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withObserverMode(true) // Enable observer mode ..withLogLevel(AdaptyLogLevel.verbose), ); ``` Параметры: | Параметр | Описание | | --------------------------- | ------------------------------------------------------------ | | observerMode | Булево значение, которое управляет [Observer mode](observer-vs-full-mode). Значение по умолчанию — `false`. | ## Использование пейволов Adapty в Observer Mode \{#using-adapty-paywalls-in-observer-mode\} Если вы также хотите использовать пейволы и A/B-тесты Adapty, это возможно — но в режиме Observer Mode потребуется дополнительная настройка. Вот что нужно сделать помимо шагов выше: 1. Отображайте пейволы как обычно для [пейволов на Remote Config](present-remote-config-paywalls-flutter). 3. [Свяжите пейволы](report-transactions-observer-mode-flutter) с транзакциями покупок. :::tip В SDK v4 вы также можете отображать флоу и пейволы, отрисованные Adapty, в режиме Observer: зарегистрируйте `AdaptyUIObserverModeResolver`, чтобы выполнять покупку или восстановление с помощью вашего собственного кода, когда пользователь нажимает соответствующую кнопку. См. [Отображение флоу в режиме Observer](flutter-present-flows-in-observer-mode). ::: --- # File: report-transactions-observer-mode-flutter --- --- title: "Отчёт о транзакциях в Observer Mode в Flutter SDK" description: "Отправляйте информацию о транзакциях покупок в Adapty Observer Mode для аналитики пользователей и отслеживания дохода во Flutter SDK." ---phoneNumber
firstName
lastName
| String | | gender | Enum, допустимые значения: `female`, `male`, `other` | | birthday | Date | ### Пользовательские атрибуты \{#custom-user-attributes\} Вы можете задавать собственные пользовательские атрибуты — как правило, они связаны с использованием вашего приложения. Например, в фитнес-приложениях это может быть количество тренировок в неделю, в приложениях для изучения языков — уровень знаний пользователя и так далее. Атрибуты можно использовать в сегментах для создания таргетированных пейволов и предложений, а также в аналитике, чтобы понять, какие продуктовые метрики сильнее всего влияют на выручку. ```dart showLineNumbers try { final builder = AdaptyProfileParametersBuilder() ..setCustomStringAttribute('value1', 'key1') ..setCustomDoubleAttribute(1.0, 'key2'); await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Чтобы удалить существующий ключ, используйте метод `.withRemoved(customAttributeForKey:)`: ```dart showLineNumbers try { final builder = AdaptyProfileParametersBuilder() ..removeCustomAttribute('key1') ..removeCustomAttribute('key2'); await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Иногда нужно узнать, какие пользовательские атрибуты уже установлены. Для этого используйте поле `customAttributes` объекта `AdaptyProfile`. :::warning Помните, что значение `customAttributes` может быть устаревшим: атрибуты пользователя могут отправляться с разных устройств в любое время, поэтому данные на сервере могут измениться после последней синхронизации. ::: ### Ограничения \{#limits\} - До 30 пользовательских атрибутов на одного пользователя - Длина имени ключа — не более 30 символов. Допускаются буквенно-цифровые символы, а также: `_` `-` `.` - Значение может быть строкой или числом с плавающей точкой длиной не более 50 символов. --- # File: flutter-listen-subscription-changes --- --- title: "Проверка статуса подписки в Flutter SDK" description: "Отслеживайте и управляйте статусом подписки пользователей в Adapty для повышения удержания клиентов в вашем Flutter-приложении." --- С Adapty отслеживать статус подписки очень просто. Вам не нужно вручную прописывать идентификаторы продуктов в коде. Вместо этого достаточно проверить наличие активного [уровня доступа](access-level), чтобы убедиться, что у пользователя есть подписка.Объект [AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html). Как правило, достаточно проверить статус уровня доступа профиля, чтобы определить, есть ли у пользователя премиум-доступ к приложению.
Метод `.getProfile` возвращает максимально актуальные данные, поскольку всегда обращается к API. Если по какой-то причине (например, при отсутствии интернета) SDK не может получить информацию с сервера, возвращаются данные из кэша. Важно также отметить, что SDK регулярно обновляет кэш `AdaptyProfile`, чтобы поддерживать эту информацию в актуальном состоянии.
| Метод `.getProfile()` возвращает профиль пользователя, из которого можно получить статус уровня доступа. В приложении может быть несколько уровней доступа. Например, если у вас газетное приложение и вы продаёте подписки на разные темы независимо друг от друга, можно создать уровни доступа «sports» и «science». Но в большинстве случаев достаточно одного уровня доступа — тогда можно просто использовать уровень доступа по умолчанию «premium». Вот пример проверки уровня доступа «premium» по умолчанию: ```dart showLineNumbers try { final profile = await Adapty().getProfile(); if (profile?.accessLevels['premium']?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### Отслеживание обновлений статуса подписки \{#listening-for-subscription-status-updates\} Adapty отправляет событие каждый раз, когда подписка пользователя изменяется. Чтобы получать сообщения от Adapty, выполните дополнительную настройку: ```dart showLineNumbers Adapty().didUpdateProfileStream.listen((profile) { // handle any changes to subscription state }); ``` Adapty также отправляет событие при запуске приложения — в этом случае передаётся кэшированный статус подписки. ### Кэш статуса подписки \{#subscription-status-cache\} Кэш в Adapty SDK хранит статус подписки профиля. Это значит, что даже при недоступности сервера можно получить кэшированные данные о статусе подписки профиля. Однако важно учитывать, что прямые запросы данных из кэша невозможны. SDK периодически обращается к серверу каждую минуту, чтобы проверить наличие обновлений или изменений, связанных с профилем. Если появятся какие-либо изменения — например, новые транзакции или другие обновления — они будут отправлены в кэшированные данные, чтобы поддерживать их синхронизацию с сервером. --- # File: flutter-deal-with-att --- --- title: "Работа с ATT во Flutter SDK" description: "Начните работу с Adapty на Flutter для упрощения настройки подписок и управления ими." --- Если ваше приложение использует фреймворк AppTrackingTransparency и запрашивает у пользователя разрешение на отслеживание, необходимо передать [статус авторизации](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) в Adapty. ```dart showLineNumbers final builder = AdaptyProfileParametersBuilder() ..setAppTrackingTransparencyStatus(AdaptyIOSAppTrackingTransparencyStatus.authorized); try { await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle unknown error } ``` :::warning Настоятельно рекомендуем отправлять это значение как можно раньше при каждом его изменении — только в этом случае данные будут своевременно переданы в настроенные вами интеграции. ::: --- # File: kids-mode-flutter --- --- title: "Режим Kids Mode во Flutter SDK" description: "Легко включите Kids Mode для соответствия политикам Apple и Google. IDFA, GAID и рекламные данные не собираются во Flutter SDK." --- Если ваше Flutter-приложение предназначено для детей, необходимо соблюдать политики [Apple](https://developer.apple.com/kids/) и [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Если вы используете Adapty SDK, несколько простых шагов помогут настроить его в соответствии с этими требованиями и успешно пройти проверку в стор. ## Что нужно настроить? \{#whats-required\} Необходимо настроить SDK, чтобы отключить сбор следующих данных: - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS) - [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android) - [IP-адрес](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) Кроме того, рекомендуем осторожно подходить к выбору customer user ID. Идентификатор в формате `необязательный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается код языка, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Например: `en` — английский, `pt-br` — бразильский португальский.
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное соединение, рассмотрите вариант `.returnCacheDataElseLoad`: он возвращает кешированные данные, если они есть. В этом случае пользователи могут получать не самые свежие данные, зато загрузка будет быстрее независимо от качества связи. Кеш обновляется регулярно, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит онбординги локально на двух уровнях: регулярно обновляемый кеш, описанный выше, и резервные онбординги. Для более быстрой загрузки мы также используем CDN и отдельный резервный сервер на случай недоступности CDN. Такая система гарантирует, что вы всегда получаете актуальную версию онбордингов, сохраняя надёжность даже при нестабильном интернете.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут для данного метода. По истечении таймаута возвращаются кешированные данные или локальный резервный вариант.
Обратите внимание, что в редких случаях метод может отработать чуть позже указанного в `loadTimeout` времени, поскольку операция может включать несколько запросов под капотом.
| Параметры ответа: | Параметр | Описание | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Объект [`AdaptyOnboarding`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyOnboarding-class.html), содержащий: идентификатор и конфигурацию онбординга, Remote Config и ряд других свойств. | ## Ускорьте загрузку онбординга с помощью онбординга аудитории по умолчанию \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Как правило, онбординги загружаются почти мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и онбордингов, а у пользователей слабый интернет, загрузка онбординга может занять больше времени, чем хотелось бы. В таких случаях удобно показывать онбординг по умолчанию — чтобы пользователь не видел пустой экран, а получал полноценный опыт. Чтобы решить эту задачу, используйте метод `getOnboardingForDefaultAudience`, который получает онбординг для указанного плейсмента из аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать онбординг через метод `getOnboarding`, как описано в разделе [Получение онбординга](#fetch-onboarding) выше. :::warning Рекомендуется использовать `getOnboarding` вместо `getOnboardingForDefaultAudience`, поскольку последний имеет важные ограничения: - **Проблемы совместимости**: могут возникнуть сложности при поддержке нескольких версий приложения — придётся либо делать обратно совместимый дизайн, либо мириться с тем, что старые версии будут отображать онбординг некорректно. - **Нет персонализации**: отображается только контент для аудитории «Все пользователи», без таргетинга по стране, атрибуции или пользовательским атрибутам. Если для вашего случая скорость загрузки важнее этих недостатков, используйте `getOnboardingForDefaultAudience`, как показано ниже. В противном случае используйте `getOnboarding`, как описано [выше](#fetch-onboarding). ::: ```dart showLineNumbers try { final onboarding = await Adapty().getOnboardingForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` Параметры: | Параметр | Наличие | Описание | |-----------------|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **locale** |необязательный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код из одного или двух подтегов, разделённых знаком минус (**-**). Первый подтег — язык, второй — регион.
Например: `en` — английский, `pt-br` — бразильский португальский.
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если вы считаете, что у ваших пользователей нестабильный интернет, рассмотрите `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут получить не самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в рамках сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется после перезапуска приложения и очищается только при переустановке или вручную.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные онбординги. Для более быстрой загрузки мы используем CDN, а также отдельный резервный сервер на случай недоступности CDN. Эта система гарантирует, что вы всегда получаете актуальную версию онбордингов, даже при нестабильном интернет-соединении.
| --- # File: flutter-present-onboardings --- --- title: "Отображение онбординга во Flutter SDK" description: "Узнайте, как эффективно отображать онбординги для повышения конверсии." --- :::warning **Онбординги устарели в SDK v4 и будут удалены в одном из следующих релизов.** Они больше не получают исправлений и улучшений. Используйте [флоу](flutter-get-pb-paywalls): в отличие от онбордингов, которые работают внутри WebView, флоу рендерятся нативно на устройстве — это даёт более плавные анимации, единый нативный внешний вид, быструю загрузку и отсутствие зависимости от WebView. Подробнее: [Получение флоу и пейволов](flutter-get-pb-paywalls) и [Отображение флоу и пейволов](flutter-present-paywalls). ::: Если вы настроили онбординг с помощью билдера, вам не нужно беспокоиться о его рендеринге в коде Flutter-приложения — всё отображение уже описано внутри самого онбординга. Он содержит как то, что нужно показать, так и то, как это должно выглядеть. Перед началом убедитесь, что: 1. Вы установили [Adapty Flutter SDK](sdk-installation-flutter) версии 3.8.0 или новее. 2. Вы [создали онбординг](create-onboarding). 3. Вы добавили онбординг в [плейсмент](placements). Adapty Flutter SDK предоставляет два способа отображения онбордингов: - **Отдельный экран (Standalone screen)** - **Встроенный виджет (Embedded widget)** ## Отображение как отдельный экран \{#present-as-standalone-screen\} Чтобы отобразить онбординг как отдельный экран, вызовите метод `onboardingView.present()` на объекте `onboardingView`, созданном методом `createOnboardingView`. Каждый `view` можно использовать только один раз. Если нужно снова показать онбординг, вызовите `createOnboardingView` ещё раз, чтобы создать новый экземпляр `onboardingView`. :::warning Повторное использование того же `onboardingView` без его пересоздания может привести к ошибке `AdaptyUIError.viewAlreadyPresented`. ::: ```dart showLineNumbers title="Flutter" try { await onboardingView.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### Закрытие онбординга \{#dismiss-the-onboarding\} Чтобы программно закрыть онбординг, используйте метод `dismiss()`: ```dart showLineNumbers title="Flutter" try { await onboardingView.dismiss(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### Настройка стиля отображения на iOS \{#configure-ios-presentation-style\} Настройте способ отображения онбординга на iOS, передав параметр `iosPresentationStyle` в метод `present()`. Параметр принимает значения `AdaptyUIIOSPresentationStyle.fullScreen` (по умолчанию) или `AdaptyUIIOSPresentationStyle.pageSheet`. ```dart showLineNumbers try { await onboardingView.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ## Встраивание в иерархию виджетов \{#embed-in-widget-hierarchy\} Чтобы встроить онбординг в существующее дерево виджетов, используйте виджет `AdaptyUIOnboardingPlatformView` напрямую в иерархии виджетов Flutter. ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, // The onboarding object you fetched onDidFinishLoading: (meta) { }, onDidFailWithError: (error) { }, onCloseAction: (meta, actionId) { }, onPaywallAction: (meta, actionId) { }, onCustomAction: (meta, actionId) { }, onStateUpdatedAction: (meta, elementId, params) { }, onAnalyticsEvent: (meta, event) { }, ) ``` :::note Чтобы платформенный виджет на Android работал корректно, убедитесь, что ваш `MainActivity` наследует `FlutterFragmentActivity`: ```kotlin showLineNumbers title="Kotlin" class MainActivity : FlutterFragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } ``` ::: ## Загрузка во время онбординга \{#loader-during-onboarding\} При отображении онбординга между сплэш-экраном и самим онбордингом может появиться короткий экран загрузки — пока инициализируется базовое представление. Это можно обработать по-разному в зависимости от ваших потребностей. #### Управление сплэш-экраном через onDidFinishLoading \{#control-splash-screen-using-ondidfinishloading\} :::note Этот подход доступен только при встраивании онбординга как виджета. Для отображения в виде отдельного экрана он недоступен. ::: Рекомендуемый кросс-платформенный подход — держать сплэш-экран или собственный оверлей видимым до тех пор, пока онбординг полностью не загрузится, а затем скрыть его вручную. При использовании встроенного виджета разместите свой виджет поверх него и скройте оверлей, когда сработает `onDidFinishLoading`: ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, onDidFinishLoading: (meta) { // Hide your custom splash screen or overlay here }, // ... other callbacks ) ``` ### Кастомизация нативного загрузчика \{#customize-native-loader\} :::important Этот подход зависит от платформы и требует поддержки нативного UI-кода. Не рекомендуется, если вы не поддерживаете отдельные нативные слои в своём приложении. ::: Если нужно кастомизировать сам загрузчик по умолчанию, его можно заменить платформо-специфичными макетами. Этот подход требует отдельных реализаций для Android и iOS: - **iOS**: добавьте `AdaptyOnboardingPlaceholderView.xib` в ваш Xcode-проект - **Android**: создайте `adapty_onboarding_placeholder_view.xml` в `res/layout` и определите там заглушку ## Настройка открытия ссылок в онбордингах \{#customize-how-links-open-in-onboardings\} :::important Настройка открытия ссылок в онбордингах поддерживается начиная с Adapty SDK v3.15.1. ::: По умолчанию ссылки в онбордингах открываются во встроенном браузере. Это обеспечивает бесшовный пользовательский опыт: веб-страницы отображаются прямо внутри приложения, и пользователю не нужно переключаться между приложениями. Если вы хотите открывать ссылки во внешнем браузере, вы можете изменить это поведение, задав параметру `externalUrlsPresentation` значение `AdaptyWebPresentation.externalBrowser`:
Затем этот ID можно использовать в коде и обрабатывать как пользовательское действие. Например, если пользователь нажимает кастомную кнопку — **Login** или **Allow notifications** — сработает метод делегата `onboardingController` с кейсом `.custom(id:)`, а параметр `actionId` будет равен **Action ID** из билдера. Вы можете создавать собственные ID, например `"allowNotifications"`.
```dart
// Full-screen presentation
void onboardingViewOnCustomAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
switch (actionId) {
case 'login':
_login();
break;
case 'allow_notifications':
_allowNotifications();
break;
}
}
// Embedded widget
onCustomAction: (meta, actionId) {
_handleCustomAction(actionId);
}
```
:::important
Обратите внимание: вам нужно самостоятельно управлять тем, что происходит при закрытии онбординга пользователем. Например, нужно прекратить отображение самого онбординга.
:::
```dart showLineNumbers title="Flutter"
// Full-screen presentation
void onboardingViewOnCloseAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
await view.dismiss();
}
// Embedded widget
onCloseAction: (meta, actionId) {
Navigator.of(context).pop();
}
```
2. Нажмите на название группы подписок. Ваши продукты будут перечислены в разделе **Subscriptions**.
3. Убедитесь, что тестируемый продукт имеет статус **Ready to Submit**.
4. Сравните ID продукта из таблицы с тем, что указан на вкладке [**Products**](https://app.adapty.io/products) в дашборде Adapty. Если ID не совпадают, скопируйте ID продукта из таблицы и [создайте продукт](create-product) с этим ID в дашборде Adapty.
## Шаг 3. Проверьте доступность продукта \{#step-4-check-product-availability\}
1. Вернитесь в **App Store Connect** и откройте тот же раздел **Subscriptions**.
2. Нажмите на название группы подписок, чтобы просмотреть продукты.
3. Выберите тестируемый продукт.
4. Прокрутите до раздела **Availability** и убедитесь, что все необходимые страны и регионы указаны.
## Шаг 4. Проверьте цены продукта \{#step-5-check-product-prices\}
1. Снова перейдите в раздел **Monetization** → **Subscriptions** в **App Store Connect**.
2. Нажмите на название группы подписок.
3. Выберите тестируемый продукт.
4. Прокрутите вниз до раздела **Subscription Pricing** и раскройте секцию **Current Pricing for New Subscribers**.
5. Убедитесь, что все необходимые цены указаны.
## Шаг 5. Убедитесь, что статус платного приложения, банковский счёт и налоговые формы активны \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. На главной странице [**App Store Connect**](https://appstoreconnect.apple.com/) нажмите **Business**.
2. Выберите название своей компании.
3. Прокрутите вниз и убедитесь, что **Paid Apps Agreement**, **Bank Account** и **Tax forms** имеют статус **Active**.
Выполнив эти шаги, вы должны устранить предупреждение `InvalidProductIdentifiers` и сделать продукты доступными в сторе.
## Шаг 6. Пересоздайте продукт, если он завис \{#step-6-recreate-the-product-if-its-stuck\}
Шаги 1–5 могут пройти успешно — статус `Approved`, совпадающий Bundle ID, действительный API-ключ — а SDK всё равно возвращает `1000 noProductIDsFound`. В таком случае продукт может быть завис в реестре Apple. Иногда реестр продуктов Apple входит в состояние, при котором продукт существует в интерфейсе App Store Connect, но недоступен через путь поиска StoreKit.
Удалите продукт в App Store Connect и пересоздайте его с тем же ID. После пересоздания подождите до 24 часов для распространения изменений.
---
# File: cantMakePayments-flutter
---
---
title: "Исправление ошибки Code-1003 cantMakePayment в Flutter SDK"
description: "Решение ошибки при проведении платежей при управлении подписками в Adapty."
---
Ошибка 1003, `cantMakePayments`, означает, что на этом устройстве нельзя совершать встроенные покупки.
Если вы столкнулись с ошибкой `cantMakePayments`, обычно это происходит по одной из следующих причин:
- Ограничения устройства: ошибка не связана с Adapty. Способы решения описаны ниже.
- Настройка Observer mode: метод `makePurchase` и Observer mode нельзя использовать одновременно. Подробнее — в соответствующем разделе ниже.
## Проблема: ограничения устройства \{#issue-device-restrictions\}
| Проблема | Решение |
|---------------------------------|-------------------------------------------------------------------------------------------------------------------|
| Ограничения Screen Time | Отключите ограничения встроенных покупок в [Screen Time](https://support.apple.com/en-us/102470) |
| Аккаунт заблокирован | Обратитесь в службу поддержки Apple для решения проблем с аккаунтом |
| Региональные ограничения | Используйте аккаунт App Store из поддерживаемого региона |
## Проблема: одновременное использование Observer mode и makePurchase \{#issue-using-both-observer-mode-and-makepurchase\}
Если вы используете `makePurchase` для обработки покупок, Observer mode не нужен. [Observer mode](observer-vs-full-mode) требуется только в том случае, если логику покупок вы реализуете самостоятельно.
Таким образом, если вы используете `makePurchase`, можно смело убрать активацию Observer mode из кода инициализации SDK.
---
# File: migration-to-flutter-sdk-v4
---
---
title: "Миграция Adapty Flutter SDK на версию 4.0"
description: "Перейдите на Adapty Flutter SDK v4.0, заменив paywall API на flow API, совместимые как с Flow Builder, так и с Paywall Builder."
---
Adapty Flutter SDK 4.0 вводит флоу и соответственно переименовывает paywall API. Новые API работают как с новым Flow Builder, так и с существующим Paywall Builder — никаких изменений в настройках дашборда Adapty не требуется.
## Краткий справочник \{#quick-reference\}
| v3 | v4 |
|---|---|
| `Adapty().getPaywall(placementId: id)` | `Adapty().getFlow(placementId: id)` |
| `Adapty().getPaywallForDefaultAudience(placementId: id)` | `Adapty().getFlowForDefaultAudience(placementId: id)` |
| `Adapty().getPaywallProducts(paywall: paywall)` | `Adapty().getPaywallProducts(flow: flow)` |
| `Adapty().logShowPaywall(paywall: paywall)` | `Adapty().logShowFlow(flow: flow)` |
| `AdaptyPaywall` (тип) | `AdaptyFlow` |
| `AdaptyPaywallFetchPolicy` (тип) | `AdaptyFlowFetchPolicy` |
| `AdaptyUI().createPaywallView(paywall: paywall)` | `AdaptyUI().createFlowView(flow: flow)` |
| `AdaptyUIPaywallView` (тип) | `AdaptyUIFlowView` |
| `AdaptyUIPaywallPlatformView` (виджет) | `AdaptyUIFlowPlatformView` |
| `AdaptyUI().presentPaywallView(view)` / `dismissPaywallView(view)` | `AdaptyUI().presentFlowView(view)` / `dismissFlowView(view)` |
| `AdaptyUIPaywallsEventsObserver` | `AdaptyUIFlowsEventsObserver` |
| `AdaptyUI().setPaywallsEventsObserver(observer)` | `AdaptyUI().setFlowsEventsObserver(observer)` |
| Колбэки `paywallViewDid*` | Колбэки `flowViewDid*` |
| `paywallViewDidFailRendering` | `flowViewDidReceiveError` |
`AdaptyPaywallProduct` сохраняет своё название — продукты по-прежнему принадлежат флоу, а `getPaywallProducts` теперь принимает `AdaptyFlow`. При получении флоу больше не нужно передавать `locale`. API для покупок и профиля (`makePurchase`, `restorePurchases`, `getProfile`, `identify` и т. д.) остался без изменений, как и методы работы с представлениями `present`, `dismiss` и `showDialog`. Часть поведения по умолчанию изменилась — см. [Изменения поведения по умолчанию](#default-behavior-changes).
## Минимальные требования \{#minimum-versions\}
Adapty Flutter SDK 4.0 повышает минимальные требования:
- **iOS 15.0** — минимальная цель развёртывания iOS, повышена с iOS 13.0.
- **Xcode 26** или новее — нативный iOS SDK использует Swift tools 6.2.
- **Flutter 3.32.0** (Dart 3.8.0) или новее.
## Установка \{#installation\}
### Обновите пакет \{#update-the-package\}
Какой пакет устанавливать, зависит от того, используется ли в вашем приложении Kids Mode.
Для большинства приложений обновите `adapty_flutter` до версии 4.0 в файле `pubspec.yaml`:
```yaml showLineNumbers title="pubspec.yaml"
dependencies:
adapty_flutter: 4.0.0
```
Если ваше приложение использует Kids Mode, укажите вместо него `adapty_flutter_kids`:
```yaml showLineNumbers title="pubspec.yaml"
dependencies:
adapty_flutter_kids: 4.0.0
```
Этот **автономный** пакет удаляет IDFA и код отслеживания рекламы для соответствия требованиям App Store. Обновите путь импорта Dart на `package:adapty_flutter_kids/adapty_flutter.dart`. В остальном миграция полностью идентична обычному пакету.
Kids Mode также требует отключения сбора IP-адресов в дашборде Adapty — полную инструкцию по настройке см. в разделе [Kids Mode](kids-mode-flutter).
### iOS: нативные SDK теперь поставляются через Swift Package Manager \{#ios-native-sdks-now-come-through-swift-package-manager\}
[Репозиторий спецификаций CocoaPods становится доступным только для чтения в декабре 2026 года](https://blog.cocoapods.org/CocoaPods-Specs-Repo/), поэтому начиная с v4 нативный iOS SDK **больше не распространяется через CocoaPods** — плагин получает его только через **Swift Package Manager**.
Если вы используете Flutter 3.32–3.43, один раз включите поддержку Swift Package Manager:
```bash
flutter config --enable-swift-package-manager
```
В Flutter 3.44 и выше Swift Package Manager включён по умолчанию, так что никаких дополнительных действий не требуется.
## Получение флоу \{#fetching-flows\}
### getPaywall → getFlow
Возвращаемый тип меняется с `AdaptyPaywall` на `AdaptyFlow`, и теперь не нужно передавать `locale` — при отображении флоу локализация определяется автоматически; для кастомных пейволов все настроенные локали возвращаются в `flow.remoteConfigs`:
```diff showLineNumbers
- final paywall = await Adapty().getPaywall(placementId: 'YOUR_PLACEMENT_ID', locale: 'en');
+ final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID');
```
`getPaywallForDefaultAudience` переименовывается аналогично:
```diff showLineNumbers
- final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID', locale: 'en');
+ final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID');
```
Тип политики загрузки переименован с `AdaptyPaywallFetchPolicy` на `AdaptyFlowFetchPolicy`; его варианты (`reloadRevalidatingCacheData`, `returnCacheDataElseLoad`, `returnCacheDataIfNotExpiredElseLoad`) остались без изменений.
### getPaywallProducts(paywall) → getPaywallProducts(flow)
`getPaywallProducts` сохраняет своё название, но теперь принимает `AdaptyFlow` через параметр `flow`:
```diff showLineNumbers
- final products = await Adapty().getPaywallProducts(paywall: paywall);
+ final products = await Adapty().getPaywallProducts(flow: flow);
```
## Модель данных \{#data-model\}
`getFlow` возвращает `AdaptyFlow` вместо `AdaptyPaywall`, и структура объекта изменилась:
| Член `AdaptyPaywall` v3 | Член `AdaptyFlow` v4 | Действие |
|---|---|---|
| `remoteConfig` (один, nullable) | `remoteConfigs` (список) | Флоу хранит один Remote Config на каждый настроенный язык. Геттер `remoteConfig` по-прежнему существует и возвращает первую запись; чтобы выбрать конкретный язык, найдите нужную запись в `remoteConfigs` по полю `locale`. |
| `productIdentifiers` | `productIdentifiers` | Сохранён, но теперь объединяет идентификаторы из всех вариаций пейволов флоу. Идентификаторы для каждой вариации доступны через `flow.paywalls[i].productIdentifiers`. |
| `hasViewConfiguration` | `hasViewConfiguration` | Без изменений. |
| `placementId` (устарело) | удалён | Используйте `flow.placement.id`. |
| `revision` (устарело) | удалён | Используйте `flow.placement.revision`. |
| `vendorProductIds` (устарело) | удалён | Используйте `productIdentifiers`. |
| _(новое)_ | `paywalls` (список `AdaptyFlowPaywall`) | Каждый элемент — одна вариация пейвола во флоу со своими `name`, `variationId` и `productIdentifiers`. |
`AdaptyPaywallViewConfiguration` больше не предоставляется публично — конфигурация представления теперь непрозрачна. Удалите все ссылки на этот тип.
## Методы веб-пейвола \{#web-paywall-methods\}
`openWebPaywall` и `createWebPaywallUrl` сохраняют свои названия, но параметр `paywall` теперь принимает `AdaptyFlowPaywall` (вариант флоу) вместо `AdaptyPaywall`. По-прежнему можно передать `AdaptyPaywallProduct`.
```diff showLineNumbers
final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID');
- await Adapty().openWebPaywall(paywall: paywall);
+ if (flow.paywalls.isNotEmpty) {
+ await Adapty().openWebPaywall(paywall: flow.paywalls[0]);
+ }
```
## Отслеживание просмотров флоу \{#tracking-flow-views\}
### logShowPaywall → logShowFlow
`logShowPaywall` переименован в `logShowFlow` и теперь принимает `AdaptyFlow`. Событие по-прежнему фиксируется для той же вариации, поэтому существующие метрики воронки и A/B-тестов продолжают работать без изменений в дашборде.
```diff showLineNumbers
- await Adapty().logShowPaywall(paywall: paywall);
+ await Adapty().logShowFlow(flow: flow);
```
Как и в v3, вызывать этот метод при отображении флоу или пейволов, отрисованных с помощью [Flow Builder](adapty-flow-builder) или [Paywall Builder](adapty-paywall-builder), не нужно — Adapty отслеживает эти просмотры автоматически.
## Отображение флоу \{#displaying-flows\}
### createPaywallView → createFlowView
Переименуйте метод и передайте `AdaptyFlow` через параметр `flow`. Остальные параметры (`loadTimeout`, `preloadProducts`, `customTags`, `customTimers`, `customAssets`, `productPurchaseParams`) остаются без изменений, как и методы представления `present`, `dismiss` и `showDialog`:
```diff showLineNumbers
- final view = await AdaptyUI().createPaywallView(paywall: paywall);
+ final view = await AdaptyUI().createFlowView(flow: flow);
await view.present();
```
### AdaptyUIPaywallView → AdaptyUIFlowView
Тип представления переименован. Устаревшее свойство `paywallVariationId` удалено — используйте `variationId`:
```diff showLineNumbers
- void flowViewDidAppear(AdaptyUIPaywallView view) {
+ void flowViewDidAppear(AdaptyUIFlowView view) {
```
### AdaptyUIPaywallPlatformView → AdaptyUIFlowPlatformView
Если вы встраиваете представление как виджет в дерево виджетов, переименуйте его и передайте параметр `flow`. Колбэки событий (`onDidAppear`, `onDidFinishPurchase` и так далее) сохраняют свои названия:
```diff showLineNumbers
- AdaptyUIPaywallPlatformView(
- paywall: paywall,
+ AdaptyUIFlowPlatformView(
+ flow: flow,
onDidFinishPurchase: (view, product, purchaseResult) { /* … */ },
)
```
:::note
Представление флоу, созданное с помощью `createFlowView`, одноразовое: после вызова `dismiss()` оно освобождается из памяти и не может быть показано повторно — вызовите `createFlowView` снова, чтобы отобразить флоу ещё раз.
:::
## Обработка событий \{#handling-events\}
Класс-наблюдатель переименован с `AdaptyUIPaywallsEventsObserver` на `AdaptyUIFlowsEventsObserver`, метод его регистрации — с `setPaywallsEventsObserver` на `setFlowsEventsObserver`, а все колбэки `paywallViewDid*` — на `flowViewDid*`:
```diff showLineNumbers
- class MyObserver extends AdaptyUIPaywallsEventsObserver {
+ class MyObserver extends AdaptyUIFlowsEventsObserver {
@override
- void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) {
+ void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) {
// …
}
}
- AdaptyUI().setPaywallsEventsObserver(this);
+ AdaptyUI().setFlowsEventsObserver(this);
```
Три коллбэка теперь **обязательны** — без них наблюдатель не скомпилируется:
- **`flowViewDidFinishPurchase`**: В v3 был опциональным — по умолчанию закрывал вью после покупки. Теперь вы сами решаете, что произойдёт: продолжить флоу или вызвать `view.dismiss()`.
- **`flowViewDidFinishRestore`**: Обязательный, как и в v3.
- **`flowViewDidReceiveError`**: Заменяет `paywallViewDidFailRendering` и теперь также получает другие ошибки вью.
Два небольших изменения:
- `setFlowsEventsObserver` (и `setOnboardingsEventsObserver`) теперь принимают `null`, чтобы отвязать ранее установленный наблюдатель — SDK больше не удерживает его.
- Новый необязательный коллбэк `flowViewDidReceiveAnalyticEvent` зарезервирован для пользовательских аналитических событий из флоу. Флоу пока не отправляют их в ваш код, поэтому реализовывать его не нужно.
В v4 также появились возможности, которые можно подключить по желанию:
- `AdaptyUI().setObserverModeResolver(...)` с `AdaptyUIObserverModeResolver` — управляет покупками и восстановлениями, инициированными из флоу, когда SDK работает в [режиме Observer](implement-observer-mode-flutter). Ранее это было доступно только в нативных SDK для iOS и Android. См. [Показ флоу в режиме Observer](flutter-present-flows-in-observer-mode).
- `AdaptyUI().setSystemRequestsHandler(...)` с `AdaptyUISystemRequestsHandler` — зарезервировано для системных запросов из флоу (запросы разрешений ОС и запросы на отзыв в App Store). Флоу пока не инициируют такие запросы, поэтому регистрировать обработчик не нужно.
## Удалённые API \{#removed-apis\}
Эти символы были помечены как устаревшие в версии 3.x и удалены в v4:
### setFallbackPaywalls → setFallback
```diff showLineNumbers
- await Adapty().setFallbackPaywalls(assetId);
+ await Adapty().setFallback(assetId);
```
### withIdfaCollectionDisabled → withAppleIdfaCollectionDisabled
```diff showLineNumbers
configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
- ..withIdfaCollectionDisabled(true),
+ ..withAppleIdfaCollectionDisabled(true),
```
### Другие удалённые элементы
- **`AdaptyPurchaseResultSuccess.jwsTransaction`**: Используйте `appleJwsTransaction`.
- **`AdaptyUIFlowView.paywallVariationId`**: Используйте `variationId`.
- **`AdaptyUIObserver` и `AdaptyUI().setObserver(...)`**: Используйте `AdaptyUIFlowsEventsObserver` и `setFlowsEventsObserver(...)`.
## Изменения поведения по умолчанию \{#default-behavior-changes\}
Эти изменения не вызывают ошибок компиляции, поэтому проверяйте их во время выполнения:
- **Успешная покупка**: В v3 дефолтный `paywallViewDidFinishPurchase` закрывал экран. В v4 `flowViewDidFinishPurchase` обязателен и не имеет реализации по умолчанию — закрывайте экран самостоятельно, если хотите такого поведения.
- **Системная кнопка «Назад» на Android**: Она больше не закрывает флоу по умолчанию. Действие передаётся в `flowViewDidPerformAction` как `AndroidSystemBackAction` — обработайте его там, если хотите, чтобы кнопка «Назад» закрывала флоу.
- **Открытие URL**: Дефолтный `flowViewDidPerformAction` теперь обрабатывает `OpenUrlAction`, открывая URL нативно (с учётом настройки встроенного или внешнего браузера из дашборда), а также закрывает экран по `CloseAction`. Переопределите коллбэк, чтобы обрабатывать URL самостоятельно.
- **Ошибки экрана**: `flowViewDidReceiveError` обязателен, и закрытие экрана зависит от вашей реализации. Если в v3 ваша интеграция рассчитывала на автоматическое закрытие при ошибках рендеринга, вызывайте `view.dismiss()` в этом коллбэке.
- **Жизненный цикл экрана**: Закрытие флоу или онбординга освобождает его из памяти. Закрытый экран нельзя показать повторно — создайте новый.
## Устаревший API онбординга \{#onboarding-api-deprecation\}
Устаревший API онбординга объявлен устаревшим в v4.0 в пользу [Flow Builder](adapty-flow-builder). Он по-прежнему работает, а IDE помечает устаревшие символы через аннотации `@Deprecated` — никаких предупреждений во время выполнения нет. Эти символы будут удалены в одном из следующих релизов, поэтому планируйте переход ваших онбордингов на Flow Builder.
Устаревшие символы: `getOnboarding`, `getOnboardingForDefaultAudience`, `createOnboardingView`, `presentOnboardingView`, `dismissOnboardingView`, `setOnboardingsEventsObserver`, `AdaptyOnboarding`, `AdaptyUIOnboardingView`, `AdaptyUIOnboardingPlatformView`, `AdaptyUIOnboardingsEventsObserver`, а также модели состояния, ввода и аналитики онбординга.
---
# File: flutter-migration-guide-310
---
---
title: "Руководство по миграции на Flutter Adapty SDK 3.10.0"
description: ""
---
Adapty SDK 3.10.0 — это крупный релиз с рядом улучшений, которые могут потребовать миграции:
1. Обновите метод `makePurchase`, чтобы использовать `AdaptyPurchaseParameters` вместо отдельных параметров.
2. Замените `vendorProductIds` на `productIdentifiers` в модели `AdaptyPaywall`.
## Обновление метода makePurchase \{#update-makepurchase-method\}
Метод `makePurchase` теперь принимает `AdaptyPurchaseParameters` вместо отдельных аргументов `subscriptionUpdateParams` и `isOfferPersonalized`. Это обеспечивает более строгую типизацию и упрощает добавление новых параметров покупки в будущем.
```diff showLineNumbers
- final purchaseResult = await adapty.makePurchase(
- product: product,
- subscriptionUpdateParams: subscriptionUpdateParams,
- isOfferPersonalized: true,
- );
+ final parameters = AdaptyPurchaseParametersBuilder()
+ ..setSubscriptionUpdateParams(subscriptionUpdateParams)
+ ..setIsOfferPersonalized(true)
+ ..setObfuscatedAccountId('your-account-id')
+ ..setObfuscatedProfileId('your-profile-id');
+ final purchaseResult = await adapty.makePurchase(
+ product: product,
+ parameters: parameters.build(),
+ );
```
Если дополнительные параметры не нужны, достаточно написать:
```dart showLineNumbers
final purchaseResult = await adapty.makePurchase(
product: product,
);
```
## Обновление использования модели AdaptyPaywall \{#update-adaptypaywall-model-usage\}
Свойство `vendorProductIds` устарело и заменено на `productIdentifiers`. Новое свойство возвращает объекты `AdaptyProductIdentifier` вместо обычных строк, что обеспечивает более структурированную информацию о продуктах.
```diff showLineNumbers
- paywall.vendorProductIds.map((vendorId) =>
- ListTextTile(title: vendorId)
- ).toList()
+ paywall.productIdentifiers.map((productId) =>
+ ListTextTile(title: productId.vendorProductId)
+ ).toList()
```
Объект `AdaptyProductIdentifier` предоставляет доступ к идентификатору продукта через свойство `vendorProductId`, сохраняя прежнюю функциональность и обеспечивая лучшую структуру для будущих улучшений.
## Обратная совместимость \{#backward-compatibility\}
Оба изменения обратно совместимы:
- Старые параметры в `makePurchase` устарели, но продолжают работать
- Свойство `vendorProductIds` устарело, но по-прежнему доступно
- Существующий код продолжит работать, однако будут отображаться предупреждения об устаревании
Рекомендуем перейти на новые API, чтобы обеспечить совместимость в будущем и воспользоваться преимуществами улучшенной типизации и расширяемости.
---
# File: flutter-migration-guide-38
---
---
title: "Миграция Adapty Flutter SDK на v. 3.8"
description: "Перейдите на Adapty Flutter SDK v3.8 для улучшения производительности и новых возможностей монетизации."
---
Adapty SDK 3.8.0 — это мажорный релиз, который принёс ряд улучшений, требующих выполнения нескольких шагов миграции.
1. Обновите названия класса и методов наблюдателя.
2. Обновите название метода для резервных пейволов.
3. Обновите название класса представления в методах обработки событий.
## Обновление класса и методов наблюдателя \{#update-observer-class-and-method-names\}
Класс наблюдателя и метод его регистрации были переименованы:
```diff showLineNumbers
- class MyObserver extends AdaptyUIObserver {
+ class MyObserver extends AdaptyUIPaywallsEventsObserver {
@override
void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) {
// Handle action
}
}
// Register observer
- AdaptyUI().setObserver(this);
+ AdaptyUI().setPaywallsEventsObserver(this);
```
## Обновление названия метода для резервных пейволов \{#update-fallback-paywalls-method-name\}
Метод установки резервных пейволов был упрощён:
```diff showLineNumbers
try {
- await Adapty.setFallbackPaywalls(assetId);
+ await Adapty.setFallback(assetId);
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
// handle the error
}
```
## Обновление имени класса представления в методах обработки событий \{#update-view-class-name-in-event-handling-methods\}
Все методы обработки событий теперь используют новый класс `AdaptyUIPaywallView` вместо `AdaptyUIView`:
```diff showLineNumbers
- void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action)
+ void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action)
- void paywallViewDidSelectProduct(AdaptyUIView view, AdaptyPaywallProduct product)
+ void paywallViewDidSelectProduct(AdaptyUIPaywallView view, AdaptyPaywallProduct product)
- void paywallViewDidStartPurchase(AdaptyUIView view, AdaptyPaywallProduct product)
+ void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product)
- void paywallViewDidFinishPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyProfile profile)
+ void paywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyProfile profile)
- void paywallViewDidFailPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyError error)
+ void paywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error)
- void paywallViewDidFinishRestore(AdaptyUIView view, AdaptyProfile profile)
+ void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile)
- void paywallViewDidFailRestore(AdaptyUIView view, AdaptyError error)
+ void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error)
- void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error)
+ void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error)
- void paywallViewDidFailRendering(AdaptyUIView view, AdaptyError error)
+ void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error)
```
---
# File: migration-to-flutter-sdk-34
---
---
title: "Миграция Adapty Flutter SDK на v. 3.4"
description: "Мигрируйте на Adapty Flutter SDK v3.4 для повышения производительности и доступа к новым функциям монетизации."
---
Adapty SDK 3.4.0 — это мажорный релиз, который вносит изменения, требующие миграции с вашей стороны.
## Обновите файлы резервных пейволов \{#update-fallback-paywall-files\}
Обновите файлы резервных пейволов, чтобы обеспечить совместимость с новой версией SDK:
1. [Скачайте обновлённые файлы резервных пейволов](fallback-paywalls) из дашборда Adapty.
2. [Замените существующие резервные пейволы в своём мобильном приложении](flutter-use-fallback-paywalls) новыми файлами.
## Обновите реализацию Observer Mode \{#update-implementation-of-observer-mode\}
Если вы используете Observer Mode, обновите его реализацию.
Раньше для передачи транзакций в Adapty использовались разные методы. В новой версии метод `reportTransaction` следует использовать единообразно как на Android, так и на iOS. Этот метод явно передаёт каждую транзакцию в Adapty, гарантируя её распознавание. Если использовался пейвол, передайте variation ID, чтобы привязать транзакцию к нему.
:::warning
**Не пропускайте передачу информации о транзакции!**
Если вы не вызовете `reportTransaction`, Adapty не распознает транзакцию, она не появится в аналитике и не будет отправлена в интеграции.
:::
```diff showLineNumbers
- // every time when calling transaction.finish()
- if (Platform.isAndroid) {
- try {
- await Adapty().restorePurchases();
- } on AdaptyError catch (adaptyError) {
- // handle the error
- } catch (e) {
- }
- }
try {
// every time when calling transaction.finish()
await Adapty().reportTransaction(
"YOUR_TRANSACTION_ID",
variationId: "PAYWALL_VARIATION_ID", // optional
);
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
// handle the error
}
```
---
# File: migration-to-flutter330
---
---
title: "Миграция Adapty Flutter SDK на v3.3"
description: "Перейдите на Adapty Flutter SDK v3.3 для улучшения производительности и новых функций монетизации."
---
Adapty SDK 3.3.0 — это крупный релиз, который принёс ряд улучшений, однако для перехода на него могут потребоваться некоторые шаги миграции.
1. Обновите метод предоставления резервных пейволов.
2. Удалите метод `getProductsIntroductoryOfferEligibility`.
3. Обновите настройки интеграций для Adjust, AirBridge, Amplitude, AppMetrica, Appsflyer, Branch, Facebook Ads, Firebase и Google Analytics, Mixpanel, OneSignal, Pushwoosh.
4. Обновите реализацию режима Observer.
## Обновление метода для предоставления резервных пейволов \{#update-method-for-providing-fallback-paywalls\}
Раньше метод принимал резервный пейвол в виде JSON-строки (`jsonString`), теперь вместо этого он принимает путь к локальному файлу резервного пейвола (`assetId`).
```diff showLineNumbers
import 'dart:async' show Future;
import 'dart:io' show Platform;
-import 'package:flutter/services.dart' show rootBundle;
-final filePath = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json';
-final jsonString = await rootBundle.loadString(filePath);
+final assetId = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json';
try {
- await adapty.setFallbackPaywalls(jsonString);
+ await adapty.setFallbackPaywalls(assetId);
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
}
```
Полный пример кода смотрите на странице [Использование резервных пейволов](flutter-use-fallback-paywalls).
## Удаление метода `getProductsIntroductoryOfferEligibility` \{#remove-getproductsintroductoryoffereligibility-method\}
До Adapty iOS SDK 3.3.0 объект продукта всегда включал офферы вне зависимости от того, подходит ли для них пользователь. Вам нужно было проверять eligibility вручную перед использованием оффера.
Теперь объект продукта включает оффер только в том случае, если пользователь на него подходит. Это значит, что проверять eligibility больше не нужно — если оффер присутствует, пользователь подходит для него.
## Обновление конфигурации SDK сторонних интеграций \{#update-third-party-integration-sdk-configuration\}
Чтобы интеграции корректно работали с Adapty Flutter SDK 3.3.0 и новее, обновите конфигурации SDK для следующих интеграций согласно инструкциям ниже.
### Adjust
Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Настройка SDK для интеграции с Adjust](adjust#connect-your-app-to-adjust).
```diff showLineNumbers
import 'package:adjust_sdk/adjust.dart';
import 'package:adjust_sdk/adjust_config.dart';
try {
final adid = await Adjust.getAdid();
if (adid == null) {
// handle the error
}
+ await Adapty().setIntegrationIdentifier(
+ key: "adjust_device_id",
+ value: adid,
+ );
final attributionData = await Adjust.getAttribution();
var attribution = MapБулево значение, управляющее [режимом Observer](observer-vs-full-mode). Включите его, если вы самостоятельно обрабатываете покупки и статус подписки, а Adapty используете только для отправки событий подписки и аналитики.
Значение по умолчанию: `false`.
🚧 В режиме Observer Adapty SDK не закрывает транзакции — убедитесь, что вы обрабатываете их самостоятельно.
| | **withCustomerUserId** | опциональный | Идентификатор пользователя в вашей системе. Мы передаём его в событиях подписки и аналитики, чтобы привязать события к нужному профилю. Вы также можете искать пользователей по `customerUserId` в меню [**Profiles and Segments**](https://app.adapty.io/profiles/users). | | **withIdfaCollectionDisabled** | опциональный |Установите значение `true`, чтобы отключить сбор и передачу IDFA.
а также передачу IP-адреса пользователя.
Значение по умолчанию: `false`.
Подробнее о сборе IDFA см. в разделе [Интеграция с аналитикой](analytics-integration#disable-collection-of-advertising-identifiers).
| | **withIpAddressCollectionDisabled** | опциональный |Установите значение `true`, чтобы отключить сбор и передачу IP-адреса пользователя.
Значение по умолчанию: `false`.
| ### Активация модуля AdaptyUI в SDK Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Настраивать модуль AdaptyUI нужно только в том случае, если вы планируете использовать [Paywall Builder](adapty-paywall-builder): ```dart showLineNumbers title="Dart" try { final mediaCache = AdaptyUIMediaCacheConfiguration( memoryStorageTotalCostLimit: 100 * 1024 * 1024, // 100MB memoryStorageCountLimit: 2147483647, // 2^31 - 1, max int value in Dart diskStorageSizeLimit: 100 * 1024 * 1024, // 100MB ); await AdaptyUI().activate( configuration: AdaptyUIConfiguration(mediaCache: mediaCache), observer:
### При входе в систему или регистрации \{#during-loginsignup\}
Если вы идентифицируете пользователей уже после запуска приложения (например, после входа в аккаунт или регистрации), используйте метод `identify`, чтобы задать их customer user ID.
- Если вы **раньше не использовали этот customer user ID**, Adapty автоматически привяжет его к текущему профилю.
- Если вы **уже использовали этот customer user ID для идентификации пользователя**, Adapty переключится на работу с профилем, связанным с этим customer user ID.
:::important
Идентификаторы пользователей должны быть уникальными для каждого пользователя. Если задать значение параметра жёстко в коде, все пользователи будут считаться одним.
:::
Всегда используйте `await` для `identify` перед вызовом других методов SDK. Параллельные вызовы приводят к ошибке `#3006 profileWasChanged` или попаданию в анонимный профиль. Подробнее: [Порядок вызовов в iOS SDK](ios-sdk-call-order).
По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильный интернет, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, но загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при переустановке или вручную.
Adapty SDK хранит пейволы локально на двух уровнях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Мы также используем CDN для более быстрой загрузки пейволов и отдельный резервный сервер на случай недоступности CDN. Система разработана так, чтобы вы всегда получали актуальную версию пейволов, даже при нестабильном интернете.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут метода. Если таймаут истёк, будут возвращены кешированные данные или локальный резервный пейвол.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeout`, поскольку операция может состоять из нескольких внутренних запросов.
| Параметры ответа: | Параметр | Описание | | :-------- | :---------- | | Flow | Объект `AdaptyFlow`, содержащий плейсмент, идентификаторы (`id`, `variationId`), имя, Remote Config и флаг `hasViewConfiguration`, указывающий, включает ли флоу конфигурацию представления. Чтобы получить продукты для предзагрузки, кастомного UI или программных проверок, вызовите `getPaywallProducts(flow:)`. | ## Получение конфигурации представления \{#fetch-the-view-configuration\} После получения флоу или пейвола проверьте, включает ли он конфигурацию представления, с помощью `flow.hasViewConfiguration`. Этот флаг показывает, как был создан плейсмент в дашборде Adapty: - **`true`** — плейсмент создан во **Flow Builder** (флоу) или **Paywall Builder** (пейвол). Adapty отрисовывает интерфейс за вас. Продолжайте выполнять шаги ниже, чтобы получить конфигурацию представления и [показать флоу или пейвол](ios-present-paywalls). - **`false`** — плейсмент является кастомным пейволом без интерфейса Builder. Используйте метод `getFlowConfiguration`, чтобы загрузить конфигурацию представления. ```swift showLineNumbers guard flow.hasViewConfiguration else { // handle as remote config paywall return } let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) ``` Параметры: | Параметр | Наличие | Описание | | :----------------------- | :------------- | :---------- | | **forFlow** | обязательный | Объект `AdaptyFlow`, полученный через `Adapty.getFlow`. | | **locale** |необязательный
по умолчанию: `nil`
| Идентификатор [локализации пейвола](add-paywall-locale-in-adapty-paywall-builder). Ожидается в виде языкового кода с одним или двумя подтегами, разделёнными `-` (например, `en`, `pt-br`). См. [Локализации и коды локалей](localizations-and-locale-codes). | | **loadTimeout** | по умолчанию: 5 сек | Ограничивает тайм-аут для этого метода. Если тайм-аут истекает, возвращаются кэшированные данные или локальный резервный пейвол. Обратите внимание, что в редких случаях метод может завершиться чуть позже указанного в `loadTimeout` значения, поскольку операция может включать несколько запросов. | | **products** | необязательный | Передайте массив объектов `AdaptyPaywallProduct`, чтобы оптимизировать время отображения продуктов на экране. Если передать `nil`, AdaptyUI автоматически загрузит необходимые продукты. | | **systemRequestsHandler** | необязательный | Объект, реализующий `AdaptySystemRequestsHandler`, который обрабатывает запросы системных разрешений и запросы на отзыв, инициированные действиями флоу. Требуется только если ваш флоу включает такие действия. | | **assetsResolver** | необязательный | Словарь `[String: AdaptyCustomAsset]`, переопределяющий изображения и видео во флоу/пейволе. См. [Настройка ресурсов](#customize-assets). | | **timerResolver** | необязательный | Объект, реализующий `AdaptyTimerResolver`, который предоставляет даты окончания для таймеров, определённых разработчиком. См. [Настройка таймеров разработчика](#set-up-developer-defined-timers). | После загрузки [отобразите флоу/пейвол](ios-present-paywalls). ## Получите флоу или пейвол для аудитории по умолчанию, чтобы ускорить загрузку \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} Как правило, флоу и пейволы загружаются почти мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и плейсментов, а пользователи работают с медленным интернетом, загрузка флоу или пейвола может занять больше времени, чем хотелось бы. В таких ситуациях имеет смысл показывать флоу или пейвол по умолчанию — это обеспечит плавный пользовательский опыт вместо пустого экрана. Чтобы решить эту проблему, используйте метод `getFlowForDefaultAudience`, который получает флоу или пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать флоу или пейвол через метод `getFlow`, как описано в разделе [Получение информации о пейволе](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) выше. :::warning Почему мы рекомендуем использовать `getFlow` Метод `getFlowForDefaultAudience` имеет ряд существенных недостатков: - **Потенциальные проблемы обратной совместимости**: если нужно показывать разные пейволы для разных версий приложения (текущей и будущих), могут возникнуть сложности. Придётся либо проектировать пейволы с учётом текущей (устаревшей) версии, либо смириться с тем, что пользователи на ней могут столкнуться с нерендерящимися пейволами. - **Потеря таргетинга**: все пользователи будут видеть один и тот же пейвол, настроенный для аудитории **All Users**, — а значит, вы теряете персонализированный таргетинг (в том числе по странам, маркетинговой атрибуции или собственным кастомным атрибутам). Если вы готовы принять эти ограничения ради более быстрой загрузки флоу или пейвола, используйте метод `getFlowForDefaultAudience` следующим образом. В противном случае используйте `getFlow`, описанный [выше](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder). ::: ```swift showLineNumbers Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` | Параметр | Обязательность | Описание | |---------|--------|-----------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера, а в случае ошибки возвращает кешированные данные. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad`: он возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому использовать его в течение сессии для снижения количества сетевых запросов безопасно.
Обратите внимание: кеш сохраняется после перезапуска приложения и очищается только при его переустановке или принудительной очистке вручную.
| ## Настройка ресурсов \{#customize-assets\} Чтобы кастомизировать изображения и видео в пейволе или флоу, используйте пользовательские ресурсы. Для hero-изображений и видео есть предопределённые идентификаторы: `hero_image` и `hero_video`. В пакете пользовательских ресурсов вы обращаетесь к этим элементам по их идентификаторам и задаёте нужное поведение. Для остальных изображений и видео необходимо [задать пользовательский идентификатор](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разные изображения или видео разным пользователям. - Показывать локальное превью, пока загружается основное изображение с сервера. - Показывать превью перед воспроизведением видео. - Указать разрешение видео в пикселях, чтобы плеер заранее зарезервировал место в макете (соотношение сторон = `width / height`) до загрузки видео. Передайте `nil`, чтобы пропустить этот параметр. Вот пример того, как передавать пользовательские ресурсы через простой словарь: ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Show a local image using a custom ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Show a local preview image while a remote main image is loading "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Show a local video with a preview image and a known resolution "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!), resolution: CGSize(width: 1080, height: 1920) ) ), ] let flowConfig = try await AdaptyUI.getFlowConfiguration( forFlow: flow, assetsResolver: customAssets ) ``` :::note Если ресурс не найден, пейвол/флоу отобразится с внешним видом по умолчанию. ::: ## Настройка таймеров, заданных разработчиком \{#set-up-developer-defined-timers\} Чтобы использовать пользовательские таймеры в мобильном приложении, создайте объект, реализующий протокол `AdaptyTimerResolver`. Этот объект определяет, как должен отображаться каждый таймер. Если хотите, можно напрямую использовать словарь `[String: Date]` — он уже соответствует этому протоколу. Пример: ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 hour } } } ``` В этом примере `CUSTOM_TIMER_NY` и `CUSTOM_TIMER_6H` — это **Timer ID** пользовательских таймеров, заданных вами в дашборде Adapty. `timerResolver` гарантирует, что приложение динамически обновляет каждый таймер правильным значением. Например: - `CUSTOM_TIMER_NY`: время, оставшееся до окончания таймера, например до Нового года. - `CUSTOM_TIMER_6H`: время, оставшееся в 6-часовом периоде, который начался, когда пользователь открыл пейвол.необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-paywall-locale-in-adapty-paywall-builder). Ожидается в виде языкового кода из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Например: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кешированные данные при их наличии. В этом случае пользователи могут получить не самые последние данные, зато время загрузки будет минимальным вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит пейволы локально на двух уровнях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Для ускорения загрузки пейволов мы также используем CDN и отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает получение актуальной версии пейволов и надёжную работу даже при слабом интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Ограничивает тайм-аут этого метода. По истечении тайм-аута возвращаются кешированные данные или локальный резервный пейвол.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения `loadTimeout`, поскольку операция может включать несколько запросов внутри.
| | Параметр | Описание | | :-------- | :---------- | | Paywall | Объект [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) со списком идентификаторов продуктов, идентификатором пейвола, Remote Config и другими свойствами. | ## Получение конфигурации представления для пейвола, созданного в Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Убедитесь, что в Paywall Builder включён переключатель **Show on device**. Если он выключен, конфигурация представления не будет доступна для получения. ::: После получения пейвола проверьте, содержит ли он конфигурацию представления — это означает, что пейвол был создан с помощью Paywall Builder. Наличие или отсутствие конфигурации определяет способ отображения пейвола. Если конфигурация представления есть — работайте с ним как с пейволом Paywall Builder; если нет — [обработайте его как пейвол с Remote Config](present-remote-config-paywalls). Используйте метод `getPaywallConfiguration` для загрузки конфигурации представления. ```swift showLineNumbers guard paywall.hasViewConfiguration else { // use your custom logic return } do { let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, products: products ) // use loaded configuration } catch { // handle the error } ``` Параметры: | Параметр | Наличие | Описание | | :----------------------- | :------------- | :------- | | **paywall** | обязательный | Объект `AdaptyPaywall` для получения контроллера нужного пейвола. | | **loadTimeout** | по умолчанию: 5 сек | Ограничивает таймаут для этого метода. Если таймаут истекает, возвращаются кэшированные данные или локальный резервный вариант. В редких случаях метод может завершиться чуть позже указанного значения `loadTimeout`, поскольку операция может включать несколько запросов под капотом. | | **products** | необязательный | Передайте массив объектов `AdaptyPaywallProduct`, чтобы оптимизировать время отображения продуктов на экране. Если передано `nil`, AdaptyUI автоматически получит необходимые продукты. | :::note Если вы используете несколько языков, узнайте, как добавить [локализацию Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) и как правильно использовать коды локалей [здесь](localizations-and-locale-codes). ::: После загрузки [отобразите пейвол](ios-present-paywalls). ## Получение пейвола для аудитории по умолчанию ради более быстрой загрузки \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Как правило, пейволы загружаются практически мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и пейволов, а пользователи работают с медленным интернетом, загрузка пейвола может занять больше времени, чем хотелось бы. В таких ситуациях имеет смысл показывать пейвол по умолчанию — это обеспечит плавный пользовательский опыт вместо того, чтобы не показывать пейвол вовсе. Чтобы решить эту задачу, используйте метод `getPaywallForDefaultAudience`, который получает пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать пейвол методом `getPaywall`, как описано в разделе [Получение информации о пейволе](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) выше. :::warning Почему мы рекомендуем использовать `getPaywall` Метод `getPaywallForDefaultAudience` имеет ряд существенных недостатков: - **Возможные проблемы с обратной совместимостью**: если нужно показывать разные пейволы для разных версий приложения (текущей и будущих), могут возникнуть сложности. Придётся либо проектировать пейволы с поддержкой текущей (устаревшей) версии, либо смириться с тем, что у пользователей на старой версии пейволы могут не отображаться корректно. - **Потеря таргетинга**: все пользователи будут видеть один и тот же пейвол, настроенный для аудитории **All Users**, — это означает отказ от персонализированного таргетинга (в том числе по странам, маркетинговой атрибуции или собственным пользовательским атрибутам). Если вы готовы принять эти компромиссы ради более быстрой загрузки пейвола, используйте метод `getPaywallForDefaultAudience` следующим образом. В противном случае используйте `getPaywall`, описанный [выше](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder). ::: ```swift showLineNumbers Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` :::note Метод `getPaywallForDefaultAudience` доступен начиная с версии iOS SDK 2.11.2. ::: | Параметр | Наличие | Описание | |---------|--------|-----------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение, которое вы указали при создании плейсмента в дашборде Adapty. | | **locale** |необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается, что этот параметр будет языковым кодом, состоящим из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Например: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае неудачи. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` для возврата кэшированных данных при их наличии. В этом случае пользователи могут получать не самые свежие данные, зато время загрузки будет меньше вне зависимости от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание, что кэш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
| ## Настройка ресурсов \{#customize-assets\} Чтобы кастомизировать изображения и видео в пейволе, используйте кастомные ресурсы. Для hero-изображений и видео есть предустановленные ID: `hero_image` и `hero_video`. В бандле кастомных ресурсов вы обращаетесь к этим элементам по их ID и меняете их поведение. Для остальных изображений и видео нужно [задать кастомный ID](custom-media) в дашборде Adapty. Например, можно: - Показывать одним пользователям одно изображение или видео, другим — другое. - Показывать локальное превью, пока загружается основное изображение с сервера. - Показывать превью перед воспроизведением видео. :::important Чтобы использовать эту функцию, обновите Adapty iOS SDK до версии 3.7.0 или выше. ::: Вот пример того, как можно передать пользовательские ресурсы через простой словарь: ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Показать локальное изображение с пользовательским ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Показать локальное превью, пока загружается основное изображение "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Показать локальное видео с превью-изображением "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!) ) ), ] let paywallConfig = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, assetsResolver: customAssets ) ``` :::note Если ресурс не найден, пейвол вернётся к своему виду по умолчанию. ::: ## Настройка таймеров, определённых разработчиком \{#set-up-developer-defined-timers\} Чтобы использовать пользовательские таймеры в мобильном приложении, создайте объект, реализующий протокол `AdaptyTimerResolver`. Этот объект определяет, как должен отображаться каждый таймер. Если хотите, можно напрямую использовать словарь `[String: Date]` — он уже соответствует этому протоколу. Пример: ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 часов case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 час } } } ``` В этом примере `CUSTOM_TIMER_NY` и `CUSTOM_TIMER_6H` — это **Timer ID** таймеров, заданных разработчиком в дашборде Adapty. `timerResolver` гарантирует, что приложение динамически обновляет каждый таймер нужным значением. Например: - `CUSTOM_TIMER_NY`: время, оставшееся до окончания таймера, например до Нового года. - `CUSTOM_TIMER_6H`: время, оставшееся в 6-часовом периоде, который начался, когда пользователь открыл пейвол.
## Число просмотров пейвола слишком велико \{#the-paywall-view-number-is-too-big\}
**Проблема**: Счётчик просмотров пейвола показывает вдвое больше ожидаемого числа.
**Причина**: Возможно, в вашем коде вызывается `logShowFlow` (iOS SDK v4+) / `logShowPaywall`, что дублирует счётчик просмотров при использовании Paywall Builder или Flow Builder. Для флоу и пейволов, созданных с помощью этих инструментов, аналитика отслеживается автоматически, поэтому использовать этот метод не нужно.
**Решение**: Убедитесь, что вы не вызываете `logShowFlow` (iOS SDK v4+) / `logShowPaywall` в своём коде, если используете Paywall Builder или Flow Builder.
## Другие проблемы \{#other-issues\}
**Проблема**: Вы столкнулись с другими проблемами, связанными с Paywall Builder, которые не описаны выше.
**Решение**: При необходимости обновите SDK до последней версии, воспользовавшись [гайдами по миграции](ios-sdk-migration-guides). Многие проблемы уже исправлены в новых версиях SDK.
---
# File: ios-present-paywall-builder-paywalls-in-observer-mode
---
---
title: "Отображение пейволов Paywall Builder в режиме Observer в iOS SDK"
description: "Узнайте, как отображать пейволы PB в режиме Observer для более глубокого анализа."
---
Если вы создали пейвол с помощью Paywall Builder, вам не нужно беспокоиться о его отображении в коде мобильного приложения — всё уже настроено. Такой пейвол содержит и то, что должно быть показано, и то, как именно это должно быть показано.
:::warning
Этот раздел относится только к [режиму Observer](observer-vs-full-mode). Если вы не работаете в режиме Observer, обратитесь к разделу [iOS — отображение пейволов, созданных в Paywall Builder](ios-present-paywalls).
:::
По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad`: он возвращает кешированные данные при их наличии. В этом случае пользователи могут не получить самые свежие данные, зато время загрузки будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Кеш сохраняется после перезапуска приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит флоу и пейволы в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Для ускоренной загрузки флоу и пейволов также используется CDN, а на случай его недоступности — отдельный резервный сервер.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут метода. При его истечении возвращаются кешированные данные или локальный резерв.
Обратите внимание, что в редких случаях метод может завершиться с небольшим превышением таймаута, заданного в `loadTimeout`, поскольку операция может состоять из нескольких запросов под капотом.
| :::note В v4 параметр `locale` перенесён из `getFlow` в `getFlowConfiguration` (используется только при рендеринге через AdaptyUI). Для кастомных пейволов все доступные локали возвращаются вместе в `flow.remoteConfigs` — выберите ту, которая соответствует языку устройства пользователя или настройкам вашего приложения. ::: Не прописывайте ID продуктов в коде! Поскольку флоу настраиваются удалённо, доступные продукты, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код корректно обрабатывает подобные сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать именно 2 продукта. Но если впоследствии вы получите 3 продукта, приложение должно показать все 3 без каких-либо изменений в коде. Единственное, что нужно прописать в коде — это ID плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Объект `AdaptyFlow`, содержащий плейсмент, идентификаторы (`id`, `variationId`), название, массив `remoteConfigs` (по одной записи на каждую настроенную локаль) и флаг `hasViewConfiguration`. Чтобы получить продукты для флоу, вызовите `getPaywallProducts(flow:)`. | ## Получение продуктов \{#fetch-products\} После получения флоу вы можете запросить массив продуктов, соответствующий ему:По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — этот режим возвращает кешированные данные, если они есть. В таком сценарии пользователи могут получить не самые свежие данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии во избежание лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или ручной очистке.
|необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается языковой код, состоящий из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локализаций и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые свежие данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при переустановке или ручной очистке.
Adapty SDK хранит пейволы в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Также используется CDN для ускорения загрузки пейволов и отдельный резервный сервер на случай недоступности CDN. Эта система гарантирует, что вы всегда получаете актуальную версию пейволов, обеспечивая надёжность даже при слабом интернете.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут метода. Если таймаут истекает, возвращаются кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeout`, поскольку операция может включать несколько запросов под капотом.
| Не задавайте product ID в коде! Поскольку пейволы настраиваются удалённо, доступные продукты, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код учитывает эти сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать именно 2 продукта. Но если позже вы получите 3 продукта, приложение должно показать все 3 без каких-либо изменений в коде. Единственное, что нужно задать в коде, — это ID плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Объект [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) содержит: список ID продуктов, идентификатор пейвола, Remote Config и ряд других свойств. | ## Получить продукты \{#fetch-products\} Когда у вас есть пейвол, вы можете запросить массив продуктов, соответствующих ему:необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается языковой код, состоящий из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут получать не самые свежие данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или принудительной очистке вручную.
|Если запрос выполнен успешно, ответ содержит этот объект. Объект [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile) предоставляет исчерпывающую информацию об уровнях доступа пользователя, подписках и разовых покупках внутри приложения.
Проверьте статус уровня доступа, чтобы убедиться, что пользователь имеет необходимый доступ к приложению.
| :::warning **Примечание:** если вы используете Apple StoreKit версии ниже v2.0 и Adapty SDK версии ниже v2.9.0, вам нужно указать [Apple App Store shared secret](app-store-connection-configuration#step-5-enter-app-store-shared-secret). Этот метод устарел и больше не рекомендуется Apple. ::: ## Встроенные покупки из App Store \{#in-app-purchases-from-the-app-store\} Когда пользователь инициирует покупку в App Store и транзакция передаётся в ваше приложение, у вас есть два варианта: - **Обработать транзакцию немедленно:** Верните `true` в `shouldAddStorePayment`. Это сразу откроет экран покупки Apple. - **Сохранить объект продукта для последующей обработки:** Верните `false` в `shouldAddStorePayment`, а затем вызовите `makePurchase` с сохранённым продуктом позже. Это может быть полезно, если перед запуском покупки нужно показать пользователю что-то своё. Вот полный фрагмент кода: ```swift showLineNumbers title="Swift" final class YourAdaptyDelegateImplementation: AdaptyDelegate { nonisolated func shouldAddStorePayment(for product: AdaptyDeferredProduct) -> Bool { // 1a. // Return `true` to continue the transaction in your app. The Apple purchase system screen will show automatically. // 1b. // Store the product object and return `false` to defer or cancel the transaction. false } // 2. Continue the deferred purchase later on by passing the product to `makePurchase` when the timing is appropriate func continueDeferredPurchase() async { let storedProduct: AdaptyDeferredProduct = // get the product object from 1b. do { try await Adapty.makePurchase(product: storedProduct) } catch { // handle the error } } } ``` ## Активация промокодов в iOS \{#redeem-offer-codes-in-ios\}Объект [`AdaptyProfile`](https://swift.adapty.io/documentation/adapty/adaptyprofile). Эта модель содержит информацию об уровнях доступа, подписках и разовых покупках.
Проверьте **статус уровня доступа**, чтобы определить, есть ли у пользователя доступ к приложению.
| :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: --- # File: ios-transaction-management --- --- title: "Расширенное управление транзакциями в iOS SDK" description: "Завершайте транзакции вручную в iOS-приложении с помощью Adapty SDK." --- :::note Расширенное управление транзакциями поддерживается в Adapty iOS SDK начиная с версии 3.12. ::: Расширенное управление транзакциями в Adapty даёт вам больше контроля над тем, как транзакции обрабатываются, верифицируются и завершаются. Эта функциональность включает три опциональных возможности, которые работают вместе: | Возможность | Назначение | |-------------------------------------------------------------|----------| | [`appAccountToken`](#assign-appaccounttoken) | Связывает транзакции Apple с вашим внутренним идентификатором пользователя | | [`jwsTransaction`](#access-the-jws-representation) | Предоставляет подписанный Apple пейлоад транзакции для валидации | | [Ручное завершение](#control-transaction-finishing-behavior) | Позволяет завершать транзакции только после подтверждения успеха от вашего бэкенда | В совокупности эти инструменты позволяют выстроить надёжные кастомные процессы валидации, пока Adapty продолжает синхронизировать транзакции со своим бэкендом. :::important Большинству приложений это не нужно. По умолчанию Adapty автоматически валидирует и завершает транзакции StoreKit. Используйте этот гайд только если вы проводите собственную валидацию на бэкенде или хотите полностью управлять жизненным циклом покупок. ::: ## Назначение `appAccountToken` \{#assign-appaccounttoken\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) — это **UUID**, который позволяет связать транзакции App Store с внутренней идентичностью пользователя в вашей системе. StoreKit привязывает этот токен к каждой транзакции, чтобы ваш бэкенд мог сопоставить данные App Store с вашими пользователями. Используйте стабильный UUID, генерируемый для каждого пользователя, и повторно применяйте его для одного аккаунта на разных устройствах. Это гарантирует корректную привязку покупок и уведомлений App Store. Токен можно задать двумя способами — при активации SDK или при идентификации пользователя. :::important Вы всегда должны передавать `appAccountToken` вместе с `customerUserId`. Если передать только токен, он не будет включён в транзакцию. :::Для StoreKit 1: объект [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Для StoreKit 2: объект [Transaction](https://developer.apple.com/documentation/storekit/transaction).
|phoneNumber
firstName
lastName
| String | | gender | Enum, допустимые значения: `female`, `male`, `other` | | birthday | Date | ### Пользовательские атрибуты \{#custom-user-attributes\} Вы можете задавать собственные атрибуты — как правило, они связаны с тем, как пользователь взаимодействует с вашим приложением. Например, для фитнес-приложений это может быть количество тренировок в неделю, а для приложений по изучению языков — уровень знаний пользователя. Такие атрибуты можно использовать в сегментах для создания таргетированных пейволов и предложений, а также в аналитике, чтобы понять, какие продуктовые метрики сильнее всего влияют на выручку. ```swift showLineNumbers do { builder = try builder.with(customAttribute: "value1", forKey: "key1") } catch { // handle key/value validation error } ``` Чтобы удалить существующий ключ, используйте метод `.withRemoved(customAttributeForKey:)`: ```swift showLineNumbers do { builder = try builder.withRemoved(customAttributeForKey: "key2") } catch { // handle error } ``` Иногда нужно узнать, какие пользовательские атрибуты уже установлены. Для этого используйте поле `customAttributes` объекта `AdaptyProfile`. :::warning Имейте в виду, что значение `customAttributes` может быть устаревшим: атрибуты пользователя могут отправляться с разных устройств в любое время, поэтому данные на сервере могут измениться после последней синхронизации. ::: ### Ограничения \{#limits\} - Не более 30 пользовательских атрибутов на одного пользователя - Длина имени ключа — до 30 символов. Имя ключа может содержать буквенно-цифровые символы и любые из следующих: `_` `-` `.` - Значение может быть строкой или числом с плавающей точкой длиной не более 50 символов. --- # File: subscription-status --- --- title: "Проверка статуса подписки в iOS SDK" description: "Отслеживайте и управляйте статусом подписки пользователя в Adapty для улучшения удержания клиентов." --- С Adapty отслеживать статус подписки очень просто. Вам не нужно вручную прописывать идентификаторы продуктов в коде — достаточно проверить наличие активного [уровня доступа](access-level), чтобы убедиться, что у пользователя есть подписка. Перед тем как приступить к проверке статуса подписки, настройте [App Store Server Notifications](enable-app-store-server-notifications). ## Уровень доступа и объект AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Уровни доступа — это свойства объекта [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile). Рекомендуем получать профиль при запуске приложения, например, когда вы [идентифицируете пользователя](identifying-users#set-customer-user-id-on-configuration), и обновлять его при каждом изменении. Так вы сможете использовать объект профиля, не запрашивая его повторно. Чтобы получать уведомления об обновлениях профиля, подпишитесь на изменения профиля, как описано в разделе [Подписка на обновления статуса подписки](subscription-status#listening-for-subscription-status-updates) ниже. :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ## Получение уровня доступа с сервера \{#retrieving-the-access-level-from-the-server\} Чтобы получить уровень доступа с сервера, используйте метод `.getProfile()`:Объект [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile). Как правило, для определения наличия у пользователя премиум-доступа достаточно проверить статус уровня доступа профиля.
Метод `.getProfile` возвращает максимально актуальные данные, поскольку всегда пытается обратиться к API. Если по какой-либо причине (например, из-за отсутствия подключения к интернету) Adapty SDK не может получить данные с сервера, возвращаются данные из кэша. Важно отметить, что Adapty SDK регулярно обновляет кэш `AdaptyProfile`, чтобы данные оставались как можно более актуальными.
| Метод `.getProfile()` возвращает профиль пользователя, из которого можно получить статус уровня доступа. В одном приложении может быть несколько уровней доступа. Например, если у вас новостное приложение с независимыми подписками на разные темы, вы можете создать уровни доступа «sports» и «science». Однако в большинстве случаев достаточно одного уровня доступа — тогда можно просто использовать уровень «premium» по умолчанию. Пример проверки уровня доступа «premium» по умолчанию:опциональный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Например: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локализации и рекомендациях по их использованию — в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые свежие данные, зато загрузка будет быстрее вне зависимости от качества связи. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные онбординги. Мы также используем CDN для более быстрой загрузки онбордингов и отдельный резервный сервер на случай недоступности CDN. Система спроектирована так, чтобы вы всегда получали актуальную версию онбордингов даже при нестабильном интернете.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут метода. Если таймаут истекает, возвращаются кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшим превышением значения, указанного в `loadTimeout`, поскольку операция может включать несколько запросов под капотом.
| | Параметр | Описание | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Объект [`AdaptyOnboarding`](https://swift.adapty.io/documentation/adapty/adaptyonboarding) с идентификатором и конфигурацией онбординга, Remote Config и рядом других свойств. | ## Ускорьте загрузку онбординга с помощью онбординга для аудитории по умолчанию \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Как правило, онбординги загружаются почти мгновенно, и беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и онбордингов, а у пользователей слабое интернет-соединение, загрузка онбординга может занять больше времени, чем хотелось бы. В таких случаях лучше показать онбординг по умолчанию, чтобы не оставлять пользователя ни с чем. Чтобы решить эту задачу, можно использовать метод `getOnboardingForDefaultAudience`, который получает онбординг указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать онбординг через метод `getOnboarding`, как описано в разделе [Получение онбординга](#fetch-onboarding) выше. :::warning Рассмотрите возможность использования `getOnboarding` вместо `getOnboardingForDefaultAudience`, поскольку последний имеет важные ограничения: - **Проблемы совместимости**: может вызвать трудности при поддержке нескольких версий приложения — придётся либо делать обратно совместимые дизайны, либо мириться с тем, что старые версии будут отображать контент некорректно. - **Без персонализации**: показывает контент только для аудитории «Все пользователи», без учёта страны, атрибуции или пользовательских атрибутов. Если более быстрая загрузка важнее этих недостатков в вашем случае, используйте `getOnboardingForDefaultAudience`, как показано ниже. В противном случае используйте `getOnboarding`, как описано [выше](#fetch-onboarding). ::: ```swift showLineNumbers Adapty.getOnboardingForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(onboarding): // запрошенный онбординг case let .failure(error): // обработка ошибки } } ``` Параметры: | Параметр | Наличие | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **locale** |опциональный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается код языка, состоящий из одного или двух подтегов, разделённых символом минуса (**-**). Первый подтег обозначает язык, второй — регион.
Например: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае данные могут быть не самыми свежими, зато загрузка будет быстрее независимо от качества связи. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные онбординги. Для более быстрой загрузки онбордингов используется CDN, а в случае его недоступности — отдельный резервный сервер. Эта система обеспечивает получение актуальных версий онбордингов при надёжной работе даже при слабом интернет-соединении.
| --- # File: ios-present-onboardings --- --- title: "Present onboardings in iOS SDK" description: "Discover how to present onboardings on iOS to boost conversions and revenue." --- :::tip **Начиная с SDK v4**, вы можете создавать [флоу](get-pb-paywalls) как более мощную альтернативу онбордингам. В отличие от онбордингов, которые работают внутри WebView, флоу рендерятся нативно на устройстве — это обеспечивает более плавные анимации, нативный вид iOS, быструю загрузку и отсутствие зависимости от WebView. Подробнее в разделах [Получение флоу и пейволов](get-pb-paywalls) и [Отображение флоу и пейволов](ios-present-paywalls). ::: Если вы создали онбординг с помощью конструктора, вам не нужно беспокоиться о его рендеринге в коде мобильного приложения для отображения пользователю. Такой онбординг содержит и то, что должно показываться, и то, как это должно показываться. Перед началом убедитесь, что: 1. Вы установили [Adapty iOS SDK](sdk-installation-ios) версии 3.8.0 или выше. 2. Вы [создали онбординг](create-onboarding). 3. Вы добавили онбординг в [плейсмент](placements). ## Показ онбордингов в Swift \{#present-onboardings-in-swift\} Чтобы отобразить визуальный онбординг на экране устройства, выполните следующие шаги: 1. Получите конфигурацию онбординга с помощью метода `.getOnboardingConfiguration`. 2. Инициализируйте визуальный онбординг с помощью метода `.onboardingController`: Параметры запроса: | Параметр | Наличие | Описание | |:-----------------------------|:---------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onboarding configuration** | required | Объект `AdaptyUI.OnboardingConfiguration`, содержащий все свойства онбординга. Используйте метод `AdaptyUI.getOnboardingConfiguration` для его получения. | | **delegate** | required | Объект `AdaptyOnboardingControllerDelegate` для прослушивания событий онбординга. | Возвращает: | Объект | Описание | |:-------------------------------|:--------------------------------------------------------| | **AdaptyOnboardingController** | Объект, представляющий запрошенный экран онбординга | 3. После успешного создания объекта его можно отобразить на экране устройства: ```swift showLineNumbers title="Swift" import Adapty import AdaptyUI // 0. Get an onboarding if you haven't done it yet let onboarding = try await Adapty.getOnboarding(placementId: "YOUR_PLACEMENT_ID") // 1. Obtain the onboarding view configuration: let configuration = try AdaptyUI.getOnboardingConfiguration(forOnboarding: onboarding) // 2. Create Onboarding View Controller let onboardingController = try AdaptyUI.onboardingController( with: configuration, delegate:
Затем вы можете использовать этот ID в своём коде и обрабатывать его как пользовательское действие. Например, если пользователь нажимает на кастомную кнопку — скажем, **Login** или **Allow notifications** — метод делегата `onboardingController` будет вызван с кейсом `.custom(id:)`, где параметр `actionId` соответствует **Action ID** из билдера. Вы можете задавать собственные ID, например "allowNotifications".
```swift showLineNumbers
func onboardingController(_ controller: AdaptyOnboardingController, onCustomAction action: AdaptyOnboardingsCustomAction) {
if action.actionId == "allowNotifications" {
// Request notification permissions
}
}
func onboardingController(_ controller: AdaptyOnboardingController, didFailWithError error: AdaptyUIError) {
// Handle errors
}
```
:::important
Обратите внимание: вам нужно самостоятельно обработать закрытие онбординга пользователем — например, скрыть экран онбординга.
:::
Например:
```swift showLineNumbers
func onboardingController(_ controller: AdaptyOnboardingController, onCloseAction action: AdaptyOnboardingsCloseAction) {
controller.dismiss(animated: true)
}
```
2. Нажмите на название группы подписок. В разделе **Subscriptions** появится список ваших продуктов.
3. Убедитесь, что тестируемый продукт имеет статус **Ready to Submit**. Если нет, следуйте инструкциям на странице [Продукт в App Store](app-store-products).
4. Сравните ID продукта из таблицы с тем, что указан во вкладке [**Products**](https://app.adapty.io/products) дашборда Adapty. Если ID не совпадают, скопируйте ID продукта из таблицы и [создайте продукт](create-product) с этим ID в дашборде Adapty.
## Шаг 3. Проверьте доступность продукта \{#step-4-check-product-availability\}
1. Вернитесь в **App Store Connect** и откройте раздел **Subscriptions**.
2. Нажмите на название группы подписок, чтобы просмотреть продукты.
3. Выберите продукт, который хотите протестировать.
4. Прокрутите до раздела **Availability** и убедитесь, что в нём указаны все необходимые страны и регионы.
## Шаг 4. Проверьте цены продуктов \{#step-5-check-product-prices\}
1. Снова перейдите в раздел **Monetization** → **Subscriptions** в **App Store Connect**.
2. Нажмите на название группы подписок.
3. Выберите продукт, который хотите протестировать.
4. Прокрутите вниз до раздела **Subscription Pricing** и разверните раздел **Current Pricing for New Subscribers**.
5. Убедитесь, что все необходимые цены указаны.
## Шаг 5. Убедитесь, что платный статус приложения, банковский счёт и налоговые формы активны \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. На главной странице [**App Store Connect**](https://appstoreconnect.apple.com/) нажмите **Business**.
2. Выберите название вашей компании.
3. Прокрутите вниз и убедитесь, что ваши **Paid Apps Agreement**, **Bank Account** и **Tax forms** отображаются со статусом **Active**.
Следуя этим шагам, вы сможете устранить предупреждение `InvalidProductIdentifiers` и запустить свои продукты в сторе.
## Шаг 6. Пересоздайте продукт, если он завис \{#step-6-recreate-the-product-if-its-stuck\}
Шаги 1–5 могут пройти успешно — статус `Approved`, совпадающий Bundle ID, корректный API-ключ — а SDK всё равно возвращает `1000 noProductIDsFound`. В таком случае продукт может быть завис в реестре Apple. Реестр продуктов Apple иногда переходит в состояние, при котором продукт существует в интерфейсе App Store Connect, но недоступен для поиска через StoreKit.
Удалите продукт в App Store Connect и пересоздайте его с тем же идентификатором. После пересоздания подождите до 24 часов — столько может занять распространение изменений.
---
# File: cantMakePayments
---
---
title: "Исправление ошибки Code-1003 cantMakePayment"
description: "Устраните ошибку при совершении платежей при управлении подписками в Adapty."
---
Ошибка 1003, `cantMakePayments`, означает, что на этом устройстве нельзя совершать встроенные покупки.
Если вы столкнулись с ошибкой `cantMakePayments`, обычно это происходит по одной из следующих причин:
- Ограничения устройства: ошибка не связана с Adapty. Способы решения описаны ниже.
- Настройка Observer mode: метод `makePurchase` и Observer mode нельзя использовать одновременно. Подробнее — в соответствующем разделе ниже.
## Проблема: ограничения устройства \{#issue-device-restrictions\}
| Проблема | Решение |
|---------------------------------|-------------------------------------------------------------------------------------------------------------------|
| Ограничения Screen Time | Отключите ограничения встроенных покупок в [Screen Time](https://support.apple.com/en-us/102470) |
| Аккаунт заблокирован | Обратитесь в службу поддержки Apple для решения проблем с аккаунтом |
| Региональные ограничения | Используйте аккаунт App Store из поддерживаемого региона |
## Проблема: одновременное использование Observer mode и makePurchase \{#issue-using-both-observer-mode-and-makepurchase\}
Если вы используете `makePurchase` для обработки покупок, Observer mode не нужен. [Observer mode](observer-vs-full-mode) требуется только в том случае, если логику покупок вы реализуете самостоятельно.
Таким образом, если вы используете `makePurchase`, можно смело убрать активацию Observer mode из кода инициализации SDK.
---
# File: migration-to-ios-sdk-v4
---
---
title: "Миграция Adapty iOS SDK на v4.0"
description: "Миграция на Adapty iOS SDK v4.0: замена paywall API на flow API, совместимые как с Flow Builder, так и с Paywall Builder."
---
Adapty iOS SDK 4.0 вводит флоу и переименовывает API пейволов. Новые API работают как с новым Flow Builder, так и с существующим Paywall Builder — никаких изменений в настройках дашборда Adapty не требуется.
## Краткий справочник \{#quick-reference\}
| v3 | v4 |
|---|---|
| `Adapty.getPaywall(placementId:locale:)` | `Adapty.getFlow(placementId:)` |
| `AdaptyUI.getPaywallConfiguration(forPaywall:)` | `AdaptyUI.getFlowConfiguration(forFlow:locale:)` |
| `Adapty.getPaywallProducts(paywall:)` | `Adapty.getPaywallProducts(flow:)` |
| `Adapty.logShowPaywall(_:)` | `Adapty.logShowFlow(_:)` |
| `AdaptyPaywallController` | `AdaptyFlowController` |
| `AdaptyPaywallControllerDelegate` | `AdaptyFlowControllerDelegate` |
| `AdaptyUI.paywallController(with:delegate:)` | `AdaptyUI.flowController(with:delegate:)` |
| `.paywall()` (SwiftUI modifier) | `.flow()` |
| `AdaptyPaywallView` | `AdaptyFlowView` |
| `didFailRenderingWith:` / `didFailRendering:` | `didReceiveError:` |
| `didFinishPurchase` (опциональный, автоматически закрывается при успехе) | `didFinishPurchase` (обязательный, без автоматического закрытия) |
| Продукты пакета `Adapty_KidsMode` / `AdaptyUI_KidsMode` | Трейт пакета `KidsMode` |
| `Adapty.updateAttribution(_:source:)` (`source: String`) | `Adapty.updateAttribution(_:source:)` (`source: AdaptyAttributionSource`) |
| `Adapty.setIntegrationIdentifier(key:value:)` | `Adapty.setIntegrationIdentifier(_:)` (`AdaptyIntegrationIdentifier`) |
## Минимальная версия iOS \{#minimum-ios-version\}
Adapty iOS SDK 4.0 повышает минимальный deployment target с iOS 13.0 до **iOS 15.0**. Перед обновлением установите iOS Deployment Target вашего проекта на версию 15.0 или выше.
## Установка: CocoaPods больше не поддерживается \{#installation-cocoapods-no-longer-supported\}
Adapty iOS SDK 4.0 отказывается от поддержки CocoaPods. Устанавливайте SDK через [Swift Package Manager](sdk-installation-ios#install-adapty-sdk).
Если ваш проект всё ещё использует CocoaPods, удалите поды `Adapty` и `AdaptyUI` из `Podfile`, выполните `pod install`, чтобы убрать их, а затем добавьте пакет в Xcode через **File → Add Package Dependency**, указав `https://github.com/adaptyteam/AdaptySDK-iOS.git`.
## Kids Mode: отдельные продукты заменены на трейт пакета \{#kids-mode-separate-products-replaced-by-a-package-trait\}
В v3 [Kids Mode](kids-mode) включался выбором отдельных продуктов **Adapty_KidsMode** и **AdaptyUI_KidsMode** с переименованием импортов. В v4.0 эти продукты удалены. Теперь Kids Mode — это трейт Swift-пакета с именем `KidsMode` для обычного пакета Adapty: при его включении IDFA и AdSupport исключаются из компиляции во всём SDK.
Чтобы перейти на новую версию:
1. В окне **Choose Package Products** выберите обычные продукты **Adapty** и **AdaptyUI** вместо **Adapty_KidsMode** и **AdaptyUI_KidsMode**.
2. Включите трейт `KidsMode`. В Xcode 26.4 или новее включите его для зависимости AdaptySDK-iOS в разделе **Package Dependencies** вашего проекта. Если вы добавляете Adapty как зависимость в `Package.swift` (требуется `swift-tools-version` 6.1 или новее), включите его там:
```swift showLineNumbers title="Package.swift"
.package(
url: "https://github.com/adaptyteam/AdaptySDK-iOS.git",
from: "4.0.0",
traits: ["KidsMode"]
)
```
3. Верните импорты обратно на обычные модули:
```diff showLineNumbers
- import Adapty_KidsMode
- import AdaptyUI_KidsMode
+ import Adapty
+ import AdaptyUI
```
:::note
Версии Xcode ниже 26.4 не позволяют включать трейты для проекта Xcode через интерфейс. В таком случае создайте небольшой локальный Swift-пакет, который зависит от Adapty с включённым трейтом `KidsMode`, и добавьте зависимость от этого пакета в таргет приложения.
:::
## Удалённые API \{#removed-apis\}
- **`Adapty.getPaywallProductsWithoutDeterminingOffer(paywall:)`** — удалён. Все продукты теперь включают информацию об офере, поэтому отдельный проход для определения доступности больше не нужен.
- **`AdaptyPaywallProductWithoutDeterminingOffer`** — удалён. Коллбэки, которые раньше передавали этот тип (например, `didSelectProduct`), теперь передают `AdaptyPaywallProduct`.
## Временное удаление поддержки promoted in-app purchases из App Store \{#app-store-promoted-in-app-purchases-temporarily-removed\}
В рамках миграции на StoreKit 2 Adapty iOS SDK 4.0 убирает поддержку promoted in-app purchases из App Store. Метод делегата `shouldAddStorePayment(for:)` и тип `AdaptyDeferredProduct`, который он принимает, недоступны в версии 4.0.
:::warning
Это временное ограничение — поддержка promoted in-app purchases вернётся в одном из следующих релизов 4.x. Если ваше приложение использует promoted in-app purchases, оставайтесь на iOS SDK 3.x до её возвращения.
:::
## Получение пейволов \{#fetching-paywalls\}
### getPaywall + getPaywallConfiguration → getFlow + getFlowConfiguration
Возвращаемые типы меняются с `AdaptyPaywall` / `AdaptyUI.PaywallConfiguration` на `AdaptyFlow` / `AdaptyUI.FlowConfiguration`. Параметр `locale` переносится из вызова получения данных в `getFlowConfiguration`:
```diff showLineNumbers
- let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en")
- let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall)
+ let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID")
+ let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow, locale: "en")
```
### getPaywallProducts(paywall:) → getPaywallProducts(flow:)
`getPaywallProducts` теперь принимает `AdaptyFlow`, возвращаемый `Adapty.getFlow`:
```diff showLineNumbers
- let products = try await Adapty.getPaywallProducts(paywall: paywall)
+ let products = try await Adapty.getPaywallProducts(flow: flow)
```
## Отслеживание просмотров пейвола \{#tracking-paywall-views\}
### logShowPaywall(_:) → logShowFlow(_:)
`logShowPaywall` переименован в `logShowFlow` и теперь принимает `AdaptyFlow` вместо `AdaptyPaywall`. Событие по-прежнему записывается к тому же варианту, поэтому существующие метрики воронки и A/B-тестов продолжают работать без изменений в дашборде.
```diff showLineNumbers
- try await Adapty.logShowPaywall(paywall)
+ try await Adapty.logShowFlow(flow)
```
Как и в v3, вам не нужно вызывать этот метод при отображении флоу или пейволов, отрисованных с помощью [Flow Builder](adapty-flow-builder) или [Paywall Builder](adapty-paywall-builder) — Adapty отслеживает эти просмотры автоматически.
## didFinishPurchase теперь обязателен \{#didfinishpurchase-is-now-required\}
В v3 `didFinishPurchase` был необязательным: если вы его не реализовывали, пейвол закрывался автоматически после успешной покупки. В v4.0 эта автоматическая логика закрытия убрана, чтобы флоу мог продолжаться после успешной покупки — например, чтобы показать оставшиеся экраны флоу. Теперь вы сами решаете, что происходит после покупки: закрыть экран или ничего не делать и дать флоу продолжить выполнение.
- **UIKit**: те, кто реализует `AdaptyFlowControllerDelegate`, должны реализовать `didFinishPurchase` — у него больше нет реализации по умолчанию.
- **SwiftUI**: замыкание `didFinishPurchase` в `.flow(...)` и `AdaptyFlowView(...)` теперь обязательно, как и `didFailPurchase` и `didFinishRestore`.
Чтобы сохранить поведение v3, закрывайте экран самостоятельно:
```swift showLineNumbers title="Swift"
func flowController(
_ controller: AdaptyFlowController,
didFinishPurchase product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
if !purchaseResult.isPurchaseCancelled {
controller.dismiss(animated: true)
}
}
```
## UIKit \{#uikit\}
### AdaptyPaywallController → AdaptyFlowController
Переименуйте тип контроллера и фабричный метод:
```diff showLineNumbers
- let controller = try AdaptyUI.paywallController(
- with: paywallConfiguration,
- delegate: self
- )
+ let controller = try AdaptyUI.flowController(
+ with: flowConfiguration,
+ delegate: self
+ )
```
### AdaptyPaywallControllerDelegate → AdaptyFlowControllerDelegate \{#adaptypaywall-controller-delegate--adaptyflo-controller-delegate\}
Переименуйте протокол и обновите каждую сигнатуру метода. Обратите внимание, что `didSelectProduct` теперь принимает `AdaptyPaywallProduct` вместо удалённого `AdaptyPaywallProductWithoutDeterminingOffer`, а `didFinishPurchase` [теперь обязателен к реализации](#didfinishpurchase-is-now-required) — у него больше нет реализации по умолчанию.
```diff showLineNumbers
- class YourClass: AdaptyPaywallControllerDelegate {
+ class YourClass: AdaptyFlowControllerDelegate {
- func paywallControllerDidAppear(_ controller: AdaptyPaywallController) { }
+ func flowControllerDidAppear(_ controller: AdaptyFlowController) { }
- func paywallControllerDidDisappear(_ controller: AdaptyPaywallController) { }
+ func flowControllerDidDisappear(_ controller: AdaptyFlowController) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didPerform action: AdaptyUI.Action) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didPerform action: AdaptyUI.Action) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didSelectProduct product: AdaptyPaywallProduct) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didStartPurchase product: AdaptyPaywallProduct) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didStartPurchase product: AdaptyPaywallProduct) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFinishPurchase product: AdaptyPaywallProduct,
- purchaseResult: AdaptyPurchaseResult) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFinishPurchase product: AdaptyPaywallProduct,
+ purchaseResult: AdaptyPurchaseResult) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailPurchase product: AdaptyPaywallProduct,
- error: AdaptyError) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFailPurchase product: AdaptyPaywallProduct,
+ error: AdaptyError) { }
- func paywallControllerDidStartRestore(_ controller: AdaptyPaywallController) { }
+ func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFinishRestoreWith profile: AdaptyProfile) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFinishRestoreWith profile: AdaptyProfile) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailRestoreWith error: AdaptyError) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFailRestoreWith error: AdaptyError) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailRenderingWith error: AdaptyUIError) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didReceiveError error: AdaptyUIError) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailLoadingProductsWith error: AdaptyError) -> Bool { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFailLoadingProductsWith error: AdaptyError) -> Bool { }
- func paywallController(_ controller: AdaptyPaywallController,
- didPartiallyLoadProducts failedIds: [String]) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didPartiallyLoadProducts failedIds: [String]) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFinishWebPaymentNavigation product: AdaptyPaywallProduct?,
- error: AdaptyError?) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFinishWebPaymentNavigation product: AdaptyPaywallProduct?,
+ error: AdaptyError?) { }
}
```
## SwiftUI \{#swiftui\}
### Модификатор .paywall() → .flow() \{#paywall-modifier--flow\}
Переименуйте модификатор, обновите имя параметра конфигурации и добавьте [обязательное теперь](#didfinishpurchase-is-now-required) замыкание `didFinishPurchase`:
```diff showLineNumbers
@State var flowPresented = false // rename freely — the variable name is your choice
var body: some View {
Text("Hello, AdaptyUI!")
- .paywall(
+ .flow(
isPresented: $flowPresented,
- paywallConfiguration: paywallConfiguration,
+ flowConfiguration: flowConfiguration,
+ didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ },
didFailPurchase: { product, error in /* handle the error */ },
didFinishRestore: { profile in /* check access level and dismiss */ },
didFailRestore: { error in /* handle the error */ },
- didFailRendering: { error in flowPresented = false }
+ didReceiveError: { error in flowPresented = false }
)
}
```
Переименованный колбэк срабатывает при тех же ошибках рендеринга, что и `didFailRendering`, плюс при новых ошибках выполнения из скрипта флоу (JavaScript-исключения с кодом `AdaptyUIError` `4105` — `.jsException`). Менять код в теле обработчика не нужно — достаточно переименовать параметр.
### AdaptyPaywallView → AdaptyFlowView
Переименуйте вью, обновите параметр конфигурации, добавьте [обязательное теперь](#didfinishpurchase-is-now-required) замыкание `didFinishPurchase` и обновите замыкание `didSelectProduct` — теперь оно принимает `AdaptyPaywallProduct` вместо удалённого `AdaptyPaywallProductWithoutDeterminingOffer`:
```diff showLineNumbers
- AdaptyPaywallView(
- paywallConfiguration: paywallConfiguration,
- didSelectProduct: { product: AdaptyPaywallProductWithoutDeterminingOffer in /* handle */ },
+ AdaptyFlowView(
+ flowConfiguration: flowConfiguration,
+ didSelectProduct: { product: AdaptyPaywallProduct in /* handle */ },
+ didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ },
didFailPurchase: { product, error in /* handle the error */ },
didFinishRestore: { profile in /* check access level and dismiss */ },
didFailRestore: { error in /* handle the error */ },
- didFailRendering: { error in /* handle the error */ }
+ didReceiveError: { error in /* handle the error */ }
)
```
## Пользовательские ресурсы AdaptyUI \{#adaptyui-custom-assets\}
### AdaptyUICustomVideoAsset
Два изменения затрагивают все существующие места вызова:
- `.player` теперь принимает `AVPlayer` вместо `AVQueuePlayer`.
- В каждый case добавлен завершающий параметр `resolution: CGSize?`. Передайте `nil`, чтобы сохранить текущее поведение, или передайте фактический размер в пикселях, чтобы плеер мог зарезервировать место в лэйауте (соотношение сторон = `width / height`) до загрузки видео.
```diff showLineNumbers
- case file(url: URL, preview: AdaptyUICustomImageAsset?)
- case remote(url: URL, preview: AdaptyUICustomImageAsset?)
- case player(item: AVPlayerItem, player: AVQueuePlayer, preview: AdaptyUICustomImageAsset?)
+ case file(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?)
+ case remote(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?)
+ case player(item: AVPlayerItem, player: AVPlayer, preview: AdaptyUICustomImageAsset?, resolution: CGSize?)
```
## Идентификаторы атрибуции и интеграций \{#attribution-and-integration-identifiers\}
### updateAttribution(_:source:)
Параметр `source` изменился с типа `String` на новый тип `AdaptyAttributionSource`, а вложенный ранее `AdaptyProfile.AttributionSource` переименован в `AdaptyAttributionSource` на верхнем уровне. Используйте один из предопределённых источников или передайте строковый литерал для любого другого источника — `AdaptyAttributionSource` поддерживает `ExpressibleByStringLiteral`, поэтому существующие вызовы со строковыми литералами продолжат компилироваться.
```diff showLineNumbers
- try await Adapty.updateAttribution(attribution, source: "adjust")
+ try await Adapty.updateAttribution(attribution, source: .adjust)
```
Предопределённые источники: `.appleAds`, `.adjust`, `.appsflyer`, `.branch`, `.tenjin`. Если источник хранится в переменной типа `String`, оберните его: `AdaptyAttributionSource(rawValue: yourSource)`.
### setIntegrationIdentifier(_:)
`setIntegrationIdentifier(key:value:)` заменён вариативным методом, который принимает одно или несколько значений `AdaptyIntegrationIdentifier`. Используйте предопределённые фабричные методы вместо строковых ключей:
```diff showLineNumbers
- try await Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid)
+ try await Adapty.setIntegrationIdentifier(.appsflyerId(uid))
```
Можно задать сразу несколько идентификаторов в одном вызове:
```swift showLineNumbers
try await Adapty.setIntegrationIdentifier(
.appsflyerId(uid),
.adjustDeviceId(adid)
)
```
Замените каждую старую строку ключа соответствующим фабричным методом:
| ключ v3 | фабрика v4 |
|---|---|
| `"adjust_device_id"` | `.adjustDeviceId(_:)` |
| `"airbridge_device_id"` | `.airbridgeDeviceId(_:)` |
| `"amplitude_user_id"` | `.amplitudeUserId(_:)` |
| `"amplitude_device_id"` | `.amplitudeDeviceId(_:)` |
| `"appmetrica_device_id"` | `.appmetricaDeviceId(_:)` |
| `"appmetrica_profile_id"` | `.appmetricaProfileId(_:)` |
| `"appsflyer_id"` | `.appsflyerId(_:)` |
| `"branch_id"` | `.branchId(_:)` |
| `"facebook_anonymous_id"` | `.facebookAnonymousId(_:)` |
| `"firebase_app_instance_id"` | `.firebaseAppInstanceId(_:)` |
| `"mixpanel_user_id"` | `.mixpanelUserId(_:)` |
| `"one_signal_subscription_id"` | `.oneSignalSubscriptionId(_:)` |
| `"one_signal_player_id"` | `.oneSignalPlayerId(_:)` |
| `"posthog_distinct_user_id"` | `.posthogDistinctUserId(_:)` |
| `"pushwoosh_hwid"` | `.pushwooshHWID(_:)` |
| `"tenjin_analytics_installation_id"` | `.tenjinAnalyticsInstallationId(_:)` |
---
# File: migration-to-ios-315
---
---
title: "Миграция Adapty iOS SDK на v3.15"
description: "Перейдите на Adapty iOS SDK v3.15 для повышения производительности и доступа к новым функциям монетизации."
---
Если вы используете [Paywall Builder](adapty-paywall-builder) в [режиме Observer](observer-vs-full-mode), начиная с iOS SDK 3.15, необходимо реализовать новый метод `observerModeDidInitiateRestorePurchases(onStartRestore:onFinishRestore:)`. Этот метод обеспечивает более гибкое управление логикой восстановления покупок и позволяет обрабатывать их в рамках собственного флоу. Подробности реализации см. в разделе [Отображение пейволов Paywall Builder в режиме Observer](ios-present-paywall-builder-paywalls-in-observer-mode).
```diff showLineNumbers
func observerMode(didInitiatePurchase product: AdaptyPaywallProduct,
onStartPurchase: @escaping () -> Void,
onFinishPurchase: @escaping () -> Void) {
// use the product object to handle the purchase
// use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase
}
+ func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void,
+ onFinishRestore: @escaping () -> Void) {
+ // use the onStartRestore and onFinishRestore callbacks to notify AdaptyUI about the process of the restore
+ }
```
---
# File: migration-to-ios-sdk-34
---
---
title: "Миграция Adapty iOS SDK на версию 3.4"
description: "Мигрируйте на Adapty iOS SDK v3.4 для повышения производительности и новых функций монетизации."
---
Adapty SDK 3.4.0 — это мажорный релиз, который включает улучшения, требующие шагов по миграции с вашей стороны.
## Обновление активации Adapty SDK \{#update-adapty-sdk-activation\}
### В момент входа или регистрации \{#during-loginsignup\}
Если вы идентифицируете пользователей после запуска приложения (например, после входа в аккаунт или регистрации), используйте метод `identify`, чтобы задать их customer user ID.
- Если вы **ещё не использовали этот customer user ID**, Adapty автоматически привяжет его к текущему профилю.
- Если вы **уже использовали этот customer user ID для идентификации пользователя раньше**, Adapty переключится на работу с профилем, связанным с этим customer user ID.
:::important
Идентификаторы пользователей (Customer User ID) должны быть уникальными для каждого пользователя. Если вы укажете фиксированное значение, все пользователи будут считаться одним.
:::
Дождитесь завершения `identify` (в колбэке `onSuccess`), прежде чем вызывать другие методы SDK. Конкурентные вызовы могут попасть на анонимный профиль. См. [Порядок вызовов в Kotlin Multiplatform SDK](kmp-sdk-call-order).
```kotlin showLineNumbers
Adapty.identify("YOUR_USER_ID") // Уникален для каждого пользователя
.onSuccess {
// successful identify
}
.onError { error ->
// handle the error
}
```
### При активации SDK \{#during-the-sdk-activation\}
Если вы уже знаете идентификатор пользователя на момент активации SDK, передайте его прямо в методе `activate` — вызывать `identify` отдельно не нужно.
Если идентификатор пользователя известен, но вы задаёте его только после активации, то при старте SDK Adapty создаст новый анонимный профиль и переключится на существующий лишь после вызова `identify`.
Вы можете передать как существующий customer user ID (тот, который вы уже использовали ранее), так и новый. Если передать новый, профиль, созданный при активации, будет автоматически привязан к этому customer user ID.
:::note
По умолчанию создание анонимных профилей не влияет на аналитику дашборда, поскольку установки считаются на основе идентификаторов устройств.
A device ID представляет собой одну установку приложения из стора на устройстве и regenerated only after the app is reinstalled.
Он не зависит от того, является ли это первой или повторной установкой, и от того, используется ли существующий customer user ID.
Создание профиля (при активации SDK или выходе из системы), вход в систему или обновление приложения без его переустановки не генерирует дополнительных событий установки.
Если вы хотите считать установки по уникальным пользователям, а не устройствам, перейдите в **App settings** и настройте [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```kotlin showLineNumbers
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one.
.build()
```
### Выход пользователей из системы \{#log-users-out\}
Если в вашем приложении есть кнопка выхода, используйте метод `logout`.
:::important
Выход из аккаунта создаёт новый анонимный профиль для пользователя.
:::
```kotlin showLineNumbers
Adapty.logout()
.onSuccess {
// successful logout
}
.onError { error ->
// handle the error
}
```
:::info
Чтобы снова войти в приложение, используйте метод `identify`.
:::
### Разрешите покупки без входа \{#allow-purchases-without-login\}
Если пользователи могут совершать покупки как до, так и после входа в приложение, необходимо убедиться, что после авторизации они сохранят доступ к своим покупкам:
1. Когда пользователь, не вошедший в систему, совершает покупку, Adapty привязывает её к анонимному ID профиля.
2. Когда пользователь входит в свой аккаунт, Adapty переключается на работу с идентифицированным профилем.
- Если это новый customer user ID (например, покупка была совершена до регистрации), Adapty присваивает customer user ID текущему профилю, и вся история покупок сохраняется.
- Если это существующий customer user ID (customer user ID уже привязан к профилю), после переключения профиля нужно получить актуальный уровень доступа. Можно либо вызвать [`getProfile`](kmp-check-subscription-status) сразу после идентификации, либо [подписаться на обновления профиля](kmp-check-subscription-status) — тогда данные будут синхронизироваться автоматически.
## Дальнейшие шаги \{#next-steps\}
Поздравляем! Вы реализовали логику встроенных покупок в своём приложении! Желаем вам успехов в монетизации!
Чтобы получить от Adapty ещё больше, изучите следующие темы:
- [**Тестирование**](troubleshooting-test-purchases): убедитесь, что всё работает как ожидается
- [**Интеграции**](configuration): подключите сервисы маркетинговой атрибуции и аналитики буквально в одну строку кода
- [**Настройка атрибутов профиля**](kmp-setting-user-attributes): добавляйте пользовательские атрибуты к профилям, создавайте сегменты и запускайте A/B-тесты или показывайте разные пейволы разным пользователям
---
# File: adapty-sdk-integration-skill-kmp
---
---
title: "Интеграция Adapty в приложение Kotlin Multiplatform с помощью навыка интеграции SDK"
description: "Используйте навык adapty-sdk-integration для полной интеграции SDK Adapty в ваше приложение Kotlin Multiplatform с вашим AI-инструментом для написания кода."
---
[Скилл adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) автоматизирует интеграцию Adapty от начала до конца: настройку дашборда, установку SDK, пейвол и проверку на каждом этапе. Он автоматически определяет вашу платформу и подгружает нужную документацию Adapty на каждом шаге.
**Поддерживаемые инструменты**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Для установки выберите команду для своего инструмента. Полный список — в [README скилла](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex или любой другой инструмент** — используйте [skills CLI](https://skills.sh) (обратите внимание, что скиллы, установленные таким способом, не обновляются автоматически):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Либо клонируйте репозиторий и скопируйте `skills/adapty-sdk-integration/` в директорию скиллов вашего инструмента.
После установки запустите скилл в вашем проекте:
```
/adapty-sdk-integration
```
Скилл задаст несколько вопросов по настройке, а затем проведёт через настройку дашборда, установку SDK, пейвол и проверку.
:::important
Навык находится в бета-версии. Если он зависает или ведёт себя неожиданно, используйте [пошаговый гайд по интеграции](adapty-cursor-kmp) — он проведёт ваш AI-инструмент через каждый этап с нужной документацией.
:::
[Скилл adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) автоматизирует интеграцию Adapty от начала до конца: настройку дашборда, установку SDK, пейвол и проверку на каждом этапе. Он автоматически определяет вашу платформу и подгружает нужную документацию Adapty на каждом шаге.
**Поддерживаемые инструменты**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Для установки выберите команду для своего инструмента. Полный список — в [README скилла](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex или любой другой инструмент** — используйте [skills CLI](https://skills.sh) (обратите внимание, что скиллы, установленные таким способом, не обновляются автоматически):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Либо клонируйте репозиторий и скопируйте `skills/adapty-sdk-integration/` в директорию скиллов вашего инструмента.
После установки запустите скилл в вашем проекте:
```
/adapty-sdk-integration
```
Скилл задаст несколько вопросов по настройке, а затем проведёт через настройку дашборда, установку SDK, пейвол и проверку.
---
# File: adapty-cursor-kmp
---
---
title: "Интеграция Adapty в ваше приложение Kotlin Multiplatform с помощью ИИ"
description: "Пошаговый гайд по интеграции Adapty в ваше приложение Kotlin Multiplatform с использованием Cursor, Context7, ChatGPT, Claude или других ИИ-инструментов."
---
Этот гайд проведёт вас через интеграцию Adapty в ваше Kotlin Multiplatform-приложение шаг за шагом с помощью AI-инструмента — вам нужно передавать ему нужную документацию Adapty в правильном порядке.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Прежде чем начать: настройка дашборда \{#before-you-start-dashboard-setup\}
Adapty требует предварительной настройки в дашборде, прежде чем вы напишете какой-либо код SDK. Это можно сделать с помощью интерактивного LLM-инструмента или вручную через дашборд.
### Подход через skill (рекомендуется) \{#skill-approach-recommended\}
Skill Adapty CLI позволяет вашему LLM настраивать приложение, продукты, уровни доступа, пейволы и плейсменты напрямую — без необходимости заходить в дашборд на каждом шаге. Вам нужно только [подключить сторы](integrate-payments) в дашборде.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
После добавления skill запустите `/adapty-cli` в своём агенте. Он проведёт вас через каждый шаг — включая моменты, когда нужно открыть дашборд для подключения сторов.
### Подход через дашборд
Если вы предпочитаете настраивать всё вручную, вот что нужно сделать до написания кода. LLM не сможет получить значения из дашборда за вас — их придётся указать самостоятельно.
1. **Подключите сторы**: В дашборде Adapty перейдите в **App settings → General**. Подключите App Store и Google Play, если ваше KMP-приложение поддерживает обе платформы. Это необходимо для работы покупок.
[Подключить сторы](integrate-payments)
2. **Скопируйте публичный SDK-ключ**: В дашборде Adapty перейдите в **App settings → General** и найдите раздел **API keys**. В коде это строка, которую вы передаёте в конфигуратор Adapty.
3. **Создайте хотя бы один продукт**: В дашборде Adapty перейдите на страницу **Products**. В коде вы не обращаетесь к продуктам напрямую — Adapty передаёт их через пейволы.
[Добавьте продукты](quickstart-products)
4. **Создайте пейвол и плейсмент**: в дашборде Adapty создайте пейвол на странице **Paywalls**, затем привяжите его к плейсменту на странице **Placements**. В коде идентификатор плейсмента — это строка, которую вы передаёте в `Adapty.getPaywall("YOUR_PLACEMENT_ID")`.
[Создать пейвол](quickstart-paywalls)
5. **Настройте уровни доступа**: В дашборде Adapty настройте каждый продукт на странице **Products**. В коде проверяется строка `profile.accessLevels["premium"]?.isActive`. Уровень доступа `premium` по умолчанию подходит для большинства приложений. Если платящие пользователи получают доступ к разным функциям в зависимости от продукта (например, план `basic` и план `pro`), [создайте дополнительные уровни доступа](assigning-access-level-to-a-product) до начала разработки.
:::tip
Когда у вас есть все пять, можно приступать к написанию кода. Скажите своему LLM: «Мой публичный SDK-ключ — X, мой ID плейсмента — Y», чтобы он сгенерировал корректный код инициализации и получения пейвола.
:::
### Настройте, когда будете готовы \{#set-up-when-ready\}
Это необязательно для начала разработки, но пригодится по мере развития интеграции:
- **A/B-тесты**: Настраиваются на странице **Placements**. Изменения в коде не нужны.
[A/B-тесты](ab-tests)
- **Дополнительные пейволы и плейсменты**: Добавьте больше вызовов `getPaywall` с разными идентификаторами плейсментов.
- **Интеграции с аналитикой**: Настраиваются на странице **Integrations**. Процесс настройки зависит от интеграции. См. [интеграции с аналитикой](analytics-integration) и [интеграции с атрибуцией](attribution-integration).
## Передайте документацию Adapty своему LLM \{#feed-adapty-docs-to-your-llm\}
### Используйте Context7 (рекомендуется) \{#use-context7-recommended\}
[Context7](https://context7.com) — это MCP-сервер, который даёт вашей LLM прямой доступ к актуальной документации Adapty. LLM автоматически находит нужные документы на основе вашего запроса — не нужно вручную вставлять ссылки.
Context7 работает с **Cursor**, **Claude Code**, **Windsurf** и другими инструментами, поддерживающими MCP. Для настройки выполните:
```
npx ctx7 setup
```
Команда определит ваш редактор и настроит сервер Context7. Для ручной настройки смотрите [репозиторий Context7 на GitHub](https://github.com/upstash/context7).
После настройки подключитесь к библиотеке Adapty в своих запросах:
```
Use the adaptyteam/adapty-docs library to look up how to install the Kotlin Multiplatform SDK
```
:::warning
Несмотря на то что Context7 устраняет необходимость вставлять ссылки на документацию вручную, порядок реализации имеет значение. Следуйте [пошаговому руководству по реализации](#implementation-walkthrough) строго по шагам, чтобы всё работало корректно.
:::
### Используйте документацию в формате plain text
Любую страницу документации Adapty можно открыть как plain text Markdown. Добавьте `.md` в конец URL или нажмите **Copy for LLM** под заголовком статьи. Например: [adapty-cursor-kmp.md](https://adapty.io/docs/ru/adapty-cursor-kmp.md).
В каждом шаге [пошагового руководства по интеграции](#implementation-walkthrough) ниже есть блок «Отправьте это в ваш LLM» со ссылками `.md` для вставки.
Чтобы получить сразу несколько страниц документации, см. [индексные файлы и платформо-специфичные подборки](#plain-text-doc-index-files) ниже.
## Пошаговое руководство по интеграции \{#implementation-walkthrough\}
Этот гайд описывает интеграцию Adapty в порядке реализации. Для каждого этапа указаны документы для отправки в LLM, ожидаемый результат и типичные проблемы.
### Планируйте интеграцию заранее \{#plan-your-integration\}
Прежде чем переходить к коду, попросите LLM проанализировать ваш проект и составить план реализации. Если ваш AI-инструмент поддерживает режим планирования (как в Cursor или Claude Code), воспользуйтесь им — LLM сможет изучить структуру вашего проекта и документацию Adapty до того, как начнёт писать код.
Сообщите LLM, какой подход к покупкам вы используете — от этого зависит, какие гайды он должен применять:
- [**Adapty Paywall Builder**](adapty-paywall-builder): Вы создаёте пейволы в визуальном редакторе Adapty, а SDK отображает их автоматически.
- [**Паywalls, созданные вручную**](kmp-making-purchases): Вы строите собственный интерфейс пейвола в коде, но используете Adapty для получения продуктов и обработки покупок.
- [**Observer mode**](observer-vs-full-mode): Вы сохраняете существующую инфраструктуру покупок и используете Adapty только для аналитики и интеграций.
Не знаете, что выбрать? Прочитайте [таблицу сравнения в quickstart](kmp-quickstart-paywalls).
### Установка и настройка SDK \{#install-and-configure-the-sdk\}
Добавьте зависимость Adapty SDK через Gradle и активируйте её с помощью вашего публичного ключа SDK. Это основа — без неё ничего не работает.
**Гайд:** [Установка и настройка Adapty SDK](sdk-installation-kotlin-multiplatform)
Отправьте это своему LLM:
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/ru/sdk-installation-kotlin-multiplatform.md
```
:::tip[Checkpoint]
- **Ожидаемый результат:** Приложение собирается и запускается. Logcat (Android) или консоль Xcode (iOS) показывает лог активации Adapty.
- **Частая ошибка:** «Public API key is missing» → убедитесь, что вы заменили плейсхолдер на реальный ключ из **App settings**.
:::
### Показывайте пейволы и обрабатывайте покупки \{#show-paywalls-and-handle-purchases\}
Получите пейвол по ID плейсмента, отобразите его и обработайте события покупок. Нужные вам гайды зависят от того, как вы обрабатываете покупки.
Тестируйте каждую покупку в песочнице по ходу работы — не откладывайте на конец. Инструкции по настройке см. в разделе [Тестирование покупок в песочнице](test-purchases-in-sandbox).
По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильный интернет, рассмотрите использование `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` для возврата кешированных данных, если они есть. В этом случае пользователи могут не получить самые последние данные, но загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии во избежание лишних сетевых запросов.
Обратите внимание, что кеш сохраняется после перезапуска приложения и очищается только при переустановке или ручной очистке.
Adapty SDK хранит флоу и пейволы локально в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Для более быстрой загрузки используется CDN, а также отдельный резервный сервер на случай недоступности CDN. Эта система гарантирует получение последней версии данных и надёжную работу даже при слабом интернете.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут метода. При его истечении будут возвращены кешированные данные или локальный резервный пейвол.
Обратите внимание, что в редких случаях метод может завершиться чуть позже указанного в `loadTimeout` значения, поскольку операция может включать несколько запросов под капотом.
Для Kotlin Multiplatform: вы можете создать `Duration` с помощью функций-расширений, например `5.seconds`, где `.seconds` — из `kotlin.time.Duration.Companion.seconds`.
| | Параметр | Описание | | :-------- | :---------- | | Flow | Объект `AdaptyFlow`, содержащий плейсмент, идентификаторы (`instanceIdentity`, `variationId`), название, варианты пейвола (`paywalls` — список `AdaptyFlowPaywall`) и Remote Config (`remoteConfigs` — список с одной записью на каждую локаль). Чтобы получить продукты для предзагрузки, кастомного UI или программных проверок, вызовите `getPaywallProducts(flow)`. | ## Получение конфигурации представления \{#fetch-the-view-configuration\} После получения флоу или пейвола загрузите конфигурацию представления и создайте само представление за один шаг с помощью метода `createFlowView`. Отдельного флага для проверки нет: если плейсмент был создан в **Flow Builder** (флоу) или **Paywall Builder** (пейвол), `createFlowView` возвращает представление, готовое к показу. Если плейсмент — это кастомный пейвол без UI в Builder, `createFlowView` возвращает `AdaptyResult.Error` — [обработайте его как пейвол с Remote Config](present-remote-config-paywalls-kmp). :::important Обязательно включите переключатель **Show on device** в Flow Builder. Если эта опция не включена, конфигурация представления не будет доступна для получения. ::: ```kotlin showLineNumbers AdaptyUI.createFlowView( flow = flow, loadTimeout = 5.seconds, preloadProducts = true ).onSuccess { view -> // use view }.onError { error -> // the flow has no view configured, or view creation failed } ``` | Параметр | Наличие | Описание | | :--------------------------- | :------------- | :----------------------------------------------------------- | | **flow** | обязательный | Объект `AdaptyFlow`, полученный через `Adapty.getFlow`. | | **loadTimeout** | необязательный | Ограничивает тайм-аут для этого метода. Если тайм-аут истёк, будут возвращены кэшированные данные или локальный резервный вариант. Обратите внимание, что в редких случаях метод может завершиться с тайм-аутом чуть позже указанного в `loadTimeout`, поскольку операция может включать несколько запросов под капотом. Можно использовать функции-расширения вроде `5.seconds` из `kotlin.time.Duration.Companion`. | | **preloadProducts** | необязательный | Установите `true`, чтобы заранее загрузить продукты для повышения производительности. При включении продукты загружаются заблаговременно, сокращая время отображения флоу или пейвола. | | **productPurchaseParams** | необязательный | Карта [`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) к [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). Используйте её для настройки параметров покупки — например, персонализированных предложений или параметров обновления подписки для отдельных продуктов во флоу или пейволе. | :::note Если вы используете несколько языков, узнайте, как добавить [локализацию в Builder](add-paywall-locale-in-adapty-paywall-builder). ::: После загрузки [отобразите флоу или пейвол](kmp-present-paywalls). ## Получите флоу или пейвол для аудитории по умолчанию, чтобы ускорить загрузку \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} Обычно флоу и пейволы загружаются почти мгновенно, так что беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и плейсментов, а соединение у пользователей слабое, загрузка флоу или пейвола может занять дольше, чем хотелось бы. В таких случаях имеет смысл показывать флоу или пейвол для аудитории по умолчанию — чтобы пользователь видел что-то, а не пустой экран. Чтобы решить эту задачу, можно использовать метод `getFlowForDefaultAudience`, который получает флоу или пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать флоу или пейвол через метод `getFlow`, как описано в разделе [Получение флоу/пейвола](#fetch-flowpaywall) выше. :::warning Почему мы рекомендуем использовать `getFlow` Метод `getFlowForDefaultAudience` имеет ряд существенных недостатков: - **Потенциальные проблемы обратной совместимости**: если вам нужно показывать разные флоу для разных версий приложения (текущей и будущих), могут возникнуть сложности. Придётся либо разрабатывать флоу, совместимые с текущей (устаревшей) версией, либо смириться с тем, что пользователи этой версии могут столкнуться с проблемами при отображении флоу. - **Потеря таргетинга**: все пользователи будут видеть одинаковый флоу, настроенный для аудитории **All Users**, — это означает потерю персонализированного таргетинга (в том числе по странам, маркетинговой атрибуции или вашим собственным пользовательским атрибутам). Если вы готовы принять эти ограничения ради более быстрой загрузки флоу или пейвола, используйте метод `getFlowForDefaultAudience` следующим образом. В противном случае используйте `getFlow`, описанный [выше](#fetch-flowpaywall). ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { flow -> // the requested flow }.onError { error -> // handle the error } ``` | Параметр | Наличие | Описание | |---------|--------|-----------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение вы указываете при создании плейсмента в дашборде Adapty. | | **fetchPolicy** | по умолчанию: `AdaptyPaywallFetchPolicy.Default` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае неудачи. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если вы считаете, что у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad`, чтобы возвращать кешированные данные при их наличии. В этом случае пользователи могут не получать самые свежие данные, зато время загрузки будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание, что кеш сохраняется после перезапуска приложения и очищается только при его переустановке или ручной очистке.
| ## Настройка ресурсов \{#customize-assets\} Чтобы настроить изображения и видео во флоу или пейволе, используйте кастомные ресурсы. Hero-изображения и видео имеют предопределённые идентификаторы: `hero_image` и `hero_video`. В бандле кастомных ресурсов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение. Для остальных изображений и видео нужно [задать кастомный идентификатор](custom-media) в дашборде Adapty. Например, можно: - Показывать разные изображения или видео для разных пользователей. - Показывать локальное превью-изображение, пока загружается основное удалённое изображение. - Показывать превью-изображение перед воспроизведением видео. Вот пример того, как можно передавать кастомные ресурсы через map: :::info SDK для Kotlin Multiplatform поддерживает только локальные ресурсы. Для удалённого контента необходимо скачать и закэшировать ресурсы локально, прежде чем использовать их в кастомных ресурсах. ::: ```kotlin showLineNumbers // Import generated Res class for accessing resources viewModelScope.launch { // Get URIs for bundled resources using Res.getUri() val heroImagePath = Res.getUri("files/images/hero_image.png") val demoVideoPath = Res.getUri("files/videos/demo_video.mp4") // Or read image as byte data val imageByteData = Res.readBytes("files/images/avatar.png") // Create custom assets map val customAssets: Mapопциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-paywall-locale-in-adapty-paywall-builder). Ожидается языковой код, состоящий из одного или двух субтегов, разделённых дефисом (**-**). Первый субтег — язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локализации и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `AdaptyPaywallFetchPolicy.Default` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` — оно вернёт кешированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в рамках сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит пейволы локально в двух слоях: описанный выше регулярно обновляемый кеш и [резервные пейволы](fallback-paywalls). Мы также используем CDN для ускоренной загрузки пейволов и отдельный резервный сервер на случай недоступности CDN. Эта система гарантирует, что вы всегда получаете актуальную версию пейволов, обеспечивая надёжность даже при слабом интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут для данного метода. При достижении таймаута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшим опозданием относительно значения `loadTimeout`, поскольку операция может включать несколько запросов внутри.
Для Kotlin Multiplatform: `TimeInterval` можно создать с помощью функций-расширений (например, `5.seconds`, где `.seconds` — из `import com.adapty.utils.seconds`) или `TimeInterval.seconds(5)`. Чтобы не ограничивать время ожидания, используйте `TimeInterval.INFINITE`.
| Параметры ответа: | Параметр | Описание | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Объект [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) со списком идентификаторов продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение конфигурации отображения пейвола, созданного в Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Убедитесь, что в Paywall Builder включён тумблер **Show on device**. Если эта опция отключена, конфигурация отображения будет недоступна для получения. ::: После получения пейвола проверьте, содержит ли он `ViewConfiguration` — это указывает на то, что он был создан с помощью Paywall Builder. Это поможет вам определить, как отображать пейвол. Если `ViewConfiguration` присутствует, обрабатывайте его как пейвол Paywall Builder; если нет, [обработайте его как пейвол с Remote Config](present-remote-config-paywalls-kmp). Используйте метод `createPaywallView`, чтобы загрузить конфигурацию отображения. ```kotlin showLineNumbers if (paywall.hasViewConfiguration) { AdaptyUI.createPaywallView( paywall = paywall, loadTimeout = 5.seconds, preloadProducts = true ).onSuccess { paywallView -> // use paywallView }.onError { error -> // handle the error } } else { // use your custom logic } ``` | Parameter | Presence | Description | | :--------------------------- | :------------- | :----------------------------------------------------------- | | **paywall** | required | Объект `AdaptyPaywall` для получения контроллера нужного пейвола. | | **loadTimeout** | optional | Ограничивает таймаут для этого метода. Если таймаут истекает, возвращаются кешированные данные или локальный резервный вариант. Обратите внимание, что в редких случаях метод может завершиться чуть позже указанного в `loadTimeout` значения, поскольку операция может состоять из нескольких запросов. Можно использовать функции-расширения, например `5.seconds` из `kotlin.time.Duration.Companion`. | | **preloadProducts** | optional | Установите `true`, чтобы заранее загрузить продукты для повышения производительности. При включении продукты загружаются заблаговременно, сокращая время отображения пейвола. | | **productPurchaseParams** | optional | Словарь, сопоставляющий [`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) с [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). Используйте его для настройки параметров покупки — например, персонализированных офферов или параметров обновления подписки для отдельных продуктов пейвола. | :::note Если вы используете несколько языков, узнайте, как добавить [локализацию Paywall Builder](add-paywall-locale-in-adapty-paywall-builder). ::: После загрузки [откройте пейвол](kmp-present-paywalls). ## Получите пейвол для аудитории по умолчанию, чтобы ускорить загрузку \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Как правило, пейволы загружаются почти мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и пейволов, а у пользователей слабое интернет-соединение, загрузка пейвола может занять больше времени, чем хотелось бы. В таких случаях стоит показывать пейвол по умолчанию — это обеспечит плавный пользовательский опыт вместо полного отсутствия пейвола. Чтобы решить эту проблему, используйте метод `getPaywallForDefaultAudience`, который загружает пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — загружать пейвол с помощью метода `getPaywall`, как описано в разделе [Получение информации о пейволе](#fetch-paywall-designed-with-paywall-builder) выше. :::warning Почему мы рекомендуем использовать `getPaywall` Метод `getPaywallForDefaultAudience` имеет ряд существенных недостатков: - **Возможные проблемы с обратной совместимостью**: если вам нужно показывать разные пейволы для разных версий приложения (текущей и будущих), могут возникнуть сложности. Придётся либо проектировать пейволы с поддержкой текущей (устаревшей) версии, либо смириться с тем, что пользователи этой версии могут столкнуться с проблемами — пейволы не будут отображаться. - **Потеря таргетинга**: все пользователи будут видеть один и тот же пейвол, настроенный для аудитории **All Users**, — это означает отказ от персонализированного таргетинга (в том числе по странам, маркетинговой атрибуции или собственным пользовательским атрибутам). Если вы готовы принять эти ограничения ради более быстрой загрузки пейвола, используйте метод `getPaywallForDefaultAudience`, как описано ниже. В противном случае используйте `getPaywall`, описанный [выше](#fetch-paywall-designed-with-paywall-builder). ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` | Параметр | Наличие | Описание | |---------|--------|-----------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **locale** |опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается, что этот параметр будет языковым кодом, состоящим из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Пример: `en` означает английский язык, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `AdaptyPaywallFetchPolicy.Default` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` — это позволит возвращать кешированные данные при их наличии. В таком случае пользователи могут получать не самые последние данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание, что кеш сохраняется при перезапуске приложения и очищается только при его переустановке или принудительной очистке вручную.
| ## Настройка ресурсов \{#customize-assets\} Чтобы настроить изображения и видео в пейволе, используйте пользовательские ресурсы. Главные изображения и видео имеют предопределённые идентификаторы: `hero_image` и `hero_video`. В пользовательском наборе ресурсов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение. Для других изображений и видео нужно [задать пользовательский идентификатор](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разные изображения или видео разным пользователям. - Показывать локальное превью-изображение, пока загружается основное удалённое изображение. - Показывать превью-изображение перед воспроизведением видео. :::important Чтобы использовать эту функцию, обновите SDK до версии 3.7.0 или выше. ::: Вот пример того, как можно передать пользовательские ресурсы через map: :::info Kotlin Multiplatform SDK поддерживает только локальные ресурсы. Для удалённого контента необходимо заранее скачать и кэшировать ресурсы локально, прежде чем использовать их в качестве пользовательских ресурсов. ::: ```kotlin showLineNumbers // Import generated Res class for accessing resources viewModelScope.launch { // Get URIs for bundled resources using Res.getUri() val heroImagePath = Res.getUri("files/images/hero_image.png") val demoVideoPath = Res.getUri("files/videos/demo_video.mp4") // Or read image as byte data val imageByteData = Res.readBytes("files/images/avatar.png") // Create custom assets map val customAssets: Map
## Слишком большое количество просмотров пейвола \{#the-paywall-view-number-is-too-big\}
**Проблема**: Счётчик просмотров пейвола показывает вдвое больше ожидаемого значения.
**Причина**: Возможно, в коде вызывается `logShowPaywall`, что дублирует счётчик просмотров при использовании Paywall Builder. Для пейволов, созданных с помощью Paywall Builder, аналитика отслеживается автоматически — использовать этот метод не нужно.
**Решение**: Убедитесь, что в коде не вызывается `logShowPaywall`, если вы используете Paywall Builder.
---
# File: kmp-implement-paywalls-manually
---
---
title: "Реализация пейволов вручную в Kotlin Multiplatform SDK"
description: "Узнайте, как реализовать пейволы вручную в вашем приложении на Kotlin Multiplatform с помощью Adapty SDK."
---
## Приём платежей \{#accept-purchases\}
Если вы работаете с пейволами собственной реализации, вы можете делегировать обработку покупок в Adapty с помощью метода `makePurchase`. Adapty возьмёт на себя все пользовательские сценарии, а вам останется только обрабатывать результаты покупок.
:::important
`makePurchase` работает с продуктами, созданными в дашборде Adapty. Убедитесь, что продукты и способы их получения настроены в дашборде — следуйте [quickstart guide](quickstart).
:::
По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае сбоя. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` — оно возвращает кэшированные данные, если они есть. В этом случае пользователи могут получить не самые свежие данные, зато загрузка будет быстрее независимо от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при его переустановке или принудительной очистке.
Adapty SDK хранит флоу и пейволы в двух слоях: регулярно обновляемый кэш, описанный выше, и [резервные пейволы](kmp-use-fallback-paywalls). Для ускоренной загрузки флоу и пейволов используется CDN, а также отдельный резервный сервер на случай недоступности CDN. Такая система гарантирует, что вы всегда получаете актуальные версии флоу и пейволов, сохраняя надёжность даже при нестабильном интернете.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут метода. Если таймаут истекает, возвращаются кэшированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeout`, поскольку операция может состоять из нескольких внутренних запросов.
| Не указывайте идентификаторы продуктов в коде! Поскольку флоу настраиваются удалённо, набор доступных продуктов, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код учитывает эти сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать именно 2. Но если позднее вы получите 3 продукта, приложение должно показать все 3 без каких-либо изменений в коде. Единственное, что нужно зафиксировать в коде, — это идентификатор плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Объект `AdaptyFlow` с: идентификатором флоу, вариантами пейвола (`paywalls` — каждый со своими идентификаторами продуктов), списком `remoteConfigs` (по одной записи на каждую настроенную локаль) и рядом других свойств. Чтобы получить продукты для флоу, вызовите `getPaywallProducts(flow)`. | :::note В v4 у `getFlow` нет параметра `locale`. При рендеринге флоу с помощью `createFlowView` локализация определяется автоматически. Для кастомных пейволов все доступные локали возвращаются вместе в `flow.remoteConfigs` — выберите локаль, соответствующую устройству пользователя или настройкам вашего приложения. Подробнее см. в разделе [Локализации и коды локалей](kmp-localizations-and-locale-codes). ::: ## Получение продуктов \{#fetch-products\} Получив флоу, можно запросить массив продуктов, соответствующих ему: ```kotlin showLineNumbers Adapty.getPaywallProducts(flow).onSuccess { products -> // the requested products }.onError { error -> // handle the error } ``` Параметры ответа: | Параметр | Описание | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Список объектов [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) с идентификатором продукта, названием продукта, ценой, валютой, длительностью подписки и рядом других свойств. | При реализации собственного дизайна флоу вам, скорее всего, потребуется доступ к этим свойствам объекта [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/). Ниже представлены наиболее часто используемые свойства; полный список доступных свойств см. в документации по ссылке. | Свойство | Описание | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Чтобы отобразить название продукта, используйте `product.localizedTitle`. Локализация определяется страной стора, выбранной пользователем, а не локалью устройства. | | **Price** | Чтобы отобразить цену в локализованном виде, используйте `product.price.localizedString`. Локализация определяется локалью устройства. Цену в виде числа можно получить через `product.price.amount` — значение будет в местной валюте. Чтобы получить символ валюты, используйте `product.price.currencySymbol`. | | **Subscription Period** | Чтобы отобразить период (например, неделя, месяц, год и т. д.), используйте `product.subscriptionDetails?.localizedSubscriptionPeriod`. Локализация определяется локалью устройства. Чтобы получить период подписки программно, используйте `product.subscriptionDetails?.subscriptionPeriod`. Из него можно получить enum `unit`, определяющий длину периода (DAY, WEEK, MONTH, YEAR или UNKNOWN). Значение `numberOfUnits` содержит количество единиц периода. Например, для квартальной подписки в свойстве `unit` будет `MONTH`, а в `numberOfUnits` — `3`. | | **Introductory Offer** | Чтобы отобразить значок или другой индикатор наличия introductory offer у подписки, проверьте свойство `product.subscriptionDetails?.introductoryOfferPhases`. Это список, который может содержать до двух фаз скидки: фазу бесплатного пробного периода и фазу вводной цены. В каждом объекте фазы доступны следующие полезные свойства:По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если вы считаете, что у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad`, чтобы возвращать кешированные данные при их наличии. В этом случае пользователи могут не получить самые последние данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии для уменьшения количества сетевых запросов.
Обратите внимание, что кеш сохраняется после перезапуска приложения и очищается только при его переустановке или при ручной очистке.
|необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается, что этот параметр будет языковым кодом, состоящим из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
| | **fetchPolicy** | по умолчанию: `AdaptyPaywallFetchPolicy.Default` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` — оно возвращает кэшированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание, что кэш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит пейволы в двух слоях: регулярно обновляемый кэш, описанный выше, и [резервные пейволы](kmp-use-fallback-paywalls). Также используется CDN для более быстрой загрузки пейволов и отдельный резервный сервер на случай недоступности CDN. Система спроектирована так, чтобы вы всегда получали актуальную версию пейволов даже при нестабильном интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает таймаут метода. По истечении таймаута будут возвращены кэшированные данные или локальный резервный пейвол.
Обратите внимание, что в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeout`, поскольку операция может включать несколько внутренних запросов.
| Не прописывайте идентификаторы продуктов в коде! Поскольку пейволы настраиваются удалённо, список доступных продуктов, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код учитывает эти сценарии. Например, если изначально вы получаете 2 продукта, приложение должно показывать 2 продукта. Но если позже вы получите 3 продукта, приложение должно отображать все 3 без каких-либо изменений в коде. Единственное, что нужно прописать в коде, — это идентификатор плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Объект [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) со списком идентификаторов продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение продуктов \{#fetch-products\} Получив пейвол, вы можете запросить массив продуктов, соответствующих ему: ```kotlin showLineNumbers Adapty.getPaywallProducts(paywall).onSuccess { products -> // the requested products }.onError { error -> // handle the error } ``` Параметры ответа: | Параметр | Описание | | :-------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Список объектов [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) с: идентификатором продукта, названием продукта, ценой, валютой, длительностью подписки и рядом других свойств. | При реализации собственного дизайна пейвола вам, скорее всего, понадобятся следующие свойства объекта [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/). Ниже приведены наиболее часто используемые свойства; полный список доступных свойств см. в связанной документации. | Свойство | Описание | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Чтобы отобразить название продукта, используйте `product.localizedTitle`. Локализация основана на стране стора, выбранной пользователем, а не на локали устройства. | | **Price** | Чтобы отобразить локализованную цену, используйте `product.price.localizedString`. Локализация основана на локали устройства. Цену также можно получить как число через `product.price.amount` — значение будет в местной валюте. Символ валюты доступен через `product.price.currencySymbol`. | | **Subscription Period** | Чтобы отобразить период подписки (например, неделя, месяц, год и т. д.), используйте `product.subscriptionDetails?.localizedSubscriptionPeriod`. Локализация основана на локали устройства. Для программного получения периода подписки используйте `product.subscriptionDetails?.subscriptionPeriod`. Оттуда можно обратиться к enum `unit`, чтобы узнать длину периода (DAY, WEEK, MONTH, YEAR или UNKNOWN). Значение `numberOfUnits` содержит количество единиц периода. Например, для квартальной подписки в свойстве `unit` будет `MONTH`, а в `numberOfUnits` — `3`. | | **Introductory Offer** | Чтобы показать значок или другой индикатор наличия introductory offer у подписки, проверьте свойство `product.subscriptionDetails?.introductoryOfferPhases`. Это список, который может содержать до двух фаз скидки: фазу бесплатного пробного периода и фазу вступительной цены. Каждый объект фазы содержит следующие полезные свойства:опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается языковой код, состоящий из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
| | **fetchPolicy** | по умолчанию: `AdaptyPaywallFetchPolicy.Default` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант: он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильный интернет, рассмотрите вариант `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут получить не самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
|Если запрос выполнен успешно, ответ содержит этот объект. Объект [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/) предоставляет исчерпывающую информацию об уровнях доступа пользователя, подписках и разовых покупках внутри приложения.
Проверьте статус уровня доступа, чтобы определить, есть ли у пользователя необходимый доступ к приложению.
| :::warning **Примечание:** если вы используете Apple StoreKit версии ниже v2.0 и Adapty SDK версии ниже v2.9.0, вам необходимо указать [общий секрет Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret) вместо этого. Этот метод в настоящее время устарел по решению Apple. ::: ## Изменение подписки при совершении покупки \{#change-subscription-when-making-a-purchase\} Когда пользователь выбирает новую подписку вместо продления текущей, поведение зависит от стора. В Google Play подписка не обновляется автоматически. Вам нужно управлять переключением в коде мобильного приложения, как описано ниже. Чтобы заменить подписку другой в Android, вызовите метод `.makePurchase()` с дополнительным параметром: ```kotlin showLineNumbers val subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters( oldSubVendorProductId = "old_subscription_product_id", replacementMode = AdaptyAndroidSubscriptionUpdateReplacementMode.CHARGE_FULL_PRICE ) val purchaseParams = AdaptyPurchaseParameters.Builder() .setSubscriptionUpdateParams(subscriptionUpdateParams) .build() Adapty.makePurchase( product = product, parameters = purchaseParams ).onSuccess { purchaseResult -> when (purchaseResult) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // successful cross-grade } is AdaptyPurchaseResult.UserCanceled -> { // user canceled the purchase flow } is AdaptyPurchaseResult.Pending -> { // the purchase has not been finished yet, e.g. user will pay offline by cash } } }.onError { error -> // Handle the error } ``` Дополнительный параметр запроса: | Параметр | Наличие | Описание | |:---------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **parameters** | опционально | объект [`AdaptyAndroidSubscriptionUpdateParameters`](https://kmp.adapty.io/////adapty/com.adapty.kmp.models/-adapty-android-subscription-update-parameters/), передаваемый через [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). | Подробнее о подписках и режимах замены можно прочитать в документации Google для разработчиков: - [О режимах замены](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Рекомендации Google по режимам замены](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Режим замены [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Примечание: этот метод доступен только для апгрейда подписки. Даунгрейд не поддерживается. - Режим замены [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Примечание: фактическая смена подписки произойдёт только по окончании текущего расчётного периода. ## Погашение промокодов в iOS \{#redeem-offer-codes-in-ios\}Объект [`AdaptyProfile`](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-profile/). Эта модель содержит информацию об уровнях доступа, подписках и разовых покупках.
Проверьте **статус уровня доступа**, чтобы определить, есть ли у пользователя доступ к приложению.
| :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: --- # File: implement-observer-mode-kmp --- --- title: "Реализация режима Observer в Kotlin Multiplatform SDK" description: "Реализуйте режим observer в Adapty для отслеживания событий подписок пользователей в Kotlin Multiplatform SDK." --- Если у вас уже есть собственная инфраструктура покупок и вы не готовы полностью переходить на Adapty, вы можете рассмотреть [Observer mode](observer-vs-full-mode). В базовом варианте Observer Mode предоставляет расширенную аналитику и бесшовную интеграцию с системами атрибуции и аналитики. Если это соответствует вашим потребностям, вам нужно лишь: 1. Включить его при настройке Adapty SDK, установив параметр `observerMode` в значение `true`. Следуйте инструкциям по настройке для [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform). 2. [Передавать транзакции](report-transactions-observer-mode-kmp) из вашей существующей инфраструктуры покупок в Adapty. :::tip В SDK v4 вы также можете отображать флоу и пейволы, отрисованные Adapty, в Observer mode: когда пользователь нажимает кнопку покупки или восстановления, SDK передаёт действие вашему коду, чтобы вы могли самостоятельно выполнить покупку или восстановление. См. [Отображение флоу в Observer mode](kmp-present-flows-in-observer-mode). ::: ## Настройка режима наблюдателя \{#observer-mode-setup\} Включите режим наблюдателя, если вы самостоятельно обрабатываете покупки и статус подписки, а Adapty используете только для отправки событий подписки и аналитики. :::important В режиме наблюдателя Adapty SDK не закрывает транзакции — убедитесь, что вы обрабатываете их самостоятельно. ::: ```kotlin showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withObserverMode(true) // default false .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised in observer mode") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } ``` Параметры: | Параметр | Описание | | --------------------------- | ------------------------------------------------------------ | | observerMode | Булево значение, которое управляет [режимом Observer](observer-vs-full-mode). Значение по умолчанию — `false`. | ## Использование пейволов Adapty в режиме Observer \{#using-adapty-paywalls-in-observer-mode\} Если вы также хотите использовать пейволы Adapty и функции A/B-тестирования, это возможно — но в режиме Observer потребуется дополнительная настройка. Помимо шагов выше, вам нужно будет сделать следующее: 1. Отображайте пейволы как обычно для [пейволов на основе Remote Config](present-remote-config-paywalls-kmp). 3. [Связывайте пейволы](report-transactions-observer-mode-kmp) с транзакциями покупок. --- # File: report-transactions-observer-mode-kmp --- --- title: "Передача транзакций в Observer Mode в Kotlin Multiplatform SDK" description: "Передавайте транзакции покупок в Adapty Observer Mode для отслеживания пользовательских данных и доходов в Kotlin Multiplatform SDK." --- В Observer Mode SDK Adapty не может самостоятельно отслеживать покупки, совершённые через вашу существующую систему. Вам нужно передавать транзакции из стора вручную. Важно настроить это **до** выпуска приложения, чтобы избежать ошибок в аналитике. Используйте `reportTransaction`, чтобы явно сообщать Adapty о каждой транзакции. :::warning **Не пропускайте передачу транзакций!** Если вы не вызываете `reportTransaction`, Adapty не распознает транзакцию, она не появится в аналитике и не будет отправлена в интеграции. ::: Если вы используете пейволы Adapty, передавайте `variationId` при отчёте о транзакции. Это связывает покупку с пейволом, который её инициировал, и обеспечивает точную аналитику пейволов. ```kotlin showLineNumbers Adapty.reportTransaction( transactionId = "your_transaction_id", variationId = paywall.variationId ).onSuccess { profile -> // Transaction reported successfully // profile contains updated user data }.onError { error -> // handle the error } ``` Параметры: | Параметр | Обязательность | Описание | | --------------- | -------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | обязательный | Идентификатор транзакции из стора. Как правило, это токен покупки или идентификатор транзакции, возвращаемый стором. | | variationId | необязательный | Строковый идентификатор варианта. Его можно получить через свойство `variationId` объекта [AdaptyPaywall](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-paywall/). | --- # File: kmp-troubleshoot-purchases --- --- title: "Устранение неполадок с покупками в Kotlin Multiplatform SDK" description: "Устранение неполадок с покупками в Kotlin Multiplatform SDK" --- Этот гайд поможет вам решить распространённые проблемы при ручной реализации покупок в Kotlin Multiplatform SDK. ## makePurchase выполняется успешно, но профиль не обновляется \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **Проблема**: Метод `makePurchase` завершается успешно, но профиль пользователя и статус подписки в Adapty не обновляются. **Причина**: Как правило, это указывает на неполную настройку Google Play Store или ошибки конфигурации. **Решение**: Убедитесь, что вы выполнили все [шаги настройки Google Play](initial-android). ## makePurchase вызывается дважды \{#makepurchase-is-invoked-twice\} **Проблема**: Метод `makePurchase` вызывается несколько раз для одной и той же покупки. **Причина**: Обычно это происходит из-за того, что процесс покупки запускается несколько раз вследствие проблем с управлением состоянием UI или быстрых повторных действий пользователя. **Решение**: Убедитесь, что вы выполнили все [шаги настройки Google Play](initial-android). ## AdaptyError.cantMakePayments в режиме Observer \{#adaptyelrorcantmakepayments-in-observer-mode\} **Проблема**: При использовании `makePurchase` в режиме Observer вы получаете ошибку `AdaptyError.cantMakePayments`. **Причина**: В режиме Observer покупки должны обрабатываться на вашей стороне — использовать метод `makePurchase` от Adapty не следует. **Решение**: Если вы используете `makePurchase` для покупок, отключите режим Observer. Нужно либо использовать `makePurchase`, либо обрабатывать покупки самостоятельно в режиме Observer. Подробнее см. в разделе [Реализация режима Observer](implement-observer-mode-kmp). ## Ошибка Adapty: (code: 103, message: Play Market request failed on purchases updated: responseCode=3, debugMessage=Billing Unavailable, detail: null) \{#adapty-error-code-103-message-play-market-request-failed-on-purchases-updated-responsecode3-debugmessagebilling-unavailable-detail-null\} **Проблема**: Вы получаете ошибку недоступности биллинга от Google Play Store. **Причина**: Эта ошибка не связана с Adapty. Это ошибка Google Play Billing Library, указывающая на то, что биллинг недоступен на устройстве. **Решение**: Эта ошибка не связана с Adapty. Подробнее о ней можно узнать в документации Play Store: [Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers. ## makePurchasesCompletionHandlers не найден \{#not-found-makepurchasescompletionhandlers\} **Проблема**: Вы сталкиваетесь с тем, что `makePurchasesCompletionHandlers` не удаётся найти. **Причина**: Как правило, это связано с проблемами при тестировании в песочнице. **Решение**: Создайте нового пользователя в песочнице и повторите попытку. Это обычно решает проблемы с обработчиком завершения покупки в песочнице. --- # File: kmp-user --- --- title: "Пользователи и доступ в Kotlin Multiplatform SDK" description: "Узнайте, как работать с пользователями и уровнями доступа в приложении Kotlin Multiplatform с помощью Adapty SDK." --- На этой странице собраны все гайды по работе с пользователями и уровнями доступа в приложении Kotlin Multiplatform. Выберите нужный раздел: - **[Идентификация пользователей](kmp-identifying-users)** — узнайте, как идентифицировать пользователей в приложении - **[Обновление данных пользователя](kmp-setting-user-attributes)** — задайте атрибуты пользователя и данные профиля - **[Отслеживание изменений статуса подписки](kmp-listen-subscription-changes)** — отслеживайте изменения подписки в режиме реального времени - **[Режим Kids Mode](kids-mode-kmp)** — реализуйте Kids Mode в своём приложении --- # File: kmp-identifying-users --- --- title: "Идентификация пользователей в Kotlin Multiplatform SDK" description: "Идентифицируйте пользователей в Adapty для улучшения персонализированного опыта с подписками." --- Adapty создаёт внутренний ID профиля для каждого пользователя. Однако если у вас есть собственная система аутентификации, вам следует задать свой Customer User ID. Вы можете найти пользователей по их Customer User ID в разделе [Профили](profiles-crm) и использовать его в [серверном API](getting-started-with-server-side-api) — он будет передаваться во все интеграции. ### Указание идентификатора пользователя при настройке \{#setting-customer-user-id-on-configuration\} Если идентификатор пользователя известен в момент настройки, передайте его в параметре `customerUserId` метода `.activate()`: ```kotlin showLineNumbers Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("YOUR_USER_ID") .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } } ``` :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ### Указание customer user ID после инициализации \{#setting-customer-user-id-after-configuration\} Если при настройке SDK у вас не было user ID, его можно задать позже в любой момент с помощью метода `.identify()`. Чаще всего этот метод используется после регистрации или авторизации — когда пользователь переходит из анонимного состояния в аутентифицированное. ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID").onSuccess { // successful identify }.onError { error -> // handle the error } ``` Параметры запроса: - **Customer User ID** (обязательный): строковый идентификатор пользователя. :::warning Повторная отправка важных данных пользователя В некоторых случаях, например когда пользователь снова входит в аккаунт, серверы Adapty уже располагают информацией об этом пользователе. В таких ситуациях Adapty SDK автоматически переключится на работу с новым пользователем. Если вы передавали какие-либо данные анонимному пользователю — например, пользовательские атрибуты или атрибуцию из сторонних сетей — необходимо повторно отправить эти данные для идентифицированного пользователя. Также важно учитывать, что после идентификации пользователя следует заново запросить все пейволы и продукты, поскольку данные нового пользователя могут отличаться. ::: ### Выход и вход в систему \{#logging-out-and-logging-in\} Вы можете выйти из системы в любой момент, вызвав метод `.logout()`: ```kotlin showLineNumbers Adapty.logout().onSuccess { // successful logout }.onError { error -> // handle the error } ``` После этого можно войти снова с помощью метода `.identify()`. ## Назначение `appAccountToken` (iOS) \{#assign-appaccounttoken-ios\} [`iosAppAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) — это **UUID**, который позволяет связать транзакции App Store с внутренним идентификатором пользователя. StoreKit прикрепляет этот токен к каждой транзакции, чтобы ваш бэкенд мог сопоставить данные App Store с конкретными пользователями. Используйте стабильный UUID, сгенерированный для каждого пользователя, и повторно применяйте его для одного и того же аккаунта на всех устройствах. Это гарантирует, что покупки и уведомления App Store будут корректно связаны с нужным пользователем. Токен можно передать двумя способами — при активации SDK или при идентификации пользователя. :::important Необходимо всегда передавать `iosAppAccountToken` вместе с `customerUserId`. Если передать только токен, он не будет включён в транзакцию. ::: ```kotlin showLineNumbers // During configuration: Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId( id = "YOUR_USER_ID", iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN" ) .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } // Or when identifying users Adapty.identify( customerUserId = "YOUR_USER_ID", iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN" ).onSuccess { // successful identify }.onError { error -> // handle the error } ``` ## Установка обфусцированных идентификаторов аккаунта (Android) \{#set-obfuscated-account-ids-android\} Google Play требует обфусцированные идентификаторы аккаунта в ряде сценариев — для защиты конфиденциальности и безопасности пользователей. Эти идентификаторы позволяют Google Play отслеживать покупки, не раскрывая личные данные пользователей, что особенно важно для предотвращения мошенничества и аналитики. Задавать такие идентификаторы может потребоваться, если приложение обрабатывает чувствительные пользовательские данные или должно соответствовать определённым требованиям по защите персональных данных. Обфусцированные идентификаторы позволяют Google Play отслеживать покупки, не раскрывая реальные идентификаторы пользователей. :::important Вы всегда должны передавать `androidObfuscatedAccountId` вместе с `customerUserId`. Если передать только obfuscated account ID, он не будет включён в транзакцию. ::: ```kotlin showLineNumbers // During configuration: Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId( id = "YOUR_USER_ID", androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID" ) .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } // Or when identifying users Adapty.identify( customerUserId = "YOUR_USER_ID", androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID" ).onSuccess { // successful identify }.onError { error -> // handle the error } ``` ## Определение пользователей на разных устройствах \{#detect-users-across-devices\} При активации SDK он автоматически считывает существующие права пользователя из StoreKit (iOS) или Google Play Billing (Android) и синхронизирует их с бэкендом Adapty. Активная подписка появляется в профиле Adapty без вызова `restorePurchases` со стороны приложения. Что **не** происходит автоматически — так это распознавание того, что профиль на новом устройстве принадлежит тому же пользователю, что и профиль на исходном устройстве. Adapty сопоставляет профили по Customer User ID, поэтому непрерывность идентификации зависит от того, что вы используете в качестве CUID. **Что Adapty может определить между устройствами** | Ваша настройка | Что Adapty определяет | Что нужно сделать | | --- | --- | --- | | Customer User ID = `device_id` (без входа в аккаунт) | Новое устройство получает другой CUID и, следовательно, другой профиль. Подписка синхронизируется с новым профилем через событие **Access level updated**, но `subscription_started` не срабатывает — новый профиль считается наследником исходной покупки. Аналитика, основанная на `subscription_started`, будет занижать количество возвращающихся пользователей. | Используйте стабильный идентификатор аккаунта в качестве Customer User ID, чтобы вернувшийся пользователь соответствовал существующему профилю на разных устройствах. | | Customer User ID = стабильный идентификатор аккаунта (вход на каждом устройстве) | SDK автоматически синхронизирует подписку при `activate()`, а `identify()` сопоставляет существующий профиль по CUID. | Никаких дополнительных действий не требуется — и идентификация, и подписка разрешаются автоматически. | | Наследник Apple Family Sharing | Член семьи получает подписку только через событие **Access level updated** — `subscription_started` не срабатывает. | Отслеживайте событие **Access level updated**. Полную матрицу событий см. в разделе [Apple Family Sharing](apple-family-sharing). | | Один аккаунт Apple/Google, разные пользователи внутри приложения | Первый профиль, зафиксировавший покупку, становится родительским. Последующие профили видят подписку через цепочку наследования с одним событием **Access level updated**. | Требуйте входа в аккаунт, затем выберите [режим совместного использования](sharing-paid-access-between-user-accounts), подходящий для вашей модели. | **Восстановление покупок на новом устройстве** Добавьте кнопку «Восстановить покупки», инициируемую пользователем, на свой пейвол. Apple App Review (руководство 3.1.1) её требует, и она служит запасным вариантом на случай, если автоматическая синхронизация пропустит граничный случай. Кнопка должна вызывать `restorePurchases` в вашем SDK. Программный вызов `restorePurchases` при первом запуске не нужен для обычного использования — SDK уже выполняет аналогичную операцию при `activate()`. Программные вызовы стоит использовать только для принудительной проверки чека, например при отладке отсутствующего доступа после завершения `activate()`. --- # File: kmp-setting-user-attributes --- --- title: "Установка атрибутов пользователя в Kotlin Multiplatform SDK" description: "Узнайте, как устанавливать атрибуты пользователя в Adapty для улучшенной сегментации аудитории." --- Вы можете задавать пользователям приложения необязательные атрибуты: email, номер телефона и т.д. Атрибуты можно использовать для создания [сегментов](segments) пользователей или просматривать их в CRM. ### Установка атрибутов пользователя \{#setting-user-attributes\} Чтобы установить атрибуты пользователя, вызовите метод `.updateProfile()`: ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() .withEmail("email@email.com") .withPhoneNumber("+18888888888") .withFirstName("John") .withLastName("Appleseed") .withGender(AdaptyProfile.Gender.FEMALE) .withBirthday(AdaptyProfile.Date(1970, 1, 3)) Adapty.updateProfile(builder.build()) .onSuccess { // profile updated successfully } .onError { error -> // handle the error } ``` Обратите внимание: атрибуты, ранее установленные с помощью метода `updateProfile`, не сбрасываются. :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ### Список допустимых ключей \{#the-allowed-keys-list\} Допустимые ключи `phoneNumber
firstName
lastName
| String | | gender | Enum, допустимые значения: `AdaptyProfile.Gender.FEMALE`, `AdaptyProfile.Gender.MALE`, `AdaptyProfile.Gender.OTHER` | | birthday | Date | ### Пользовательские атрибуты \{#custom-user-attributes\} Вы можете задавать собственные пользовательские атрибуты — как правило, они связаны с использованием приложения. Например, для фитнес-приложений это может быть количество тренировок в неделю, для приложений для изучения языков — уровень знаний пользователя и т.д. Их можно использовать в сегментах для создания целевых пейволов и предложений, а также в аналитике для выявления продуктовых метрик, которые сильнее всего влияют на выручку. ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() builder.withCustomAttribute("key1", "value1") ``` Чтобы удалить существующий ключ, используйте метод `.withRemovedCustomAttribute()`: ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() builder.withRemovedCustomAttribute("key2") ``` Иногда нужно узнать, какие пользовательские атрибуты уже установлены. Для этого используйте поле `customAttributes` объекта `AdaptyProfile`. :::warning Имейте в виду, что значение `customAttributes` может быть устаревшим: атрибуты пользователя могут отправляться с разных устройств в любое время, поэтому данные на сервере могут измениться после последней синхронизации. ::: ### Ограничения \{#limits\} - До 30 пользовательских атрибутов на пользователя - Длина имени ключа — до 30 символов. Имя ключа может содержать буквенно-цифровые символы, а также: `_` `-` `.` - Значение может быть строкой или числом с плавающей точкой длиной не более 50 символов. --- # File: kmp-listen-subscription-changes --- --- title: "Проверка статуса подписки в Kotlin Multiplatform SDK" description: "Отслеживайте и управляйте статусом подписки пользователей в Adapty для повышения удержания клиентов в вашем приложении на Kotlin Multiplatform." --- Adapty упрощает отслеживание статуса подписки. Вам не нужно вручную прописывать ID продуктов в коде — достаточно проверить наличие активного [уровня доступа](access-level), чтобы убедиться, что у пользователя есть подписка. Прежде чем приступить к проверке статуса подписки, настройте [Real-time Developer Notifications (RTDN)](enable-real-time-developer-notifications-rtdn). ## Уровень доступа и объект AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Уровни доступа — это свойства объекта [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/). Рекомендуем получать профиль при запуске приложения, например когда вы [идентифицируете пользователя](android-identifying-users#setting-customer-user-id-on-configuration), и обновлять его при каждом изменении. Так вы сможете использовать объект профиля без повторных запросов. Чтобы получать уведомления об обновлениях профиля, подпишитесь на изменения профиля, как описано в разделе [Подписка на обновления профиля, включая уровни доступа](android-listen-subscription-changes) ниже. :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ## Получение уровня доступа с сервера \{#retrieving-the-access-level-from-the-server\} Чтобы получить уровень доступа с сервера, используйте метод `.getProfile()`: ```kotlin showLineNumbers Adapty.getProfile().onSuccess { profile -> // check the access }.onError { error -> // handle the error } ``` Параметры ответа: | Параметр | Описание | | --------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Profile |Объект [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/). Как правило, достаточно проверить статус уровня доступа профиля, чтобы определить, есть ли у пользователя премиум-доступ к приложению.
Метод `.getProfile` возвращает наиболее актуальные данные, поскольку всегда пытается запросить API. Если по какой-либо причине (например, при отсутствии интернета) Adapty SDK не может получить информацию с сервера, возвращаются данные из кэша. Также важно учитывать, что Adapty SDK регулярно обновляет кэш `AdaptyProfile`, чтобы поддерживать данные в актуальном состоянии.
| Метод `.getProfile()` возвращает профиль пользователя, из которого можно получить статус уровня доступа. В одном приложении может быть несколько уровней доступа. Например, в приложении-газете с независимыми подписками на разные рубрики можно создать уровни доступа «sports» и «science». Однако в большинстве случаев достаточно одного уровня доступа — тогда можно просто использовать стандартный уровень «premium». Вот пример проверки стандартного уровня доступа «premium»: ```kotlin showLineNumbers Adapty.getProfile().onSuccess { profile -> if (profile.accessLevels["premium"]?.isActive == true) { // grant access to premium features } }.onError { error -> // handle the error } ``` ### Подписка на обновления статуса подписки \{#listening-for-subscription-status-updates\} При каждом изменении подписки пользователя Adapty генерирует событие. Чтобы получать сообщения от Adapty, необходима дополнительная настройка: ```kotlin showLineNumbers Adapty.setOnProfileUpdatedListener { profile -> // handle any changes to subscription state } ``` Adapty также генерирует событие при запуске приложения. В этом случае передаётся кэшированный статус подписки. ### Кэш статуса подписки \{#subscription-status-cache\} Кэш, реализованный в Adapty SDK, хранит статус подписки профиля. Это означает, что даже при недоступности сервера кэшированные данные позволяют получить информацию о статусе подписки профиля. Следует учитывать, что напрямую запрашивать данные из кэша невозможно. SDK периодически опрашивает сервер каждую минуту, проверяя наличие обновлений или изменений в профиле. При обнаружении изменений — например, новых транзакций или других обновлений — они отправляются в кэшированные данные для синхронизации с сервером. --- # File: kmp-deal-with-att --- --- title: "Работа с ATT в Kotlin Multiplatform SDK" description: "Начните работу с Adapty на Kotlin Multiplatform для упрощения настройки подписок и управления ими." --- Если ваше приложение использует фреймворк AppTrackingTransparency и показывает пользователю запрос на авторизацию отслеживания, необходимо отправить [статус авторизации](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) в Adapty. ```kotlin showLineNumbers val profileParameters = AdaptyProfileParameters.Builder() .withAttStatus(3) // 3 = ATTrackingManagerAuthorizationStatusAuthorized .build() Adapty.updateProfile(profileParameters) .onSuccess { // ATT status updated successfully } .onError { error -> // handle AdaptyError } ``` :::warning Настоятельно рекомендуем передавать это значение как можно раньше при его изменении — только в этом случае данные будут своевременно отправлены в настроенные вами интеграции. ::: --- # File: kids-mode-kmp --- --- title: "Детский режим в Kotlin Multiplatform SDK" description: "Легко включите детский режим для соблюдения политик Google. GAID и рекламные данные не собираются в Kotlin Multiplatform SDK." --- Если ваше приложение на Kotlin Multiplatform предназначено для детей, вы обязаны соблюдать политики [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Если вы используете Adapty SDK, несколько простых шагов помогут настроить его в соответствии с этими политиками и пройти проверку в сторах. ## Что нужно сделать? \{#whats-required\} Необходимо настроить Adapty SDK так, чтобы отключить сбор: - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS) - [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android) - [IP-адреса](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) Кроме того, рекомендуем осторожно использовать пользовательский идентификатор (customer user ID). Идентификатор в формате `необязательный
по умолчанию: `en`
| Идентификатор локализации онбординга. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.Например: `en` — английский, `pt-br` — бразильский португальский.
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера, а в случае ошибки возвращает кешированные данные. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные при их наличии. В этом случае пользователи могут получать не самые последние данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные онбординги. Также используется CDN для ускоренной загрузки онбордингов и отдельный резервный сервер на случай недоступности CDN. Эта система гарантирует, что вы всегда получаете актуальную версию онбордингов даже при нестабильном интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Это значение ограничивает тайм-аут для данного метода. По истечении тайм-аута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения, заданного в `loadTimeout`, поскольку операция может включать несколько внутренних запросов.
| ## Параметры ответа \{#response-parameters\} | Параметр | Описание | |:----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Объект [`AdaptyOnboarding`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-onboarding/) с: идентификатором и конфигурацией онбординга, Remote Config и рядом других свойств. | ## Ускорьте загрузку онбординга с помощью онбординга для аудитории по умолчанию \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Как правило, онбординги загружаются почти мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и онбордингов, а пользователи находятся при слабом интернет-соединении, загрузка онбординга может занять больше времени, чем хотелось бы. В таких ситуациях имеет смысл отображать онбординг по умолчанию — чтобы обеспечить плавный пользовательский опыт вместо того, чтобы не показывать ничего. Чтобы решить эту проблему, вы можете использовать метод `getOnboardingForDefaultAudience`, который загружает онбординг указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — загружать онбординг с помощью метода `getOnboarding`, как описано в разделе [Загрузка онбординга](#fetch-onboarding) выше. :::warning Используйте `getOnboarding` вместо `getOnboardingForDefaultAudience`, так как у последнего есть существенные ограничения: - **Проблемы совместимости**: могут возникать трудности при поддержке нескольких версий приложения — придётся либо делать дизайн обратно совместимым, либо мириться с некорректным отображением в старых версиях. - **Отсутствие персонализации**: показывается только контент для аудитории «Все пользователи», без таргетинга по стране, атрибуции или пользовательским атрибутам. Если для вашего сценария скорость загрузки важнее этих недостатков, используйте `getOnboardingForDefaultAudience`, как показано ниже. В противном случае используйте `getOnboarding`, как описано [выше](#fetch-onboarding). ::: ```kotlin showLineNumbers Adapty.getOnboardingForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { paywall -> // запрошенный онбординг }.onError { error -> // обработайте ошибку } ``` Параметры: | Параметр | Наличие | Описание | |---------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **locale** |опциональный
по умолчанию: `en`
| Идентификатор локализации онбординга. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых знаком минус (**-**). Первый подтег обозначает язык, второй — регион.По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут получать не самые свежие данные, но загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется после перезапуска приложения и очищается только при его переустановке или ручной очистке.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные онбординги. Мы также используем CDN для более быстрой загрузки онбордингов и отдельный резервный сервер на случай недоступности CDN. Система спроектирована так, чтобы вы всегда получали актуальную версию онбордингов, даже при нестабильном интернет-соединении.
| --- # File: kmp-present-onboardings --- --- title: "Показ онбординга в Kotlin Multiplatform SDK" description: "Узнайте, как эффективно показывать онбординги и повышать конверсию." --- :::warning **Онбординги устарели в SDK v4 и будут удалены в одном из следующих релизов.** Они больше не получают исправлений и улучшений. Используйте [флоу](kmp-get-pb-paywalls) вместо них: в отличие от онбордингов, которые работают внутри WebView, флоу рендерятся нативно на устройстве — это обеспечивает более плавные анимации, единый нативный внешний вид, быструю загрузку и отсутствие зависимости от WebView. Подробнее — в разделах [Получение флоу и пейволов](kmp-get-pb-paywalls) и [Отображение флоу и пейволов](kmp-present-paywalls). ::: Если вы создали онбординг с помощью билдера, вам не нужно беспокоиться о его отрисовке в коде вашего Kotlin Multiplatform приложения для показа пользователю. Такой онбординг содержит как то, что должно быть показано, так и то, как именно это должно быть показано. Прежде чем начать, убедитесь, что: 1. Вы установили [Adapty Kotlin Multiplatform SDK](sdk-installation-kotlin-multiplatform) версии 3.16.1 или выше. 2. Вы [создали онбординг](create-onboarding). 3. Вы добавили онбординг в [плейсмент](placements). Adapty Kotlin Multiplatform SDK предоставляет два способа отображения онбординга: - **С Compose Multiplatform** - **Без Compose Multiplatform** ## С Compose Multiplatform \{#with-compose-multiplatform\} Чтобы отобразить онбординг, вызовите метод `view.present()` на объекте `view`, созданном методом `createOnboardingView`. Каждый `view` можно использовать только один раз. Если нужно показать онбординг снова, вызовите `createOnboardingView` ещё раз, чтобы создать новый экземпляр `view`. :::warning Повторное использование одного и того же `view` без его пересоздания может привести к ошибке. ::: ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { AdaptyUI.createOnboardingView(onboarding = onboarding).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ### Настройка стиля представления для iOS \{#configure-ios-presentation-style\} Настройте способ отображения онбординга на iOS, передав параметр `iosPresentationStyle` в метод `present()`. Параметр принимает значения `AdaptyUIIOSPresentationStyle.FULLSCREEN` (по умолчанию) или `AdaptyUIIOSPresentationStyle.PAGESHEET`. ```kotlin showLineNumbers viewModelScope.launch { val view = AdaptyUI.createOnboardingView(onboarding = onboarding).getOrNull() view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET) } ``` ### Настройка открытия ссылок в онбордингах \{#customize-how-links-open-in-onboardings\} По умолчанию ссылки в онбордингах открываются во встроенном браузере. Это обеспечивает удобный пользовательский опыт: веб-страницы отображаются прямо внутри приложения, и пользователю не нужно переключаться между приложениями. Если вы хотите открывать ссылки во внешнем браузере, задайте параметру `externalUrlsPresentation` значение `AdaptyWebPresentation.EXTERNAL_BROWSER`: ```kotlin showLineNumbers viewModelScope.launch { AdaptyUI.createOnboardingView( onboarding = onboarding, externalUrlsPresentation = AdaptyWebPresentation.EXTERNAL_BROWSER // default – IN_APP_BROWSER ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ## Без Compose Multiplatform :::note `createNativeOnboardingView` входит в состав основного модуля `io.adapty:adapty-kmp`. Если ваш проект не использует Compose Multiplatform, зависимость `io.adapty:adapty-kmp-ui` не нужна. ::: Чтобы встроить онбординг без Compose Multiplatform, вызовите `createNativeOnboardingView`. Метод возвращает `AdaptyNativeOnboardingView`, который вы добавляете в свой лейаут:
Например, если пользователь нажимает кастомную кнопку — **Login** или **Allow notifications** — вызывается метод делегата `onCustomAction` с идентификатором действия из билдера. Идентификаторы задаёте вы сами, например `"allowNotifications"`.
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewOnCustomAction(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
actionId: String
) {
when (actionId) {
"openPaywall" -> {
// Показ пейвола из онбординга
// Обычно здесь нужно получить и отобразить новый пейвол
mainUiScope.launch {
// Пример: получение пейвола по ID плейсмента
// val paywallResult = Adapty.getPaywall("your_placement_id")
// paywallResult.onSuccess { paywall ->
// val paywallViewResult = AdaptyUI.createPaywallView(paywall)
// paywallViewResult.onSuccess { paywallView ->
// paywallView.present()
// }
// }
}
}
"allowNotifications" -> {
// Обработка разрешений на уведомления
}
else -> {
// Обработка других пользовательских действий
}
}
}
}
// Настройка наблюдателя
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
2. Нажмите на название группы подписок. Вы увидите свои продукты в разделе **Subscriptions**.
3. Убедитесь, что тестируемый продукт имеет статус **Ready to Submit**. Если нет, следуйте инструкциям на странице [Продукт в App Store](app-store-products).
4. Сравните ID продукта из таблицы с тем, что указан на вкладке [**Products**](https://app.adapty.io/products) в дашборде Adapty. Если ID не совпадают, скопируйте ID продукта из таблицы и [создайте продукт](create-product) с этим ID в дашборде Adapty.
## Шаг 3. Проверьте доступность продуктов \{#step-4-check-product-availability\}
1. Вернитесь в **App Store Connect** и откройте тот же раздел **Subscriptions**.
2. Нажмите на название группы подписок, чтобы просмотреть свои продукты.
3. Выберите продукт, который тестируете.
4. Прокрутите вниз до раздела **Availability** и убедитесь, что все нужные страны и регионы указаны.
## Шаг 4. Проверка цен продуктов \{#step-5-check-product-prices\}
1. Снова откройте раздел **Monetization** → **Subscriptions** в **App Store Connect**.
2. Нажмите на название группы подписок.
3. Выберите продукт, который хотите протестировать.
4. Прокрутите вниз до раздела **Subscription Pricing** и разверните раздел **Current Pricing for New Subscribers**.
5. Убедитесь, что все необходимые цены указаны.
## Шаг 5. Проверьте статус платёжного аккаунта, банковских реквизитов и налоговых форм \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. На главной странице [**App Store Connect**](https://appstoreconnect.apple.com/) нажмите **Business**.
2. Выберите название вашей компании.
3. Прокрутите вниз и убедитесь, что **Paid Apps Agreement**, **Bank Account** и **Tax forms** отображаются как **Active**.
Выполнив эти шаги, вы сможете устранить предупреждение `InvalidProductIdentifiers` и запустить продукты в сторе
## Шаг 6. Пересоздайте продукт, если он завис \{#step-6-recreate-the-product-if-its-stuck\}
Шаги 1–5 могут пройти успешно — статус `Approved`, совпадающий Bundle ID, корректный API-ключ — а SDK всё равно возвращает `1000 noProductIDsFound`. В таком случае продукт может быть завис в реестре Apple. Реестр продуктов Apple иногда входит в состояние, при котором продукт существует в интерфейсе App Store Connect, но недоступен по пути поиска StoreKit.
Удалите продукт в App Store Connect и пересоздайте его с тем же идентификатором. После пересоздания подождите до 24 часов для распространения изменений.
---
# File: cantMakePayments-kmp
---
---
title: "Исправление ошибки Code-1003 cantMakePayment в Kotlin Multiplatform SDK"
description: "Устранение ошибки проведения платежей при управлении подписками в Adapty."
---
Ошибка 1003, `cantMakePayments`, означает, что на этом устройстве нельзя совершать встроенные покупки.
Если вы столкнулись с ошибкой `cantMakePayments`, обычно это происходит по одной из следующих причин:
- Ограничения устройства: ошибка не связана с Adapty. Способы решения описаны ниже.
- Настройка Observer mode: метод `makePurchase` и Observer mode нельзя использовать одновременно. Подробнее — в соответствующем разделе ниже.
## Проблема: ограничения устройства \{#issue-device-restrictions\}
| Проблема | Решение |
|---------------------------------|-------------------------------------------------------------------------------------------------------------------|
| Ограничения Screen Time | Отключите ограничения встроенных покупок в [Screen Time](https://support.apple.com/en-us/102470) |
| Аккаунт заблокирован | Обратитесь в службу поддержки Apple для решения проблем с аккаунтом |
| Региональные ограничения | Используйте аккаунт App Store из поддерживаемого региона |
## Проблема: одновременное использование Observer mode и makePurchase \{#issue-using-both-observer-mode-and-makepurchase\}
Если вы используете `makePurchase` для обработки покупок, Observer mode не нужен. [Observer mode](observer-vs-full-mode) требуется только в том случае, если логику покупок вы реализуете самостоятельно.
Таким образом, если вы используете `makePurchase`, можно смело убрать активацию Observer mode из кода инициализации SDK.
---
# File: kmp-sdk-migration-guides
---
---
title: "Руководства по миграции Kotlin Multiplatform SDK"
description: "Руководства по миграции для версий Adapty Kotlin Multiplatform SDK."
---
На этой странице собраны все руководства по миграции для Adapty Kotlin Multiplatform SDK. Выберите версию, на которую хотите перейти, чтобы получить подробные инструкции:
- **[Миграция на v4.0 (beta)](migration-to-kmp-sdk-v4)**
- **[Миграция на v3.15](migration-to-kmp-315)**
---
# File: migration-to-kmp-sdk-v4
---
---
title: "Миграция Adapty Kotlin Multiplatform SDK на v. 4.0"
description: "Мигрируйте на Adapty Kotlin Multiplatform SDK v4.0 (beta): замените API пейволов на API флоу, совместимые как с Flow Builder, так и с Paywall Builder."
---
Adapty Kotlin Multiplatform SDK 4.0 (beta) вводит флоу и соответственно переименовывает API пейволов. Новые API работают как с новым Flow Builder, так и с существующим Paywall Builder — никаких изменений в настройках дашборда Adapty не требуется.
## Краткий справочник \{#quick-reference\}
| v3 | v4 |
|---|---|
| `Adapty.getPaywall(placementId, locale)` | `Adapty.getFlow(placementId)` |
| `Adapty.getPaywallForDefaultAudience(placementId, locale)` | `Adapty.getFlowForDefaultAudience(placementId)` |
| `Adapty.getPaywallProducts(paywall)` | `Adapty.getPaywallProducts(flow)` |
| `Adapty.logShowPaywall(paywall)` | `Adapty.logShowFlow(flow)` |
| `AdaptyPaywall` | `AdaptyFlow` |
| `AdaptyUI.createPaywallView(paywall, ...)` | `AdaptyUI.createFlowView(flow, ...)` |
| `AdaptyUI.createNativePaywallView(...)` → `AdaptyNativePaywallView` | `AdaptyUI.createNativeFlowView(...)` → `AdaptyNativeFlowView` |
| `AdaptyUIPaywallView` | `AdaptyUIFlowView` |
| `AdaptyUI.presentPaywallView(view)` / `dismissPaywallView(view)` | `AdaptyUI.presentFlowView(view)` / `dismissFlowView(view)` |
| `AdaptyUI.setPaywallsEventsObserver(observer)` | `AdaptyUI.setFlowsEventsObserver(observer)` |
| `AdaptyUI.registerPaywallEventsListener` / `unregisterPaywallEventsListener` | `AdaptyUI.registerFlowEventsListener` / `unregisterFlowEventsListener` |
| `AdaptyUIPaywallsEventsObserver` | `AdaptyUIFlowsEventsObserver` |
| `AdaptyUIPaywallPlatformView(paywall, ...)` | `AdaptyUIFlowPlatformView(flow, ...)` |
| `paywallViewDidPerformAction`, `paywallViewDidAppear` и другие колбэки `paywallView...` | `flowViewDidPerformAction`, `flowViewDidAppear` и другие колбэки `flowView...` |
| `paywallViewDidFailRendering` | `flowViewDidReceiveError` |
`AdaptyPaywallProduct` сохраняет своё название — продукты по-прежнему принадлежат флоу, и `getPaywallProducts` тоже сохраняет название, теперь принимая `AdaptyFlow`. Методы `getFlow` и `getFlowForDefaultAudience` больше не принимают параметр `locale`. API покупок и профиля (`makePurchase`, `restorePurchases`, `getProfile`, `identify`, `updateProfile`) и резервные пейволы через `setFallback` остаются без изменений. Методы онбординга по-прежнему работают, но помечены как устаревшие — см. [Устаревание Onboarding API](#onboarding-api-deprecation). Некоторые стандартные настройки поведения изменились — см. [Изменения поведения по умолчанию](#default-behavior-changes).
## Установка \{#installation\}
v4.0 — это предрелизная версия, поэтому указывайте точный номер версии: Gradle не выбирает предрелизные версии через динамические диапазоны:
```toml showLineNumbers title="libs.versions.toml"
[versions]
adapty-kmp = "4.0.0-beta.1"
[libraries]
adapty-kmp = { module = "io.adapty:adapty-kmp", version.ref = "adapty-kmp" }
adapty-kmp-ui = { module = "io.adapty:adapty-kmp-ui", version.ref = "adapty-kmp" }
```
Модуль `adapty-kmp-ui` нужен только если вы отображаете флоу и пейволы через слой Compose Multiplatform (`view.present()`). Подробная инструкция по настройке — в разделе [Установка Adapty SDK](sdk-installation-kotlin-multiplatform).
Нативные SDK Adapty обновлены до версии 4.x на обеих платформах и подтягиваются автоматически — изменений в сборке не требуется. Минимальная версия iOS остаётся **15.0**, это не изменилось в данном релизе.
## Получение флоу \{#fetching-flows\}
### getPaywall → getFlow
Возвращаемый тип изменяется с `AdaptyPaywall` на `AdaptyFlow`, а параметр `locale` удалён — при отображении флоу локаль определяется автоматически; для кастомных пейволов все локали возвращаются в `flow.remoteConfigs`:
```diff showLineNumbers
- Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en")
- .onSuccess { paywall ->
- // use the paywall
+ Adapty.getFlow("YOUR_PLACEMENT_ID")
+ .onSuccess { flow ->
+ // use the flow
}
.onError { error ->
// handle the error
}
```
`getPaywallForDefaultAudience` переименован аналогичным образом:
```diff showLineNumbers
- Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en")
+ Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID")
```
### getPaywallProducts(paywall) → getPaywallProducts(flow)
`getPaywallProducts` сохраняет своё название, но теперь принимает `AdaptyFlow`:
```diff showLineNumbers
- Adapty.getPaywallProducts(paywall)
+ Adapty.getPaywallProducts(flow)
.onSuccess { products ->
// use the products
}
```
## Модель данных \{#data-model\}
`getFlow` возвращает `AdaptyFlow` вместо `AdaptyPaywall`, и структура объекта изменилась:
| Свойство v3 `AdaptyPaywall` | Свойство v4 `AdaptyFlow` | Действие |
|---|---|---|
| `remoteConfig: AdaptyRemoteConfig?` (одиночное) | `remoteConfigs: List
### В процессе входа/регистрации \{#during-loginsignup\}
Если вы идентифицируете пользователей после запуска приложения (например, после входа в аккаунт или регистрации), используйте метод `identify`, чтобы задать их customer user ID.
- Если вы **не использовали этот customer user ID раньше**, Adapty автоматически свяжет его с текущим профилем.
- Если вы **уже использовали этот customer user ID для идентификации пользователя**, Adapty переключится на работу с профилем, связанным с этим customer user ID.
:::important
Идентификаторы пользователей должны быть уникальными для каждого пользователя. Если захардкодить значение параметра, все пользователи будут считаться одним.
:::
Всегда используйте `await` для `identify` перед вызовом других методов SDK. Параллельные вызовы приводят к ошибке `#3006 profileWasChanged` или работают с анонимным профилем. См. [Порядок вызовов в React Native SDK](react-native-sdk-call-order).
```typescript showLineNumbers
try {
await adapty.identify("YOUR_USER_ID"); // Unique for each user
// successfully identified
} catch (error) {
// handle the error
}
```
### При активации SDK \{#during-the-sdk-activation\}
Если вы знаете customer user ID ещё до активации SDK, его можно передать прямо в метод `activate` — и не вызывать `identify` отдельно.
Если же вы знаете customer user ID, но устанавливаете его только после активации, то при активации Adapty создаст новый анонимный профиль и переключится на существующий лишь после вызова `identify`.
Вы можете передать как существующий customer user ID (который вы уже использовали ранее), так и новый. Если передать новый, профиль, созданный при активации, будет автоматически привязан к этому customer user ID.
:::note
По умолчанию создание анонимных профилей не влияет на аналитические дашборды, поскольку установки считаются на основе идентификаторов устройств.
Идентификатор устройства соответствует одной установке приложения из стора и обновляется только при переустановке приложения.
Он не зависит от того, является ли установка первой или повторной, а также от того, используется ли существующий пользовательский ID.
Создание профиля (при активации SDK или выходе из системы), вход в систему или обновление приложения без его переустановки не генерируют дополнительных событий установки.
Если вы хотите считать установки на основе уникальных пользователей, а не устройств, перейдите в **App settings** и настройте [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```typescript showLineNumbers
adapty.activate("PUBLIC_SDK_KEY", {
customerUserId: "YOUR_USER_ID" // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one.
});
```
### Выход пользователей из аккаунта \{#log-users-out\}
Если в приложении есть кнопка выхода, используйте метод `logout`.
:::important
Выход из аккаунта создаёт новый анонимный профиль для пользователя.
:::
```typescript showLineNumbers
try {
await adapty.logout();
// successful logout
} catch (error) {
// handle the error
}
```
:::info
Чтобы снова войти в аккаунт, используйте метод `identify`.
:::
### Разрешите покупки без входа в систему \{#allow-purchases-without-login\}
Если пользователи могут совершать покупки как до, так и после входа в приложение, необходимо убедиться, что после входа они сохранят доступ:
1. Когда неавторизованный пользователь совершает покупку, Adapty привязывает её к анонимному ID профиля.
2. Когда пользователь входит в аккаунт, Adapty переключается на работу с идентифицированным профилем.
- Если это новый customer user ID (например, покупка была совершена до регистрации), Adapty присваивает customer user ID текущему профилю, сохраняя всю историю покупок.
- Если customer user ID уже существует (он уже привязан к профилю), после переключения профиля нужно получить актуальный уровень доступа. Для этого можно вызвать [`getProfile`](react-native-check-subscription-status) сразу после идентификации или [подписаться на обновления профиля](react-native-check-subscription-status), чтобы данные синхронизировались автоматически.
## Следующие шаги \{#next-steps\}
Поздравляем! Вы реализовали логику встроенных покупок в своём приложении! Желаем вам всего наилучшего в монетизации вашего приложения!
Чтобы получить от Adapty ещё больше, изучите эти темы:
- [**Тестирование**](troubleshooting-test-purchases): Убедитесь, что всё работает как ожидается
- [**Онбординги**](react-native-onboardings): Вовлекайте пользователей с помощью онбордингов и повышайте удержание
- [**Интеграции**](configuration): Интегрируйтесь с сервисами маркетинговой атрибуции и аналитики буквально в одну строку кода
- [**Настройка атрибутов профиля**](react-native-setting-user-attributes): Добавляйте пользовательские атрибуты к профилям и создавайте сегменты — чтобы запускать A/B-тесты или показывать разные пейволы разным пользователям
---
# File: adapty-sdk-integration-skill-react-native
---
---
title: "Интеграция Adapty в приложение React Native с помощью навыка SDK integration"
description: "Используйте навык adapty-sdk-integration для сквозной интеграции Adapty SDK в приложение React Native с помощью вашего AI-инструмента для кодирования."
---
[Скилл adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) автоматизирует интеграцию Adapty от начала до конца: настройку дашборда, установку SDK, пейвол и проверку на каждом этапе. Он автоматически определяет вашу платформу и подгружает нужную документацию Adapty на каждом шаге.
**Поддерживаемые инструменты**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Для установки выберите команду для своего инструмента. Полный список — в [README скилла](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex или любой другой инструмент** — используйте [skills CLI](https://skills.sh) (обратите внимание, что скиллы, установленные таким способом, не обновляются автоматически):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Либо клонируйте репозиторий и скопируйте `skills/adapty-sdk-integration/` в директорию скиллов вашего инструмента.
После установки запустите скилл в вашем проекте:
```
/adapty-sdk-integration
```
Скилл задаст несколько вопросов по настройке, а затем проведёт через настройку дашборда, установку SDK, пейвол и проверку.
:::important
Этот навык находится в бета-версии. Если он зависает или ведёт себя непредсказуемо, воспользуйтесь [пошаговым руководством по интеграции](adapty-cursor-react-native) — оно проведёт ваш AI-инструмент через каждый этап с нужной документацией.
:::
[Скилл adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) автоматизирует интеграцию Adapty от начала до конца: настройку дашборда, установку SDK, пейвол и проверку на каждом этапе. Он автоматически определяет вашу платформу и подгружает нужную документацию Adapty на каждом шаге.
**Поддерживаемые инструменты**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Для установки выберите команду для своего инструмента. Полный список — в [README скилла](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex или любой другой инструмент** — используйте [skills CLI](https://skills.sh) (обратите внимание, что скиллы, установленные таким способом, не обновляются автоматически):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Либо клонируйте репозиторий и скопируйте `skills/adapty-sdk-integration/` в директорию скиллов вашего инструмента.
После установки запустите скилл в вашем проекте:
```
/adapty-sdk-integration
```
Скилл задаст несколько вопросов по настройке, а затем проведёт через настройку дашборда, установку SDK, пейвол и проверку.
---
# File: adapty-cursor-react-native
---
---
title: "Интеграция Adapty в ваше React Native приложение с помощью ИИ"
description: "Пошаговое руководство по интеграции Adapty в ваше React Native приложение с использованием Cursor, Context7, ChatGPT, Claude или других ИИ-инструментов."
---
Это руководство шаг за шагом проведёт вас через интеграцию Adapty в ваше приложение на React Native с помощью AI-инструмента для написания кода — вы даёте ему нужную документацию Adapty в правильном порядке.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Прежде чем начать: настройка дашборда \{#before-you-start-dashboard-setup\}
Adapty требует предварительной настройки в дашборде — до того как вы начнёте писать код с использованием SDK. Это можно сделать с помощью интерактивного LLM-скилла или вручную через дашборд.
### Подход через skill (рекомендуется) \{#skill-approach-recommended\}
Skill Adapty CLI позволяет вашему LLM настраивать приложение, продукты, уровни доступа, пейволы и плейсменты напрямую — без необходимости открывать дашборд на каждом шаге. Нужно только [подключить сторы](integrate-payments) в дашборде.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
После добавления skill запустите `/adapty-cli` в своём агенте. Он проведёт вас через каждый шаг — включая момент, когда нужно открыть дашборд для подключения сторов.
### Подход через дашборд
Если вы предпочитаете настраивать всё вручную, вот что нужно сделать до написания кода. Ваш LLM не может самостоятельно получить значения из дашборда — вам придётся предоставить их самостоятельно.
1. **Подключите сторы**: В дашборде Adapty перейдите в **App settings → General**. Подключите App Store и Google Play, если ваше приложение поддерживает обе платформы. Это обязательное условие для работы покупок.
[Подключите сторы](integrate-payments)
2. **Скопируйте публичный SDK-ключ**: В дашборде Adapty перейдите в **App settings → General** и найдите раздел **API keys**. В коде это строка, которую вы передаёте в `adapty.activate("YOUR_PUBLIC_SDK_KEY")`.
3. **Создайте хотя бы один продукт**: В дашборде Adapty перейдите на страницу **Products**. В коде ссылаться на продукты напрямую не нужно — Adapty передаёт их через пейволы.
[Добавить продукты](quickstart-products)
4. **Создайте пейвол и плейсмент**: В дашборде Adapty создайте пейвол на странице **Paywalls**, затем привяжите его к плейсменту на странице **Placements**. В коде идентификатор плейсмента — это строка, которую вы передаёте в `adapty.getPaywall("YOUR_PLACEMENT_ID")`.
[Создать пейвол](quickstart-paywalls)
5. **Настройте уровни доступа**: в дашборде Adapty настройте каждый продукт на странице **Products**. В коде проверяйте строку `profile.accessLevels['premium']?.isActive`. Уровень доступа `premium` по умолчанию подходит большинству приложений. Если платящие пользователи получают доступ к разным функциям в зависимости от продукта (например, план `basic` и план `pro`), [создайте дополнительные уровни доступа](assigning-access-level-to-a-product) до начала разработки.
:::tip
Как только у вас есть все пять — можно писать код. Скажите LLM: «Мой публичный SDK-ключ — X, мой идентификатор плейсмента — Y», чтобы она сгенерировала правильный код инициализации и получения пейвола.
:::
### Настройте по мере готовности \{#set-up-when-ready\}
Это не обязательно для начала разработки, но пригодится по мере развития интеграции:
- **A/B-тесты**: настраиваются на странице **Placements**. Изменений в коде не требуется.
[A/B-тесты](ab-tests)
- **Дополнительные пейволы и плейсменты**: добавьте больше вызовов `getPaywall` с разными идентификаторами плейсментов.
- **Интеграции с аналитикой**: настраиваются на странице **Integrations**. Процесс настройки зависит от конкретной интеграции. См. [интеграции с аналитикой](analytics-integration) и [интеграции с атрибуцией](attribution-integration).
## Загрузите документацию Adapty в свой LLM \{#feed-adapty-docs-to-your-llm\}
### Используйте Context7 (рекомендуется) \{#use-context7-recommended\}
[Context7](https://context7.com) — это MCP-сервер, который даёт вашей LLM прямой доступ к актуальной документации Adapty. LLM автоматически находит нужные доки, исходя из вашего запроса, — никакого ручного копирования ссылок.
Context7 работает с **Cursor**, **Claude Code**, **Windsurf** и другими MCP-совместимыми инструментами. Для настройки выполните:
```
npx ctx7 setup
```
Команда определит ваш редактор и настроит сервер Context7. Для ручной настройки см. [репозиторий Context7 на GitHub](https://github.com/upstash/context7).
После настройки обращайтесь к библиотеке Adapty в своих промптах:
```
Use the adaptyteam/adapty-docs library to look up how to install the React Native SDK
```
:::warning
Несмотря на то что Context7 избавляет от необходимости вручную вставлять ссылки на документацию, порядок реализации важен. Следуйте [пошаговому руководству](#implementation-walkthrough) ниже строго по шагам, чтобы всё работало корректно.
:::
### Используйте документацию в формате обычного текста \{#use-plain-text-docs\}
Любой документ Adapty доступен в формате Markdown. Добавьте `.md` в конец URL или нажмите **Copy for LLM** под заголовком статьи. Например: [adapty-cursor-react-native.md](https://adapty.io/docs/ru/adapty-cursor-react-native.md).
Каждый шаг [пошагового руководства по интеграции](#implementation-walkthrough) ниже содержит блок «Отправьте это своему LLM» со ссылками `.md` для вставки.
Чтобы получить сразу несколько документов, смотрите [индексные файлы и подборки по платформам](#plain-text-doc-index-files) ниже.
## Пошаговое руководство по интеграции \{#implementation-walkthrough\}
Этот гайд проведёт вас через интеграцию Adapty в порядке реализации. Каждый этап включает документацию для передачи в LLM, описание ожидаемого результата и типичные проблемы.
### Планирование интеграции \{#plan-your-integration\}
Прежде чем браться за код, попросите LLM проанализировать ваш проект и составить план реализации. Если ваш AI-инструмент поддерживает режим планирования (например, Cursor или Claude Code), используйте его — тогда LLM сможет изучить структуру вашего проекта и документацию Adapty ещё до написания кода.
Укажите LLM, какой подход к покупкам вы используете — от этого зависит, какие гайды ей нужно будет применять:
- [**Adapty Paywall Builder**](adapty-paywall-builder): Вы создаёте пейволы в визуальном редакторе Adapty, а SDK отображает их автоматически.
- [**Пейволы, созданные вручную**](react-native-making-purchases): Вы строите собственный интерфейс пейвола в коде, но используете Adapty для получения продуктов и обработки покупок.
- [**Режим наблюдателя**](observer-vs-full-mode): Вы сохраняете существующую инфраструктуру покупок и используете Adapty только для аналитики и интеграций.
Не знаете, что выбрать? Прочитайте [сравнительную таблицу в руководстве по быстрому старту](react-native-quickstart-paywalls).
### Установка и настройка SDK \{#install-and-configure-the-sdk\}
Добавьте зависимость Adapty SDK через npm (или yarn) и активируйте её с помощью вашего публичного ключа SDK. Это основа — без неё ничего не работает.
У нас есть отдельные гайды по установке для проектов на Expo и bare React Native — выберите тот, что подходит для вашего случая.
**Гайды:**
- [Установка с Expo](sdk-installation-react-native-expo)
- [Установка с bare React Native](sdk-installation-react-native-pure)
:::tip[Checkpoint]
- **Ожидаемый результат:** Приложение собирается и запускается на iOS и Android. В логах Metro bundler видна запись об активации Adapty.
- **Частая ошибка:** "Public API key is missing" → убедитесь, что заменили заглушку на реальный ключ из **App settings**.
:::
### Показ пейволов и обработка покупок \{#show-paywalls-and-handle-purchases\}
Получите пейвол по идентификатору плейсмента, отобразите его и обработайте события покупок. Нужные вам гайды зависят от того, как вы обрабатываете покупки.
Тестируйте каждую покупку в песочнице по ходу работы — не откладывайте на конец. Инструкции по настройке смотрите в разделе [Тестирование покупок в песочнице](test-purchases-in-sandbox).
По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Рекомендуем этот вариант — он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильный интернет, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, зато время загрузки будет меньше независимо от качества соединения. Кеш обновляется регулярно, поэтому его безопасно использовать в рамках сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при переустановке или ручной очистке.
Adapty SDK хранит пейволы локально на двух уровнях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Для более быстрой загрузки пейволов мы также используем CDN и отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает получение актуальных версий пейволов и надёжную работу даже при слабом интернет-соединении.
| | **loadTimeoutMs** | по умолчанию: 5 сек |Это значение ограничивает таймаут для данного метода. По истечении таймаута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться по таймауту немного позже, чем указано в `loadTimeout`, поскольку операция может состоять из нескольких запросов под капотом.
Для Android: можно создать `TimeInterval` с помощью функций-расширений (например, `5.seconds`, где `.seconds` — из `import com.adapty.utils.seconds`) или `TimeInterval.seconds(5)`. Чтобы убрать ограничение, используйте `TimeInterval.INFINITE`.
| Response parameters: | Параметр | Описание | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | Объект `AdaptyFlow` с идентификаторами флоу (`id`, `variationId`), названием, плейсментом, вариантами пейвола (`paywalls`) и Remote Config (`remoteConfigs`). | ## Получение конфигурации представления \{#fetch-the-view-configuration\} :::important Убедитесь, что в билдере включён переключатель **Show on device**. Если этот параметр не включён, конфигурация представления не будет доступна для получения. ::: Если плейсмент был создан в **Flow Builder** или **Paywall Builder**, Adapty отрисовывает UI самостоятельно. Создайте представление с помощью `createFlowView`, затем [отобразите флоу или пейвол](react-native-present-paywalls). Если плейсмент — это кастомный пейвол без UI билдера, [обрабатывайте его как пейвол с Remote Config](present-remote-config-paywalls-react-native). В React Native SDK вызывайте `createFlowView` напрямую — предварительно получать конфигурацию не нужно. :::warning Результат метода `createFlowView` можно использовать только один раз. Если вам нужно использовать его повторно, вызовите метод `createFlowView` заново. Повторный вызов без пересоздания может привести к ошибке `AdaptyUIError.viewAlreadyPresented`. ::: ```typescript showLineNumbers try { const view = await createFlowView(flow); } catch (error) { // handle the error } ``` Параметры: | Параметр | Наличие | Описание | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | обязательный | Объект `AdaptyFlow` для получения контроллера нужного флоу/пейвола. | | **customTags** | необязательный | Словарь кастомных тегов и их значений. Кастомные теги служат плейсхолдерами в контенте и динамически заменяются на конкретные строки для персонализации контента во флоу/пейволе. Подробнее см. в разделе «Кастомные теги в Paywall Builder». | | **prefetchProducts** | необязательный | Включите для оптимизации времени отображения продуктов на экране. При значении `true` AdaptyUI автоматически загружает необходимые продукты. По умолчанию: `false`. | | **android.enableSafeArea** | необязательный | Только для Android (игнорируется на iOS). Передаётся как вложенный объект: `android: { enableSafeArea: true }`. При значении `true` к представлению флоу применяются отступы для безопасной области. По умолчанию `true` для модального представления (`createFlowView` + `present()`) и `false` для встраиваемого компонента `AdaptyFlowView`. Значение по умолчанию подходит для большинства случаев. | :::note Если вы используете несколько языков, узнайте, как добавить [локализацию флоу](add-paywall-locale-in-adapty-paywall-builder) и как правильно использовать коды локалей [здесь](react-native-localizations-and-locale-codes). ::: Когда у вас есть представление, [откройте флоу/пейвол](react-native-present-paywalls). ## Получение флоу или пейвола для аудитории по умолчанию для более быстрой загрузки \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} Как правило, флоу и пейволы загружаются почти мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и плейсментов, а у пользователей слабое интернет-соединение, загрузка флоу или пейвола может занять больше времени, чем хотелось бы. В таких случаях можно показывать флоу или пейвол для аудитории по умолчанию — это обеспечит плавный пользовательский опыт вместо пустого экрана. Чтобы решить эту задачу, можно использовать метод `getFlowForDefaultAudience`, который получает флоу или пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать флоу или пейвол через метод `getFlow`, как описано в разделе [Получение флоу/пейвола](#fetch-flowpaywall) выше. :::warning Почему мы рекомендуем использовать `getFlow` Метод `getFlowForDefaultAudience` имеет ряд существенных недостатков: - **Потенциальные проблемы с обратной совместимостью**: если вам нужно показывать разные пейволы для разных версий приложения (текущей и будущих), вы можете столкнуться с трудностями. Придётся либо проектировать пейволы с поддержкой текущей (устаревшей) версии, либо мириться с тем, что пользователи этой версии могут видеть нерендерящиеся пейволы. - **Потеря таргетинга**: все пользователи будут видеть один и тот же пейвол, настроенный для аудитории **All Users**, что означает отказ от персонализированного таргетинга (в том числе по странам, маркетинговой атрибуции или собственным пользовательским атрибутам). Если вы готовы принять эти недостатки ради более быстрой загрузки флоу или пейвола, используйте метод `getFlowForDefaultAudience` следующим образом. В противном случае используйте `getFlow`, описанный [выше](#fetch-flowpaywall). ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlowForDefaultAudience(id); // the requested flow/paywall } catch (error) { // handle the error } ``` | Параметр | Наличие | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — оно вернёт кешированные данные, если они есть. В этом случае пользователи могут получить не самые свежие данные, зато загрузка будет быстрее вне зависимости от качества связи. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или принудительной очистке вручную.
| ## Кастомизация ресурсов \{#customize-assets\} Чтобы кастомизировать изображения и видео в своём флоу или пейволе, используйте пользовательские ресурсы. У hero-изображений и видео есть предопределённые ID: `hero_image` и `hero_video`. В пользовательском наборе ресурсов вы обращаетесь к этим элементам по их ID и настраиваете их поведение. Для остальных изображений и видео нужно [задать пользовательский ID](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разные изображения или видео разным пользователям. - Показывать локальное превью, пока загружается основное удалённое изображение. - Показывать превью перед запуском видео. :::important Чтобы использовать эту функцию, обновите Adapty React Native SDK до версии 3.8.0 или выше. ::: Вот пример того, как можно передать кастомные ресурсы через простой словарь: ```javascript const customAssets: Recordнеобязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-paywall-locale-in-adapty-paywall-builder). Ожидается языковой код из одного или двух подтегов, разделённых дефисом (**-**). Первый подтег — язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локализации и рекомендациях по их использованию — в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера, а при ошибке возвращает кешированные данные. Мы рекомендуем именно этот вариант: он гарантирует, что пользователи всегда получают актуальные данные.
Если вы считаете, что ваши пользователи часто сталкиваются с нестабильным интернетом, рассмотрите `.returnCacheDataElseLoad` — возвращает кеш, если он есть. В этом случае данные могут быть не самыми свежими, зато загрузка будет быстрее при любом качестве соединения. Кеш обновляется регулярно, поэтому использовать его в течение сессии безопасно — это позволяет избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется между перезапусками приложения и очищается только при переустановке или вручную.
Adapty SDK хранит пейволы локально на двух уровнях: регулярно обновляемый кеш (описан выше) и [резервные пейволы](fallback-paywalls). Для быстрой загрузки используется CDN, а при его недоступности — отдельный резервный сервер. Такая система гарантирует, что вы всегда получаете актуальную версию пейволов, даже при нестабильном интернете.
| | **loadTimeoutMs** | по умолчанию: 5 сек |Ограничивает таймаут этого метода. По истечении таймаута возвращаются кешированные данные или локальный фолбэк.
Обратите внимание: в редких случаях метод может завершиться чуть позже указанного в `loadTimeout` значения, так как операция может включать несколько запросов под капотом.
Для Android: `TimeInterval` можно создать с помощью функций-расширений (например, `5.seconds`, где `.seconds` — из `import com.adapty.utils.seconds`) или `TimeInterval.seconds(5)`. Чтобы снять ограничение, используйте `TimeInterval.INFINITE`.
| ## Параметры ответа \{#response-parameters\} | Параметр | Описание | | :-------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Объект [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall) со списком ID продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение конфигурации отображения пейвола, созданного в Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Убедитесь, что в Paywall Builder включён переключатель **Show on device**. Если он не активирован, конфигурация отображения не будет доступна для получения. ::: После получения пейвола проверьте, содержит ли он `ViewConfiguration` — это означает, что пейвол был создан в Paywall Builder. Это подскажет вам, как отображать пейвол. Если `ViewConfiguration` присутствует, обработайте его как пейвол Paywall Builder; если нет, [обработайте его как пейвол Remote Config](present-remote-config-paywalls-react-native). В React Native SDK напрямую вызовите метод `createPaywallView`, не получая предварительно конфигурацию представления вручную. :::warning Результат метода `createPaywallView` можно использовать только один раз. Если он нужен повторно, вызовите метод `createPaywallView` заново. Повторный вызов без пересоздания может привести к ошибке `AdaptyUIError.viewAlreadyPresented`. ::: ```typescript showLineNumbers // for the Adapty SDK < 3.14 – import {createPaywallView} from 'react-native-adapty/dist/ui'; if (paywall.hasViewConfiguration) { try { const view = await createPaywallView(paywall); } catch (error) { // handle the error } } else { //use your custom logic } ``` Параметры: | Параметр | Обязательность | Описание | | :------------------- | :------------- | :----------------------------------------------------------- | | **paywall** | обязательный | Объект `AdaptyPaywall` для получения контроллера нужного пейвола. | | **customTags** | необязательный | Словарь пользовательских тегов и их значений. Пользовательские теги служат плейсхолдерами в содержимом пейвола и динамически заменяются конкретными строками для персонализации контента. Подробнее см. в разделе о пользовательских тегах в Paywall Builder. | | **prefetchProducts** | необязательный | Включите для оптимизации времени отображения продуктов на экране. При значении `true` AdaptyUI автоматически загрузит необходимые продукты. По умолчанию: `false`. | :::note Если вы используете несколько языков, узнайте, как добавить [локализацию Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) и как правильно использовать коды локалей [здесь](react-native-localizations-and-locale-codes). ::: Получив объект представления, [покажите пейвол](react-native-present-paywalls). ## Получите пейвол для аудитории по умолчанию, чтобы загрузить его быстрее \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Как правило, пейволы загружаются почти мгновенно, и беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и пейволов, а у пользователей слабое интернет-соединение, загрузка пейвола может занять больше времени, чем хотелось бы. В таких ситуациях имеет смысл показывать пейвол по умолчанию — это обеспечит плавный пользовательский опыт вместо полного отсутствия пейвола. Чтобы решить эту задачу, используйте метод `getPaywallForDefaultAudience`, который получает пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать пейвол через метод `getPaywall`, как описано в разделе [Получение информации о пейволе](#fetch-paywall-designed-with-paywall-builder) выше. :::warning Почему мы рекомендуем использовать `getPaywall` Метод `getPaywallForDefaultAudience` имеет ряд существенных недостатков: - **Возможные проблемы с обратной совместимостью**: если нужно показывать разные пейволы для разных версий приложения (текущей и будущих), могут возникнуть сложности. Придётся либо проектировать пейволы с поддержкой текущей (устаревшей) версии, либо смириться с тем, что у пользователей этой версии пейволы могут не отображаться. - **Потеря таргетинга**: все пользователи будут видеть один и тот же пейвол, настроенный для аудитории **All Users**, — это означает отказ от персонализированного таргетинга (в том числе по странам, маркетинговой атрибуции или собственным пользовательским атрибутам). Если вас устраивают эти ограничения ради более быстрой загрузки пейвола, используйте метод `getPaywallForDefaultAudience` следующим образом. В противном случае используйте `getPaywall`, описанный [выше](#fetch-paywall-designed-with-paywall-builder). ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywallForDefaultAudience(id, locale); // the requested paywall } catch (error) { // handle the error } ``` :::note Метод `getPaywallForDefaultAudience` доступен начиная с версии React Native SDK 2.11.2. ::: | Параметр | Наличие | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **locale** |опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается в виде языкового кода, состоящего из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию — в разделе [Локализации и коды локалей](react-native-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В таком случае пользователи могут получить не самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
| ## Настройка ресурсов \{#customize-assets\} Чтобы настроить изображения и видео на пейволе, используйте пользовательские ресурсы. У hero-изображений и видео есть предопределённые идентификаторы: `hero_image` и `hero_video`. В бандле пользовательских ресурсов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение. Для остальных изображений и видео необходимо [задать пользовательский идентификатор](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разные изображения или видео разным пользователям. - Показывать локальное превью-изображение, пока загружается основное удалённое изображение. - Показывать превью-изображение перед запуском видео. :::important Для использования этой функции обновите Adapty React Native SDK до версии 3.8.0 или выше. ::: Вот пример того, как можно передать кастомные ресурсы через простой словарь: ```javascript const customAssets: Record
## Счётчик просмотров пейвола слишком большой \{#the-paywall-view-number-is-too-big\}
**Проблема**: Количество просмотров пейвола отображается в два раза больше ожидаемого.
**Причина**: Возможно, в коде вызывается `logShowFlow` (React Native SDK v4+) / `logShowPaywall`, что дублирует счётчик просмотров, если вы используете Paywall Builder или Flow Builder. Для флоу и пейволов, созданных с помощью этих инструментов, аналитика отслеживается автоматически, поэтому использовать этот метод не нужно.
**Решение**: Убедитесь, что в коде не вызывается `logShowFlow` (React Native SDK v4+) / `logShowPaywall`, если вы используете Paywall Builder или Flow Builder.
## Другие проблемы \{#other-issues\}
**Проблема**: Вы столкнулись с другими проблемами, связанными с Paywall Builder, которые не описаны выше.
**Решение**: При необходимости обновите SDK до последней версии, воспользовавшись [гайдами по миграции](react-native-sdk-migration-guides). Многие проблемы уже исправлены в новых версиях SDK.
---
# File: react-native-quickstart-manual
---
---
title: "Включить покупки в пользовательском пейволе в React Native SDK"
description: "Интегрируйте Adapty SDK в свои пользовательские пейволы на React Native для поддержки встроенных покупок."
---
В этом гайде описано, как интегрировать Adapty в пользовательские пейволы. Сохраняйте полный контроль над реализацией пейвола, пока Adapty SDK получает продукты, обрабатывает новые покупки и восстанавливает предыдущие.
:::important
**Это руководство предназначено для разработчиков, реализующих кастомные пейволы.** Если вы хотите самый простой способ подключить покупки, используйте [Adapty Flow Builder](react-native-quickstart-paywalls). С Flow Builder вы создаёте флоу в визуальном редакторе без кода, Adapty автоматически обрабатывает всю логику покупок, а тестировать разные дизайны можно без перепубликации приложения.
:::
## Прежде чем начать \{#before-you-start\}
### Настройка продуктов \{#set-up-products\}
Чтобы подключить встроенные покупки, нужно разобраться с тремя ключевыми понятиями:
- [**Products**](product) – всё, что пользователи могут купить (подписки, расходуемые покупки, пожизненный доступ)
- [**Paywalls**](paywalls) – конфигурации, определяющие, какие продукты предлагать. В Adapty пейволы — единственный способ получить продукты, но такой подход позволяет менять продукты, цены и офферы без изменений в коде приложения.
- [**Placements**](placements) – где и когда показывать пейволы в приложении (например, `main`, `onboarding`, `settings`). Вы настраиваете пейволы для плейсментов в дашборде, а затем запрашиваете их по ID плейсмента в коде. Это упрощает запуск A/B-тестов и показ разных пейволов разным пользователям.
Убедитесь, что вы понимаете эти концепции, даже если используете собственный пейвол. По сути, это просто способ управлять продуктами, которые вы продаёте в приложении.
Чтобы реализовать собственный пейвол, нужно создать **пейвол** и добавить его в **плейсмент**. Это позволит получать продукты. Чтобы разобраться, что нужно сделать в дашборде, следуйте quickstart-гайду [здесь](quickstart).
### Управление пользователями \{#manage-users\}
Вы можете работать как с backend-аутентификацией, так и без неё.
Тем не менее Adapty SDK по-разному обрабатывает анонимных и идентифицированных пользователей. Прочитайте [гайд по быстрой идентификации](react-native-quickstart-identify), чтобы разобраться в деталях и убедиться, что вы правильно работаете с пользователями.
## Шаг 1. Получите продукты \{#step-1-get-products\}
Чтобы получить продукты для вашего кастомного пейвола, нужно:
1. Получить объект `flow`, передав ID [плейсмента](placements) в метод `getFlow`.
2. Получить массив продуктов для этого флоу с помощью метода `getPaywallProducts`.
```typescript showLineNumbers
async function loadPaywall() {
try {
const flow: AdaptyFlow = await adapty.getFlow('YOUR_PLACEMENT_ID');
const products: AdaptyPaywallProduct[] = await adapty.getPaywallProducts(flow);
// Use products to build your custom paywall UI
} catch (error) {
// Handle the error
}
}
```
## Шаг 2. Обработка покупок \{#step-2-accept-purchases\}
Когда пользователь нажимает на продукт в вашем кастомном пейволе, вызовите метод `makePurchase` с выбранным продуктом. Он обработает флоу покупки и вернёт обновлённый профиль.
```typescript showLineNumbers
async function purchaseProduct(product: AdaptyPaywallProduct) {
try {
const purchaseResult: AdaptyPurchaseResult = await adapty.makePurchase(product);
switch (purchaseResult.type) {
case 'success':
// Purchase successful, profile updated
break;
case 'user_cancelled':
// User canceled the purchase
break;
case 'pending':
// Purchase is pending (e.g., user will pay offline with cash)
break;
}
} catch (error) {
// Handle the error
}
}
```
## Шаг 3. Восстановление покупок \{#step-3-restore-purchases\}
Сторы требуют, чтобы во всех приложениях с подписками была возможность восстановить покупки.
Вызывайте метод `restorePurchases`, когда пользователь нажимает кнопку восстановления. Это синхронизирует историю покупок с Adapty и вернёт обновлённый профиль.
```typescript showLineNumbers
async function restorePurchases() {
try {
const profile: AdaptyProfile = await adapty.restorePurchases();
// Restore successful, profile updated
} catch (error) {
// Handle the error
}
}
```
## Следующие шаги \{#next-steps\}
:::tip
Есть вопросы или возникли проблемы? Загляните на наш [форум поддержки](https://adapty.featurebase.app/), где можно найти ответы на распространённые вопросы или задать свой. Наша команда и сообщество всегда готовы помочь!
:::
Ваш пейвол готов к отображению в приложении. Протестируйте покупки в [песочнице App Store](test-purchases-in-sandbox) или в [Google Play Store](testing-on-android), чтобы убедиться, что тестовая покупка через пейвол проходит успешно. Чтобы увидеть, как это работает в готовой к продакшену реализации, изучите [CustomPurchaseScreen.tsx](https://github.com/adaptyteam/AdaptySDK-React-Native/blob/master/examples/ExpoGoWebMock/src/CustomPurchaseScreen.tsx) в нашем примере приложения — там показана обработка покупок с правильной обработкой ошибок, состояниями загрузки и управлением состоянием UI.
Затем [проверьте, совершил ли пользователь покупку](react-native-check-subscription-status), чтобы решить, показывать ли пейвол или открыть доступ к платным функциям.
---
# File: fetch-paywalls-and-products-react-native
---
---
title: "Получение пейволов и продуктов для пейволов с Remote Config в React Native SDK"
description: "Получайте пейволы и продукты в Adapty React Native SDK для улучшения монетизации пользователей."
---
По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если вы считаете, что у ваших пользователей нестабильный интернет, рассмотрите использование `.returnCacheDataElseLoad`: оно возвращает кешированные данные, если они есть. В этом случае пользователи могут не получать самые свежие данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или принудительной очистке.
Adapty SDK хранит флоу и пейволы в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](react-native-use-fallback-paywalls). Также используется CDN для более быстрой загрузки флоу и пейволов, а также отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает получение последней версии флоу и надёжность работы даже при плохом интернет-соединении.
| | **loadTimeoutMs** | по умолчанию: 5 сек |Это значение ограничивает таймаут для данного метода. По истечении таймаута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeout`, так как операция может включать несколько запросов под капотом.
| :::note В v4 метод `getFlow` больше не принимает параметр `locale`. Для кастомных пейволов все доступные локали возвращаются в Remote Config флоу (`flow.remoteConfigs`) — выберите ту, которая соответствует настройкам устройства или приложения пользователя. ::: Не указывайте ID продуктов жёстко в коде! Поскольку флоу настраиваются удалённо, доступные продукты, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код обрабатывает подобные сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать именно 2 продукта. Но если позднее вы получите 3 продукта, приложение должно отобразить все 3 без каких-либо изменений в коде. Единственное, что нужно указать жёстко, — это ID плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Объект `AdaptyFlow`, содержащий плейсмент, идентификаторы (`id`, `variationId`), название, варианты пейвола (`paywalls`) и массив `remoteConfigs` (по одной записи на каждую настроенную локаль). Чтобы получить продукты для флоу, вызовите `getPaywallProducts(flow)`. | ## Получение продуктов \{#fetch-products\} Получив флоу, вы можете запросить массив продуктов, соответствующих ему: ```typescript showLineNumbers try { // ...flow const products = await adapty.getPaywallProducts(flow); // the requested products list } catch (error) { // handle the error } ``` Параметры ответа: | Parameter | Description | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Список объектов [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) с: идентификатором продукта, названием продукта, ценой, валютой, длительностью подписки и рядом других свойств. | При реализации собственного дизайна пейвола вам, скорее всего, потребуется доступ к свойствам объекта [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct). Ниже показаны наиболее часто используемые свойства, но полный список всех доступных свойств см. в документации по ссылке. | Свойство | Описание | |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Чтобы отобразить название продукта, используйте `product.localizedTitle`. Обратите внимание, что локализация основана на стране стора, выбранной пользователем, а не на языке устройства. | | **Price** | Чтобы отобразить локализованную цену, используйте `product.price?.localizedString`. Локализация основана на настройках языка устройства. Цену в виде числа можно получить через `product.price?.amount` — значение будет указано в местной валюте. Символ валюты доступен через `product.price?.currencySymbol`. | | **Subscription Period** | Чтобы отобразить период подписки (например, неделя, месяц, год и т. д.), используйте `product.subscription?.localizedSubscriptionPeriod`. Локализация основана на настройках языка устройства. Для программного получения периода подписки используйте `product.subscription?.subscriptionPeriod`. Через свойство `unit` можно узнать единицу периода: `'day'`, `'week'`, `'month'`, `'year'` или `'unknown'`. Свойство `numberOfUnits` возвращает количество единиц периода. Например, для квартальной подписки в `unit` будет `'month'`, а в `numberOfUnits` — `3`. | | **Introductory Offer** | Чтобы показать бейдж или другой индикатор наличия introductory offer, проверьте свойство `product.subscription?.offer?.phases`. Это список, который может содержать до двух фаз скидки: фазу бесплатного пробного периода и фазу вводной цены. В каждом объекте фазы доступны следующие полезные свойства:По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если вы считаете, что у ваших пользователей нестабильный интернет, рассмотрите использование `.returnCacheDataElseLoad` для возврата кэшированных данных, если они существуют. В этом случае пользователи могут не получить самые последние данные, но загрузка будет быстрее, независимо от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание, что кэш сохраняется при перезапуске приложения и очищается только при переустановке приложения или вручную.
|необязательный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается языковой код, состоящий из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Например: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](react-native-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Если вы считаете, что у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кешированные данные, если они есть. В этом случае пользователи могут не получить самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется после перезапуска приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит пейволы на двух уровнях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](react-native-use-fallback-paywalls). Для более быстрой загрузки пейволов используется CDN, а на случай его недоступности — отдельный резервный сервер. Эта система обеспечивает получение актуальных версий пейволов и надёжную работу даже при нестабильном интернет-соединении.
| | **loadTimeoutMs** | по умолчанию: 5 сек |Это значение ограничивает тайм-аут метода. По истечении тайм-аута возвращаются кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях тайм-аут метода может наступить чуть позже указанного в `loadTimeout`, поскольку операция может включать несколько запросов под капотом.
| Не задавайте идентификаторы продуктов жёстко в коде! Поскольку пейволы настраиваются удалённо, доступные продукты, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код учитывает эти сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать эти 2 продукта. Но если позже вы получите 3 продукта, приложение должно показать все 3 без каких-либо изменений в коде. Единственное, что нужно задать жёстко, — это идентификатор плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Объект [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall) с: списком идентификаторов продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение продуктов \{#fetch-products\} Получив пейвол, вы можете запросить массив продуктов, соответствующих ему: ```typescript showLineNumbers try { // ...paywall const products = await adapty.getPaywallProducts(paywall); // the requested products list } catch (error) { // handle the error } ``` Параметры ответа: | Параметр | Описание | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Список объектов [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) с идентификатором продукта, названием продукта, ценой, валютой, длительностью подписки и рядом других свойств. | При реализации собственного дизайна пейвола вам, скорее всего, понадобятся свойства объекта [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct). Ниже приведены наиболее часто используемые свойства; полный список доступных свойств смотрите в документации по ссылке. | Свойство | Описание | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Чтобы отобразить название продукта, используйте `product.localizedTitle`. Локализация основана на стране стора, выбранной пользователем, а не на локали устройства. | | **Price** | Чтобы отобразить цену в локализованном формате, используйте `product.price?.localizedString`. Локализация основана на локали устройства. Также можно получить цену как число через `product.price?.amount` — значение будет в местной валюте. Чтобы получить символ валюты, используйте `product.price?.currencySymbol`. | | **Subscription Period** | Чтобы отобразить период (например, неделя, месяц, год и т. д.), используйте `product.subscription?.localizedSubscriptionPeriod`. Локализация основана на локали устройства. Для программного получения периода подписки используйте `product.subscription?.subscriptionPeriod`. Через свойство `unit` можно узнать единицу периода: `'day'`, `'week'`, `'month'`, `'year'` или `'unknown'`. Свойство `numberOfUnits` возвращает количество единиц периода. Например, для квартальной подписки в `unit` будет `'month'`, а в `numberOfUnits` — `3`. | | **Introductory Offer** | Чтобы показать бейдж или другой индикатор наличия introductory offer, проверьте свойство `product.subscription?.offer?.phases`. Это список, который может содержать до двух фаз скидки: фаза бесплатного пробного периода и фаза вводной цены. Каждый объект фазы содержит следующие полезные свойства:опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается, что этот параметр будет языковым кодом, состоящим из одного или нескольких подтегов, разделённых символом «минус» (**-**). Первый подтег обозначает язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендуемом подходе к их использованию см. в разделе [Локализации и коды локалей](react-native-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если вы считаете, что ваши пользователи работают в условиях нестабильного интернета, рассмотрите использование `.returnCacheDataElseLoad` — оно возвращает кешированные данные, если они есть. В этом случае пользователи могут получать не самые последние данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
|Если запрос выполнен успешно, ответ содержит этот объект. Объект [AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile) предоставляет исчерпывающую информацию об уровнях доступа пользователя, подписках и разовых покупках в приложении.
Проверьте статус уровня доступа, чтобы убедиться, что у пользователя есть необходимый доступ к приложению.
| :::warning **Примечание:** если вы используете Apple StoreKit версии ниже 2.0 и Adapty SDK версии ниже 2.9.0, вам нужно указать [общий секрет Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret) вместо этого. Данный метод в настоящее время устарел согласно Apple. ::: ## Смена подписки при совершении покупки \{#change-subscription-when-making-a-purchase\} Когда пользователь выбирает новую подписку вместо продления текущей, поведение зависит от стора: - В App Store подписка обновляется автоматически в рамках группы подписок. Если пользователь покупает подписку из одной группы, уже имея активную подписку из другой, обе подписки будут активны одновременно. - В Google Play подписка не обновляется автоматически. Переключение нужно реализовать в коде приложения, как описано ниже. Чтобы заменить подписку другой в Android, вызовите метод `.makePurchase()` с дополнительным параметром: ```typescript showLineNumbers try { const purchaseResult = await adapty.makePurchase(product, params); switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; } } catch (error) { // Handle the error } ``` Дополнительный параметр запроса: | Параметр | Наличие | Описание | | :--------- | :------- | :----------------------------------------------------------- | | **params** | обязательный | объект типа [`MakePurchaseParamsInput`](https://react-native.adapty.io/types/makepurchaseparamsinput). | :::info **Версия 3.8.2+**: Структура `MakePurchaseParamsInput` была обновлена. `oldSubVendorProductId` и `prorationMode` теперь вложены в `subscriptionUpdateParams`, а `isOfferPersonalized` перемещён на верхний уровень. ```javascript makePurchase(product, { android: { subscriptionUpdateParams: { oldSubVendorProductId: 'old_product_id', prorationMode: 'charge_prorated_price' }, isOfferPersonalized: true } }); ``` ::: Подробнее о подписках и режимах замены можно прочитать в документации для разработчиков Google: - [О режимах замены](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Рекомендации Google по режимам замены](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Режим замены [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Примечание: этот метод доступен только для апгрейда подписки. Даунгрейд не поддерживается. - Режим замены [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Примечание: фактическая смена подписки произойдёт только по окончании текущего расчётного периода. ## Активация промокодов в iOS \{#redeem-offer-codes-in-ios\}Объект [`AdaptyProfile`](https://react-native.adapty.io/interfaces/adaptyprofile). Эта модель содержит информацию об уровнях доступа, подписках и разовых покупках.
Проверьте **статус уровня доступа**, чтобы определить, есть ли у пользователя доступ к приложению.
| :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: --- # File: implement-observer-mode-react-native --- --- title: "Implement Observer mode in React Native SDK" description: "Реализация режима наблюдателя в Adapty для отслеживания событий подписки пользователей в React Native SDK." --- Если у вас уже есть собственная инфраструктура для покупок и вы не готовы полностью переходить на Adapty, вы можете попробовать [Observer mode](observer-vs-full-mode). В базовом виде Observer Mode предлагает расширенную аналитику и бесшовную интеграцию с системами атрибуции и аналитики. Если это вам подходит, нужно сделать только следующее: 1. Включить его при настройке Adapty SDK, установив параметр `observerMode` в `true`. Следуйте инструкциям по настройке для [React Native](sdk-installation-reactnative). 2. [Передавать транзакции](report-transactions-observer-mode-react-native) из вашей существующей инфраструктуры покупок в Adapty. ### Настройка Observer mode \{#observer-mode-setup\} Включите Observer mode, если вы самостоятельно обрабатываете покупки и статус подписки, а Adapty используете только для отправки событий подписки и аналитики. :::important В режиме Observer mode Adapty SDK не закрывает транзакции — убедитесь, что вы обрабатываете их самостоятельно. ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { observerMode: true, // Enable observer mode }); ``` Параметры: | Параметр | Описание | | --------------------------- | ------------------------------------------------------------ | | observerMode | Булево значение, которое управляет [Observer mode](observer-vs-full-mode). Значение по умолчанию: `false`. | ## Использование пейволов Adapty в Observer Mode \{#using-adapty-paywalls-in-observer-mode\} Если вы также хотите использовать пейволы Adapty и возможности A/B-тестирования — это возможно, но в Observer mode потребует дополнительной настройки. Вот что нужно сделать помимо шагов выше: 1. Отображайте пейволы как обычно для [пейволов на базе Remote Config](present-remote-config-paywalls-react-native). 3. [Привяжите пейволы](report-transactions-observer-mode-react-native) к транзакциям покупок. --- # File: report-transactions-observer-mode-react-native --- --- title: "Отчёт о транзакциях в Observer Mode в React Native SDK" description: "Отчитывайтесь о транзакциях покупок в Adapty Observer Mode для отслеживания данных о пользователях и доходах в React Native SDK." ---Для iOS, StoreKit 1: объект [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Для iOS, StoreKit 2: объект [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Для Android: строковый идентификатор (purchase.getOrderId) покупки, где покупка является экземпляром класса [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) из библиотеки биллинга.
| | variationId | обязательный | Строковый идентификатор варианта. Его можно получить через свойство `variationId` объекта [AdaptyPaywall](https://react-native.adapty.io/interfaces/adaptypaywall). |phoneNumber
firstName
lastName
| String | | gender | Enum, допустимые значения: `female`, `male`, `other` | | birthday | Date | ### Пользовательские атрибуты \{#custom-user-attributes\} Вы можете задавать собственные атрибуты — как правило, они связаны с тем, как пользователь работает с приложением. Например, в фитнес-приложении это может быть количество тренировок в неделю, в приложении для изучения языков — уровень знаний. Атрибуты можно использовать в сегментах для создания целевых пейволов и предложений, а также в аналитике, чтобы выяснить, какие продуктовые метрики сильнее всего влияют на выручку. ```typescript showLineNumbers try { await adapty.updateProfile({ codableCustomAttributes: { key_1: 'value_1', key_2: 2, }, }); } catch (error) { // handle `AdaptyError` } ``` Чтобы удалить существующий ключ, используйте метод `.withRemoved(customAttributeForKey:)`: ```typescript showLineNumbers try { // to remove a key, pass null as its value await adapty.updateProfile({ codableCustomAttributes: { key_1: null, key_2: null, }, }); } catch (error) { // handle `AdaptyError` } ``` Иногда нужно узнать, какие пользовательские атрибуты уже были установлены. Для этого используйте поле `customAttributes` объекта `AdaptyProfile`. :::warning Имейте в виду, что значение `customAttributes` может быть устаревшим: атрибуты могут отправляться с разных устройств в любое время, поэтому данные на сервере могут измениться после последней синхронизации. ::: ### Ограничения \{#limits\} - Не более 30 пользовательских атрибутов на пользователя - Длина имени ключа — не более 30 символов. Допустимы буквенно-цифровые символы и следующие знаки: `_` `-` `.` - Значение может быть строкой или числом с плавающей точкой длиной не более 50 символов. --- # File: react-native-listen-subscription-changes --- --- title: "Проверка статуса подписки в React Native SDK" description: "Отслеживайте и управляйте статусом подписки пользователей в Adapty для повышения удержания клиентов в вашем React Native приложении." --- С Adapty отслеживать статус подписки очень просто. Вам не нужно вручную прописывать идентификаторы продуктов в коде — достаточно проверить наличие активного [уровня доступа](access-level).Объект [AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile). Как правило, для определения наличия у пользователя премиум-доступа к приложению достаточно проверить статус уровня доступа в профиле.
Метод `.getProfile` возвращает наиболее актуальный результат, поскольку всегда пытается обратиться к API. Если по какой-то причине (например, при отсутствии интернет-соединения) Adapty SDK не может получить данные с сервера, возвращаются данные из кэша. Важно учитывать, что Adapty SDK регулярно обновляет кэш `AdaptyProfile`, чтобы поддерживать информацию в актуальном состоянии.
| Метод `.getProfile()` возвращает профиль пользователя, из которого можно получить статус уровня доступа. В приложении может быть несколько уровней доступа. Например, в новостном приложении с независимыми подписками на разные разделы можно создать уровни доступа «sports» и «science». Однако в большинстве случаев достаточно одного уровня доступа — стандартного «premium». Пример проверки стандартного уровня доступа «premium»: ```typescript showLineNumbers try { const profile = await adapty.getProfile(); const isActive = profile.accessLevels?.["premium"]?.isActive; if (isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` ### Прослушивание обновлений статуса подписки \{#listening-for-subscription-status-updates\} При каждом изменении подписки пользователя Adapty генерирует событие. Чтобы получать сообщения от Adapty, выполните дополнительную настройку: ```typescript showLineNumbers // Create an "onLatestProfileLoad" event listener adapty.addEventListener('onLatestProfileLoad', profile => { // handle any changes to subscription state }); ``` Adapty также генерирует событие при запуске приложения — в этом случае передаётся кэшированный статус подписки. ### Кэш статуса подписки \{#subscription-status-cache\} Кэш, реализованный в Adapty SDK, хранит статус подписки профиля. Это означает, что даже при недоступности сервера кэшированные данные позволяют получить информацию о статусе подписки профиля. Вместе с тем прямые запросы данных из кэша невозможны. SDK периодически опрашивает сервер каждую минуту для проверки обновлений профиля. При наличии изменений — новых транзакций или других обновлений — они передаются в кэшированные данные для синхронизации с сервером. --- # File: react-native-deal-with-att --- --- title: "Работа с ATT в React Native SDK" description: "Начните работу с Adapty на React Native для упрощения настройки подписок и управления ими." --- Если ваше приложение использует фреймворк AppTrackingTransparency и отображает пользователю запрос на авторизацию отслеживания, необходимо передать [статус авторизации](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) в Adapty. ```typescript showLineNumbers try { await adapty.updateProfile({ // you can also pass a string value (validated via tsc) if you prefer appTrackingTransparencyStatus: AppTrackingTransparencyStatus.Authorized, }); } catch (error) { // handle `AdaptyError` } ``` :::warning Настоятельно рекомендуем передавать это значение как можно раньше при его изменении — только в этом случае данные будут своевременно отправлены в настроенные вами интеграции. ::: --- # File: kids-mode-react-native --- --- title: "Режим для детей в React Native SDK" description: "Легко включите режим для детей, чтобы соответствовать политикам Apple и Google. IDFA, GAID и рекламные данные не собираются в React Native SDK." --- Если ваше приложение на React Native предназначено для детей, вы должны соблюдать политики [Apple](https://developer.apple.com/kids/) и [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Если вы используете Adapty SDK, несколько простых шагов помогут настроить его в соответствии с этими политиками и пройти проверку в сторах. :::important На iOS Kids Mode включается через трейт Swift Package `KidsMode`, который исключает из сборки весь код, связанный с IDFA, AdSupport и AppTrackingTransparency. Для этого требуется SDK v4 (который устанавливает нативный iOS SDK через Swift Package Manager) и **Xcode 26** или новее. См. раздел [Изменения в iOS Podfile](#updates-in-your-ios-podfile) ниже. ::: ## Что нужно настроить? \{#whats-required\} Вам нужно настроить SDK, чтобы отключить сбор следующих данных: - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS) - [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android) - [IP-адрес](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) Кроме того, рекомендуем осторожно обращаться с customer user ID. Идентификатор в формате `опциональный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильный интернет, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут получить не самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется после перезапуска приложения и очищается только при его переустановке или принудительной очистке вручную.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные онбординги. Для более быстрой загрузки онбордингов используется CDN, а на случай его недоступности — отдельный резервный сервер. Такая система гарантирует, что вы всегда получаете актуальную версию онбордингов, сохраняя надёжность даже при слабом интернет-соединении.
| | **loadTimeoutMs** | по умолчанию: 5 сек |Это значение ограничивает таймаут метода. Если таймаут истекает, возвращаются кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться чуть позже указанного в `loadTimeout` значения, поскольку операция может включать несколько внутренних запросов.
| Параметры ответа: | Параметр | Описание | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Объект [`AdaptyOnboarding`](https://react-native.adapty.io/interfaces/adaptyonboarding) с: идентификатором и конфигурацией онбординга, Remote Config и рядом других свойств. | ## Ускорьте получение онбординга с помощью онбординга для аудитории по умолчанию \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Как правило, онбординги загружаются почти мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и онбордингов, а у пользователей слабое интернет-соединение, загрузка онбординга может занять больше времени, чем хотелось бы. В таких случаях имеет смысл показывать онбординг по умолчанию — чтобы пользователь видел хоть что-то, а не пустой экран. Чтобы решить эту проблему, воспользуйтесь методом `getOnboardingForDefaultAudience`, который получает онбординг указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать онбординг с помощью метода `getOnboarding`, как описано в разделе [Получение онбординга](#fetch-onboarding) выше. :::warning Используйте `getOnboarding` вместо `getOnboardingForDefaultAudience`, поскольку последний имеет существенные ограничения: - **Проблемы совместимости**: Может вызывать сложности при поддержке нескольких версий приложения — придётся либо проектировать с учётом обратной совместимости, либо мириться с тем, что старые версии могут отображать контент некорректно. - **Без персонализации**: Показывает контент только для аудитории «All Users», без таргетинга по стране, атрибуции или пользовательским атрибутам. Если для вашего сценария скорость загрузки важнее этих недостатков, используйте `getOnboardingForDefaultAudience`, как показано ниже. В противном случае используйте `getOnboarding`, как описано [выше](#fetch-onboarding). ::: ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const onboarding = await adapty.getOnboardingForDefaultAudience(placementId, locale); // запрошенный онбординг } catch (error) { // обработка ошибки } ``` Параметры: | Параметр | Наличие | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **locale** |опциональный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Например: `en` — английский язык, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию — в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и в случае сбоя возвращает кэшированные данные. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — этот режим возвращает кэшированные данные, если они есть. В таком сценарии пользователи могут получить не самые последние данные, но загрузка будет быстрее независимо от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кэш, описанный выше, и резервные онбординги. Для более быстрой загрузки мы также используем CDN и отдельный резервный сервер на случай недоступности CDN. Эта система гарантирует, что вы всегда получаете актуальную версию онбордингов, сохраняя надёжность даже при нестабильном интернете.
| --- # File: react-native-present-onboardings --- --- title: "Отображение онбордингов в React Native SDK" description: "Узнайте, как отображать онбординги на React Native для повышения конверсии и дохода." --- :::warning **Онбординги устарели в SDK v4 и будут удалены в одном из следующих релизов.** Они больше не получают исправлений и улучшений. Используйте [флоу](react-native-get-pb-paywalls) вместо них: в отличие от онбордингов, которые работают внутри WebView, флоу рендерятся нативно на устройстве — это даёт более плавные анимации, единый нативный стиль, быструю загрузку и отсутствие зависимости от WebView. Смотрите [Получение флоу и пейволов](react-native-get-pb-paywalls) и [Отображение флоу и пейволов](react-native-present-paywalls), чтобы начать работу. ::: Если вы настроили онбординг с помощью билдера, вам не нужно беспокоиться о его отрисовке в коде мобильного приложения для показа пользователю. Такой онбординг содержит и то, что должно отображаться, и то, как это должно выглядеть. Перед началом убедитесь, что: 1. Вы установили [Adapty React Native SDK](sdk-installation-reactnative) версии 3.8.0 или новее. 2. Вы [создали онбординг](create-onboarding). 3. Вы добавили онбординг в [плейсмент](placements). Adapty React Native SDK предоставляет два способа показа онбордингов: - **React-компонент**: встроенный компонент позволяет интегрировать его в архитектуру приложения и систему навигации. - **Модальное представление** ## React-компонент \{#react-component\} Чтобы встроить онбординг в существующее дерево компонентов, используйте компонент `AdaptyOnboardingView` напрямую в иерархии React Native-компонентов. Встроенный компонент позволяет интегрировать его в архитектуру и навигационную систему приложения. :::note На Android рекомендуем выполнить дополнительную настройку `AdaptyOnboardingView`, чтобы избежать визуального артефакта при рендеринге. См. [Системный UI перекрывает контент онбординга на Android](#system-ui-overlaps-onboarding-content-on-android). :::
Затем этот ID можно использовать в коде и обрабатывать его как пользовательское действие. Например, если пользователь нажимает кастомную кнопку — **Login** или **Allow notifications** — обработчик события сработает с параметром `actionId`, соответствующим **Action ID** из билдера. Вы можете задавать собственные ID, например `"allowNotifications"`.
:::important
Обратите внимание, что вам нужно самостоятельно обработать ситуацию, когда пользователь закрывает онбординг. Например, необходимо прекратить его отображение.
:::
2. Нажмите на название группы подписок. Вы увидите свои продукты в разделе **Subscriptions**.
3. Убедитесь, что тестируемый продукт отмечен как **Ready to Submit**.
4. Сравните ID продукта из таблицы с тем, что указан во вкладке [**Products**](https://app.adapty.io/products) дашборда Adapty. Если ID не совпадают, скопируйте ID продукта из таблицы и [создайте продукт](create-product) с этим ID в дашборде Adapty.
## Шаг 3. Проверьте доступность продукта \{#step-4-check-product-availability\}
1. Вернитесь в **App Store Connect** и откройте раздел **Subscriptions**.
2. Нажмите на название группы подписок, чтобы просмотреть ваши продукты.
3. Выберите продукт, который хотите протестировать.
4. Прокрутите до раздела **Availability** и убедитесь, что в нём перечислены все необходимые страны и регионы.
## Шаг 4. Проверьте цены продуктов \{#step-5-check-product-prices\}
1. Снова откройте раздел **Monetization** → **Subscriptions** в **App Store Connect**.
2. Нажмите на название группы подписок.
3. Выберите продукт, который хотите протестировать.
4. Прокрутите вниз до раздела **Subscription Pricing** и раскройте секцию **Current Pricing for New Subscribers**.
5. Убедитесь, что все необходимые цены указаны.
## Шаг 5. Убедитесь, что статус приложения, банковский счёт и налоговые формы активны \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. На главной странице [**App Store Connect**](https://appstoreconnect.apple.com/) нажмите **Business**.
2. Выберите название своей компании.
3. Прокрутите вниз и убедитесь, что ваши **Paid Apps Agreement**, **Bank Account** и **Tax forms** отображаются как **Active**.
Выполнив эти шаги, вы сможете устранить предупреждение `InvalidProductIdentifiers` и запустить продукты в сторе.
## Шаг 6. Пересоздайте продукт, если он завис \{#step-6-recreate-the-product-if-its-stuck\}
Шаги 1–5 могут пройти успешно — статус `Approved`, совпадающий Bundle ID, рабочий API-ключ — но SDK всё равно возвращает `1000 noProductIDsFound`. В таком случае продукт, возможно, завис в реестре Apple. Реестр продуктов Apple иногда переходит в состояние, при котором продукт существует в интерфейсе App Store Connect, но недоступен через путь поиска StoreKit.
Удалите продукт в App Store Connect и пересоздайте его с тем же идентификатором. После пересоздания подождите до 24 часов, пока изменения распространятся.
---
# File: cantMakePayments-react-native
---
---
title: "Исправление ошибки Code-1003 cantMakePayment в React Native SDK"
description: "Решение ошибки при совершении покупок при управлении подписками в Adapty."
---
Ошибка 1003, `cantMakePayments`, означает, что на этом устройстве нельзя совершать встроенные покупки.
Если вы столкнулись с ошибкой `cantMakePayments`, обычно это происходит по одной из следующих причин:
- Ограничения устройства: ошибка не связана с Adapty. Способы решения описаны ниже.
- Настройка Observer mode: метод `makePurchase` и Observer mode нельзя использовать одновременно. Подробнее — в соответствующем разделе ниже.
## Проблема: ограничения устройства \{#issue-device-restrictions\}
| Проблема | Решение |
|---------------------------------|-------------------------------------------------------------------------------------------------------------------|
| Ограничения Screen Time | Отключите ограничения встроенных покупок в [Screen Time](https://support.apple.com/en-us/102470) |
| Аккаунт заблокирован | Обратитесь в службу поддержки Apple для решения проблем с аккаунтом |
| Региональные ограничения | Используйте аккаунт App Store из поддерживаемого региона |
## Проблема: одновременное использование Observer mode и makePurchase \{#issue-using-both-observer-mode-and-makepurchase\}
Если вы используете `makePurchase` для обработки покупок, Observer mode не нужен. [Observer mode](observer-vs-full-mode) требуется только в том случае, если логику покупок вы реализуете самостоятельно.
Таким образом, если вы используете `makePurchase`, можно смело убрать активацию Observer mode из кода инициализации SDK.
---
# File: migration-to-react-native-sdk-v4
---
---
title: "Миграция Adapty React Native SDK на v. 4.0"
description: "Перейдите на Adapty React Native SDK v4.0 (beta): замените paywall API на flow API, совместимые как с Flow Builder, так и с Paywall Builder."
---
Adapty React Native SDK 4.0 (beta) вводит флоу и переименовывает paywall API соответствующим образом. Новые API работают как с новым Flow Builder, так и с существующим Paywall Builder — никаких изменений в настройках дашборда Adapty не требуется.
## Краткий справочник \{#quick-reference\}
| v3 | v4 |
|---|---|
| `adapty.getPaywall(placementId, locale?, params?)` | `adapty.getFlow(placementId, params?)` |
| `adapty.getPaywallForDefaultAudience(placementId, locale?, params?)` | `adapty.getFlowForDefaultAudience(placementId, params?)` |
| `adapty.getPaywallProducts(paywall)` | `adapty.getPaywallProducts(flow)` |
| `adapty.logShowPaywall(paywall)` | `adapty.logShowFlow(flow)` |
| `AdaptyPaywall` (тип) | `AdaptyFlow` |
| `createPaywallView(paywall)` | `createFlowView(flow)` |
| `AdaptyPaywallView` (компонент) | `AdaptyFlowView` |
| `EventHandlers` (тип) | `FlowEventHandlers` |
| `onPaywallShown` | `onAppeared` |
| `onPaywallClosed` | `onDisappeared` |
| `onRenderingFailed` | `onError` |
`AdaptyPaywallProduct` сохраняет своё название — продукты по-прежнему принадлежат флоу, а `getPaywallProducts` теперь принимает `AdaptyFlow`. Методы `getFlow` и `getFlowForDefaultAudience` больше не принимают параметр `locale`. Методы представления `present`, `dismiss`, `setEventHandlers` и `showDialog`, а также обработчики событий `onCloseButtonPress`, `onUrlPress`, `onCustomAction`, `onProductSelected`, `onPurchaseStarted`, `onPurchaseCompleted`, `onPurchaseFailed`, `onRestoreStarted`, `onRestoreCompleted`, `onRestoreFailed`, `onLoadingProductsFailed`, `onWebPaymentNavigationFinished` и `onAndroidSystemBack` сохраняют те же названия, что и в v3. Некоторые стандартные поведения изменились — см. [Изменения стандартного поведения](#default-behavior-changes).
## Минимальная версия iOS \{#minimum-ios-version\}
Adapty React Native SDK 4.0 повышает минимальную версию iOS с 13.0 до **iOS 15.0**. Перед обновлением установите значение deployment target не ниже 15.0.
## Установка \{#installation\}
### Обновите пакет \{#update-the-package\}
v4.0 — это предварительный релиз, поэтому укажите точную версию — npm не выбирает предварительные версии через диапазоны с `^` или `~`:
```bash showLineNumbers
npm install react-native-adapty@4.0.0
# or
yarn add react-native-adapty@4.0.0
```
### iOS: нативные SDK теперь подключаются через Swift Package Manager \{#ios-native-sdks-now-come-through-swift-package-manager\}
[Репозиторий спецификаций CocoaPods переходит в режим только для чтения в декабре 2026 года](https://blog.cocoapods.org/CocoaPods-Specs-Repo/), поэтому начиная с v4 нативные SDK `Adapty`, `AdaptyUI` и `AdaptyPlugin` **больше не подключаются как под-зависимости CocoaPods** — podspec подтягивает их через **Swift Package Manager** (с помощью хелпера `spm_dependency`). Это требует двух вещей:
- **React Native 0.75 или новее** — нужна для вспомогательного подспека `spm_dependency`. На более старой версии `pod install` завершится с явной ошибкой; сначала обновите React Native или оставайтесь на `react-native-adapty` 3.x.
- **Динамические фреймворки** — зависимости SPM требуют динамической компоновки. Способ её включения отличается для Expo и обычного React Native.
#### Expo
Добавьте конфиг-плагин [`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/) и задайте динамическую компоновку iOS-фреймворков в `app.json` (или `app.config.js`):
```json showLineNumbers title="app.json"
{
"expo": {
"plugins": [
[
"expo-build-properties",
{
"ios": {
"useFrameworks": "dynamic"
}
}
]
]
}
}
```
Затем установите плагин и пересоздайте нативный проект:
```bash showLineNumbers
npx expo install expo-build-properties
npx expo prebuild --clean
```
#### Bare React Native
Добавьте динамические фреймворки в iOS-таргет, затем переустановите поды:
```ruby showLineNumbers title="ios/Podfile"
use_frameworks! :linkage => :dynamic
```
```bash showLineNumbers
cd ios && pod install --repo-update
```
Если ранее вы подключали `Adapty`, `AdaptyUI` или `AdaptyPlugin` как зависимости CocoaPods, сначала удалите все явные строки `pod 'Adapty'`, `pod 'AdaptyUI'` или `pod 'AdaptyPlugin'` из вашего `Podfile`.
:::warning
Переход со статической компоновки по умолчанию на динамические фреймворки может конфликтовать с библиотеками, которые ещё не поддерживают модульные заголовки, и несовместим с Flipper. Если возникнут ошибки сборки, ознакомьтесь с этим [материалом об интеграции Swift Package Manager с библиотеками React Native](https://www.callstack.com/blog/integrating-swift-package-manager-with-react-native-libraries).
:::
Полная инструкция по установке — в разделе [Установка Adapty SDK](sdk-installation-reactnative).
## Получение флоу \{#fetching-flows\}
### getPaywall → getFlow
Тип возвращаемого значения изменился с `AdaptyPaywall` на `AdaptyFlow`, а параметр `locale` убран — при рендеринге флоу локаль определяется автоматически; для кастомных пейволов все локали возвращаются в `flow.remoteConfigs`:
```diff showLineNumbers
- const paywall = await adapty.getPaywall('YOUR_PLACEMENT_ID', 'en');
+ const flow = await adapty.getFlow('YOUR_PLACEMENT_ID');
```
`getPaywallForDefaultAudience` переименован аналогично:
```diff showLineNumbers
- const paywall = await adapty.getPaywallForDefaultAudience('YOUR_PLACEMENT_ID', 'en');
+ const flow = await adapty.getFlowForDefaultAudience('YOUR_PLACEMENT_ID');
```
### getPaywallProducts(paywall) → getPaywallProducts(flow)
`getPaywallProducts` сохраняет своё название, но теперь принимает `AdaptyFlow`:
```diff showLineNumbers
- const products = await adapty.getPaywallProducts(paywall);
+ const products = await adapty.getPaywallProducts(flow);
```
## Модель данных \{#data-model\}
`getFlow` возвращает `AdaptyFlow` вместо `AdaptyPaywall`, и структура объекта изменилась:
| поле v3 `AdaptyPaywall` | поле v4 `AdaptyFlow` | Действие |
|---|---|---|
| `remoteConfig?` (одно) | `remoteConfigs?: AdaptyRemoteConfig[]` (массив) | Флоу содержит один Remote Config на каждый настроенный язык. Читайте тот, который соответствует пользователю: `flow.remoteConfigs?.find((c) => c.lang === 'en')`. |
| `products` | `flow.paywalls[i].productIdentifiers` | Идентификаторы продуктов теперь хранятся в каждом варианте флоу, а не в самом флоу. |
| `webPurchaseUrl?` | `flow.paywalls[i].webPurchaseUrl` | Перенесено из флоу в каждый вариант пейвола. |
| `version?: number` | `flowVersionId?: string` | Переименовано, тип изменён с `number` на `string`. |
| `hasViewConfiguration` | удалено | Удалите все проверки `hasViewConfiguration` из кода. |
| `requestLocale` | удалено | Локаль больше не является частью модели. |
| _(новое)_ | `paywalls: AdaptyFlowPaywall[]` | Каждый элемент — один вариант пейвола во флоу. |
| _(новое)_ | `responseCreatedAt: number` | Временная метка ответа сервера в миллисекундах. |
Product identifiers moved from the flow to each variation:
```diff showLineNumbers
- const ids = paywall.products;
+ const ids = flow.paywalls[0].productIdentifiers;
```
## Методы веб-пейвола \{#web-paywall-methods\}
`openWebPaywall` и `createWebPaywallUrl` сохраняют свои названия, но первым аргументом теперь передаётся `AdaptyFlowPaywall` (вариант флоу) вместо `AdaptyPaywall`. По-прежнему можно передать `AdaptyPaywallProduct`.
```diff showLineNumbers
const flow = await adapty.getFlow('YOUR_PLACEMENT_ID');
- await adapty.openWebPaywall(paywall);
+ await adapty.openWebPaywall(flow.paywalls[0]);
```
## Отслеживание просмотров флоу \{#tracking-flow-views\}
### logShowPaywall → logShowFlow
`logShowPaywall` переименован в `logShowFlow` и теперь принимает `AdaptyFlow`. Событие по-прежнему логируется для той же вариации, так что существующие метрики воронки и A/B-тестов продолжат работать без изменений в дашборде.
```diff showLineNumbers
- await adapty.logShowPaywall(paywall);
+ await adapty.logShowFlow(flow);
```
Как и в v3, вызывать этот метод при отображении флоу или пейволов, отрисованных с помощью [Flow Builder](adapty-flow-builder) или [Paywall Builder](adapty-paywall-builder), не нужно — Adapty отслеживает такие просмотры автоматически.
## Отображение флоу \{#displaying-flows\}
### createPaywallView → createFlowView
Переименуйте фабричную функцию и передайте `AdaptyFlow`. Методы возвращаемого контроллера (`present`, `dismiss`, `setEventHandlers`, `showDialog`) остаются без изменений:
```diff showLineNumbers
- import { createPaywallView } from 'react-native-adapty';
+ import { createFlowView } from 'react-native-adapty';
- const view = await createPaywallView(paywall);
+ const view = await createFlowView(flow);
await view.present();
```
### AdaptyPaywallView → AdaptyFlowView
Если вы используете React-компонент, переименуйте его и передайте проп `flow`:
```diff showLineNumbers
- import { AdaptyPaywallView } from 'react-native-adapty';
+ import { AdaptyFlowView } from 'react-native-adapty';
- ```diff showLineNumbers - subscriptionDetails?: AdaptySubscriptionDetails; + subscription?: AdaptySubscriptionDetails; ``` 2. [AdaptySubscriptionDetails](https://react-native.adapty.io/interfaces/adaptysubscriptiondetails): - `promotionalOffer` удалён. Теперь promotional offer передаётся в свойстве `offer` только если он доступен. В этом случае `offer?.identifier?.type` будет равен `'promotional'`. - `introductoryOfferEligibility` удалён (офферы возвращаются только если пользователь имеет право на них). - `offerId` удалён. ID оффера теперь хранится в `AdaptySubscriptionOffer.identifier`. - `offerTags` перемещён в `AdaptySubscriptionOffer.android`.
```diff showLineNumbers - introductoryOffers?: AdaptyDiscountPhase[]; + offer?: AdaptySubscriptionOffer; ios?: { - promotionalOffer?: AdaptyDiscountPhase; subscriptionGroupIdentifier?: string; }; android?: { - offerId?: string; basePlanId: string; - introductoryOfferEligibility: OfferEligibility; - offerTags?: string[]; renewalType?: 'prepaid' | 'autorenewable'; }; } ``` 3. [AdaptyDiscountPhase](https://react-native.adapty.io/interfaces/adaptydiscountphase): - Поле `identifier` удалено из модели `AdaptyDiscountPhase`. Идентификатор оффера теперь хранится в `AdaptySubscriptionOffer.identifier`.
```diff showLineNumbers - ios?: { - readonly identifier?: string; - }; ``` ### Удалённые модели \{#remove-models\} 1. `AttributionSource`: - Вместо него теперь используется строка там, где ранее применялся `AttributionSource`. 2. `OfferEligibility`: - Эта модель удалена, так как больше не нужна. Теперь оффер возвращается только если пользователь имеет право на его получение. ## Удаление метода `getProductsIntroductoryOfferEligibility` \{#remove-getproductsintroductoryoffereligibility-method\} До Adapty SDK 3.3.1 объекты продуктов всегда включали офферы, даже если пользователь не имел права на их получение. Это требовало ручной проверки права на получение оффера перед его использованием. Начиная с версии 3.3.1, объект продукта включает офферы только если пользователь имеет на них право. Это упрощает процесс: если оффер присутствует, можно считать, что пользователь имеет право на его получение. ## Обновление процесса покупки \{#update-making-purchase\} В более ранних версиях отменённые и ожидающие покупки считались ошибками и возвращали коды `2: 'paymentCancelled'` и `25: 'pendingPurchase'` соответственно. Начиная с версии 3.3.1, отменённые и ожидающие покупки считаются успешными результатами и должны обрабатываться соответствующим образом: ```typescript showLineNumbers try { const purchaseResult = await adapty.makePurchase(product); switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; } } catch (error) { // Handle the error } ``` ## Обновление отображения пейволов Paywall Builder \{#update-paywall-builder-paywall-presentation\} Актуальные примеры смотрите в документации [Отображение новых пейволов Paywall Builder в React Native](react-native-present-paywalls). ```diff showLineNumbers - import { createPaywallView } from '@adapty/react-native-ui'; + import { createPaywallView } from 'react-native-adapty/dist/ui'; const view = await createPaywallView(paywall); view.registerEventHandlers(); // handle close press, etc try { await view.present(); } catch (error) { // handle the error } ``` ## Обновление реализации таймеров, определяемых разработчиком \{#update-developer-defined-timer-implementation\} Переименуйте параметр `timerInfo` в `customTimers`: ```diff showLineNumbers - let timerInfo = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } + let customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } //and then you can pass it to createPaywallView as follows: - view = await createPaywallView(paywall, { timerInfo }) + view = await createPaywallView(paywall, { customTimers }) ``` ## Изменение событий покупки в Paywall Builder \{#modify-paywall-builder-purchase-events\} Раньше: - Отменённые покупки вызывали коллбэк `onPurchaseCancelled`. - Ожидающие покупки возвращали код ошибки `25: 'pendingPurchase'`. Теперь: - Оба случая обрабатываются коллбэком `onPurchaseCompleted`. #### Шаги для миграции: \{#steps-to-migrate\} 1. Удалите коллбэк `onPurchaseCancelled`. 2. Удалите обработку кода ошибки `25: 'pendingPurchase'`. 3. Обновите коллбэк `onPurchaseCompleted`: ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.registerEventHandlers({ // ... other optional callbacks onPurchaseCompleted(purchaseResult, product) { switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; // highlight-start case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; // highlight-end } // highlight-start return purchaseResult.type !== 'user_cancelled'; // highlight-end }, }); ``` ## Обновление событий кастомных действий в Paywall Builder \{#modify-paywall-builder-custom-action-events\} Удалённые коллбэки: - `onAction` - `onCustomEvent` Добавленный коллбэк: - Новый коллбэк `onCustomAction(actionId)`. Используйте его для кастомных действий. ## Изменение коллбэка `onProductSelected` \{#modify-onproductselected-callback\} Ранее `onProductSelected` принимал объект `product`. Теперь требуется `productId` в виде строки. ## Удаление параметров сторонних интеграций из метода `updateProfile` \{#remove-third-party-integration-parameters-from-updateprofile-method\} Идентификаторы сторонних интеграций теперь задаются с помощью метода `setIntegrationIdentifier`. Метод `updateProfile` больше не принимает их. ## Обновление конфигурации SDK сторонних интеграций \{#update-third-party-integration-sdk-configuration\} Чтобы интеграции корректно работали с Adapty React Native SDK 3.3.1 и выше, обновите конфигурации SDK для следующих интеграций согласно разделам ниже. Кроме того, если вы использовали `AttributionSource` для получения идентификатора атрибуции, измените код так, чтобы передавать нужный идентификатор в виде строки. ### Adjust Обновите код вашего мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Настройка SDK для интеграции с Adjust](adjust#connect-your-app-to-adjust). ```diff showLineNumbers import { Adjust, AdjustConfig } from "react-native-adjust"; import { adapty } from "react-native-adapty"; var adjustConfig = new AdjustConfig(appToken, environment); // Before submiting Adjust config... adjustConfig.setAttributionCallbackListener(attribution => { // Make sure Adapty SDK is activated at this point // You may want to lock this thread awaiting of `activate` adapty.updateAttribution(attribution, "adjust"); }); // ... Adjust.create(adjustConfig); + Adjust.getAdid((adid) => { + if (adid) + adapty.setIntegrationIdentifier("adjust_device_id", adid); + }); ``` ### AirBridge \{#airbridge\} Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Конфигурация SDK для интеграции AirBridge](airbridge#connect-your-app-to-airbridge). ```diff showLineNumbers import Airbridge from 'airbridge-react-native-sdk'; import { adapty } from 'react-native-adapty'; try { const deviceId = await Airbridge.state.deviceUUID(); - await adapty.updateProfile({ - airbridgeDeviceId: deviceId, - }); + await adapty.setIntegrationIdentifier("airbridge_device_id", deviceId); } catch (error) { // handle `AdaptyError` } ``` ### Amplitude \{#amplitude\} Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Конфигурация SDK для интеграции Amplitude](amplitude#sdk-configuration). ```diff showLineNumbers import { adapty } from 'react-native-adapty'; try { - await adapty.updateProfile({ - amplitudeDeviceId: deviceId, - amplitudeUserId: userId, - }); + await adapty.setIntegrationIdentifier("amplitude_device_id", deviceId); + await adapty.setIntegrationIdentifier("amplitude_user_id", userId); } catch (error) { // handle `AdaptyError` } ``` ### AppMetrica Обновите код своего мобильного приложения, как показано ниже. Полный пример кода можно найти в разделе [Настройка SDK для интеграции с AppMetrica](appmetrica#sdk-configuration). ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import AppMetrica, { DEVICE_ID_KEY, StartupParams, StartupParamsReason } from '@appmetrica/react-native-analytics'; // ... const startupParamsCallback = async ( params?: StartupParams, reason?: StartupParamsReason ) => { const deviceId = params?.deviceId if (deviceId) { try { - await adapty.updateProfile({ - appmetricaProfileId: 'YOUR_ADAPTY_CUSTOMER_USER_ID', - appmetricaDeviceId: deviceId, - }); + await adapty.setIntegrationIdentifier("appmetrica_profile_id", 'YOUR_ADAPTY_CUSTOMER_USER_ID'); + await adapty.setIntegrationIdentifier("appmetrica_device_id", deviceId); } catch (error) { // handle `AdaptyError` } } } AppMetrica.requestStartupParams(startupParamsCallback, [DEVICE_ID_KEY]) ``` ### AppsFlyer Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Настройка SDK для интеграции с AppsFlyer](appsflyer#connect-your-app-to-appsflyer). ```diff showLineNumbers import { adapty, AttributionSource } from 'react-native-adapty'; import appsFlyer from 'react-native-appsflyer'; appsFlyer.onInstallConversionData(installData => { try { - const networkUserId = appsFlyer.getAppsFlyerUID(); - adapty.updateAttribution(installData, AttributionSource.AppsFlyer, networkUserId); + const uid = appsFlyer.getAppsFlyerUID(); + adapty.setIntegrationIdentifier("appsflyer_id", uid); + adapty.updateAttribution(installData, "appsflyer"); } catch (error) { // handle the error } }); // ... appsFlyer.initSdk(/*...*/); ``` ### Branch \{#branch\} Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Конфигурация SDK для интеграции Branch](branch#connect-your-app-to-branch). ```diff showLineNumbers import { adapty, AttributionSource } from 'react-native-adapty'; import branch from 'react-native-branch'; branch.subscribe({ enComplete: ({ params, }) => { - adapty.updateAttribution(params, AttributionSource.Branch); + adapty.updateAttribution(params, "branch"); }, }); ``` ### Facebook Ads Обновите код вашего мобильного приложения, как показано ниже. Полный пример кода можно найти в разделе [Настройка SDK для интеграции с Facebook Ads](facebook-ads#connect-your-app-to-facebook-ads). ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import { AppEventsLogger } from 'react-native-fbsdk-next'; try { const anonymousId = await AppEventsLogger.getAnonymousID(); - await adapty.updateProfile({ - facebookAnonymousId: anonymousId, - }); + await adapty.setIntegrationIdentifier("facebook_anonymous_id", anonymousId); } catch (error) { // handle `AdaptyError` } ``` ### Firebase и Google Analytics \{#firebase-and-google-analytics\} Обновите код мобильного приложения, как показано ниже. Полный пример кода можно найти в разделе [настройка SDK для интеграции с Firebase и Google Analytics](firebase-and-google-analytics). ```diff showLineNumbers import analytics from '@react-native-firebase/analytics'; import { adapty } from 'react-native-adapty'; try { const appInstanceId = await analytics().getAppInstanceId(); - await adapty.updateProfile({ - firebaseAppInstanceId: appInstanceId, - }); + await adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId); } catch (error) { // handle `AdaptyError` } ``` ### Mixpanel \{#mixpanel\} Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Конфигурация SDK для интеграции Mixpanel](mixpanel#sdk-configuration). ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import { Mixpanel } from 'mixpanel-react-native'; // ... try { - await adapty.updateProfile({ - mixpanelUserId: mixpanelUserId, - }); + await adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelUserId); } catch (error) { // handle `AdaptyError` } ``` ### OneSignal Обновите код мобильного приложения, как показано ниже. Полный пример кода можно найти в разделе [Настройка SDK для интеграции с OneSignal](onesignal#sdk-configuration).
:::important
**Дальнейшие шаги зависят от того, есть ли у вас уже продукты в App Store и/или Google Play:**
:::
5. Нажмите **Save & Continue** и перейдите на вкладку **App Store** или **Google Play**, чтобы заполнить данные о продукте для стора.
Этот пейвол отображается в коде вашего приложения.
:::tip
Adapty позволяет показывать разные пейволы разным группам пользователей и анализировать эффективность. Узнайте больше об [аудиториях](audience) и [A/B-тестах](ab-tests).
:::
## Следующие шаги \{#next-steps\}
Поздравляем с успешным онбордингом в Adapty! Теперь вы готовы развивать встроенные покупки.
Подготовьтесь к релизу в продакшн:
Или продолжите работу с перечисленными ниже разделами:
- **[A/B-тестирование](ab-tests)**: Экспериментируйте с ценами, длительностью подписок, пробными периодами и визуальными элементами, чтобы найти наиболее эффективные комбинации.
- **[Аналитика](how-adapty-analytics-works)**: Изучайте детальные метрики монетизации, чтобы понять поведение пользователей и оптимизировать доход.
- **Интеграции**: Adapty отправляет [события подписки](events) в сторонние инструменты аналитики и атрибуции, такие как [Amplitude](amplitude), [AppsFlyer](appsflyer), [Adjust](adjust), [Branch](branch), [Mixpanel](mixpanel), [Facebook Ads](facebook-ads), [AppMetrica](appmetrica), а также в пользовательский [Webhook](webhook).
:::tip
Есть вопросы или возникли проблемы? Загляните на наш [форум поддержки](https://adapty.featurebase.app/), где можно найти ответы на распространённые вопросы или задать свой. Наша команда и сообщество всегда готовы помочь!
:::
---
# File: release-checklist
---
---
title: "Чеклист перед релизом"
description: "Следуйте чеклисту Adapty, чтобы обеспечить плавный процесс обновления приложения."
---
Рады, что вы выбрали Adapty! Надеемся, интеграция прошла гладко. Этот гайд поможет убедиться, что приложение готово к публикации в сторах, а монетизация работает корректно.
## Что нужно подготовить заранее \{#pre-flight-essentials\}
Перед началом проверки убедитесь, что у вас есть:
- Реальное устройство с sandbox-аккаунтом
- Доступ к дашборду Adapty
- Доступ к App Store Connect / Google Play Console
:::note
Хотя sandbox-покупки можно тестировать на симуляторах, реальные устройства необходимы для полноценного тестирования всех сценариев — включая диалоги оплаты и биометрическую аутентификацию.
:::
## Универсальные проверки \{#universal-validations\}
- [ ] **Подключение стора**: Убедитесь, что вы подключили Adapty к App Store и/или Google Play:
- [ ] [App Store](initial_ios)
- [ ] [Google Play](initial-android)
- [ ] **Доставка событий подписки**: Убедитесь, что серверные уведомления настроены:
- [ ] [Серверные уведомления App Store](enable-app-store-server-notifications)
- [ ] [Уведомления разработчика в реальном времени (RTDN)](enable-real-time-developer-notifications-rtdn)
- [ ] **Идентификация профиля**: Проверьте логику идентификации пользователей и убедитесь, что покупки привязываются к нужному профилю:
- [ ] [Убедитесь, что логика идентификации в коде приложения соответствует вашему сценарию использования](ios-quickstart-identify)
- [ ] [Убедитесь, что вы понимаете логику parent/inheritor при совместном использовании платного доступа между профилями пользователей](sharing-paid-access-between-user-accounts)
- [ ] **Офферы**: Если в приложении используются promotional offer из App Store, убедитесь, что вы [добавили ключ встроенных покупок](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers) как в основное поле, так и в раздел **App Store promotional offers**.
- [ ] **Сбор данных**: Убедитесь в соответствии требованиям конфиденциальности:
- [ ] Если вам необходимо соответствовать требованиям законодательства о конфиденциальности (например, GDPR или CCPA) или приложение предназначено для детей, управляйте тем, [включён ли сбор и передача IDFA и IP-адреса](sdk-installation-ios#data-policies).
- [ ] Если в приложении используется AppTrackingTransparency, убедитесь, что вы [передаёте статус авторизации в Adapty](ios-deal-with-att).
- [ ] **Метки конфиденциальности**: [Узнайте подробнее](apple-app-privacy) о том, какие данные собирает Adapty и какие флаги нужно выставить при проверке.
## Проверка покупок \{#purchase-validations\}
:::tip
Есть вопросы или возникли проблемы? Загляните на наш [форум поддержки](https://adapty.featurebase.app/), где можно найти ответы на распространённые вопросы или задать свой. Наша команда и сообщество всегда готовы помочь!
:::
Перед запуском убедитесь, что покупки в вашем приложении работают корректно и пейвол готов к ревью в сторе.
Способ проверки встроенных покупок зависит от того, как вы их реализовали:
- Вы отображаете пейвол, созданный в Adapty Paywall Builder
- Вы реализовали собственный пейвол и используете метод `makePurchase` внутри него для обработки покупок
- Вы используете Adapty в режиме наблюдателя (как с Adapty Paywall Builder, так и с собственным пейволом)
Возможно, но требует значительно большего объёма дополнительного кода и настройки, чем в Full Mode.
| ✅ | | **Время внедрения** |Для аналитики и интеграций: менее часа
С A/B-тестами: до недели с учётом тщательного тестирования
| Несколько часов | ## Как работает Observer mode \{#how-observer-mode-works\} В Observer mode вы передаёте новые транзакции от Apple/Google в Adapty SDK, а SDK перенаправляет их на бэкенд Adapty. При этом вы самостоятельно управляете доступом к платному контенту в приложении, завершаете транзакции, обрабатываете продления, решаете проблемы с оплатой и так далее. ## Как настроить Observer mode \{#how-to-set-up-observer-mode\} 1. Выполните начальную интеграцию Adapty [с Google Play](initial-android) и [с App Store](initial_ios). 2. Включите Observer mode при настройке Adapty SDK, установив параметр `observerMode` в значение `true`. Следуйте инструкциям по настройке для [iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk), [Android](sdk-installation-android#activate-adapty-module-of-adapty-sdk), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform#activate-adapty-sdk) и [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 3. [Передайте транзакции](report-transactions-observer-mode) из вашей существующей инфраструктуры покупок в Adapty для iOS и кросс-платформенных фреймворков на базе iOS. 4. (Опционально) Если вы хотите использовать сторонние интеграции, настройте их, как описано в разделе [Настройка сторонних интеграций](configuration). :::warning В Observer mode Adapty SDK не завершает транзакции — убедитесь, что вы обрабатываете этот аспект самостоятельно. ::: ## Как использовать пейволы и A/B-тесты в Observer mode \{#how-to-use-paywalls-and-ab-tests-in-observer-mode\} В Observer mode Adapty SDK не может определить источник покупок, поскольку они совершаются в вашей собственной инфраструктуре. Поэтому, если вы планируете использовать пейволы и/или A/B-тесты в Observer mode, необходимо связывать транзакцию из стора с соответствующим пейволом в коде мобильного приложения при передаче транзакции. Кроме того, пейволы, созданные с помощью Paywall Builder, должны отображаться особым образом при использовании Observer mode: - Отображайте пейволы в Observer mode для [iOS](implement-observer-mode) или [Android](android-present-paywall-builder-paywalls-in-observer-mode). - [Связывайте пейволы с транзакциями покупок](report-transactions-observer-mode) при передаче транзакций в Observer mode. --- # File: migration-from-revenuecat --- --- title: "Миграция с RevenueCat" description: "Мигрируйте с RevenueCat на Adapty по нашему пошаговому гайду." --- Миграция состоит из 5 логических шагов и занимает в среднем 2 часа. 90% всех миграций укладываются менее чем в один рабочий день. 1. Изучите ключевые отличия; создайте и настройте аккаунт Adapty _(5 минут)_; 2. Установите Adapty SDK для вашей платформы ([iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity)) вместо RevenueCat SDK _(1 час)_; 3. Настройте [уведомления сервера Apple App Store](enable-app-store-server-notifications) для Adapty и (опционально) [пересылку raw-событий](enable-app-store-server-notifications#raw-events-forwarding) _(5 минут)_; 4. Протестируйте и выпустите обновление приложения _(30 минут);_ 5. (Опционально) Запросите у поддержки RevenueCat исторические данные в формате CSV _(5 минут);_ 6. (Опционально) Импортируйте исторические данные через поддержку Adapty _(30 минут)_. :::info Подписчики мигрируют автоматически Все пользователи, когда-либо активировавшие подписку, автоматически появятся в Adapty, как только откроют новую версию приложения с Adapty SDK. Валидация статуса подписки и доступ к премиум-контенту будут восстановлены автоматически. ::: Перед выпуском новой версии приложения с Adapty SDK обязательно ознакомьтесь с нашим [чеклистом перед релизом](release-checklist). ## Изучите ключевые отличия; создайте и настройте аккаунт Adapty \{#learn-the-core-differences-create-and-prepare-an-adapty-account\} SDK Adapty и RevenueCat устроены схожим образом. Главное отличие — в сетевом взаимодействии и скорости: Adapty SDK разработан так, чтобы как можно быстрее предоставлять информацию по запросу. Например, при запросе пейвола вы сначала получаете [Remote Config](customize-paywall-with-remote-config) для предварительной сборки онбординга или пейвола, а затем запрашиваете продукты отдельным запросом. Терминология немного отличается: | RevenueCat | Adapty | | :---------- | :-------------- | | Package | Product | | Offering | Paywall | | Paywall | Paywall Builder | | Entitlement | Access level | В Adapty есть концепция [плейсмента](placements). Это логическое место внутри приложения, где пользователь может совершить покупку. В большинстве случаев плейсментов один или два: - Онбординг (80% всех покупок происходит именно там); - Общий (показывается в настройках или внутри приложения после онбординга).
## Установите Adapty SDK и замените RevenueCat SDK \{#install-adapty-sdk-and-replace-revenuecat-sdk\}
Установите Adapty SDK для вашей платформы ([iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity)) в своём приложении.
Нужно заменить несколько методов SDK на стороне приложения. Разберём наиболее распространённые функции и то, как их заменить на методы Adapty SDK.
### Активация SDK \{#sdk-activation\}
Замените `Purchases.configure` на `Adapty.activate`.
### Получение пейволов (офферингов) \{#getting-paywalls-offerings\}
Замените `Purchases.shared.getOfferings` на [`Adapty.getPaywall`](fetch-paywalls-and-products#fetch-paywall-information).
В Adapty пейвол всегда запрашивается через [placement id](placements). На практике вы запрашиваете не более 1–2 пейволов, поэтому мы намеренно сделали именно так — чтобы ускорить SDK и снизить сетевую нагрузку.
### Получение профиля пользователя \{#getting-a-user-customer-profile\}
Замените `Purchases.shared.getCustomerInfo` на `Adapty.getProfile`.
### Получение продуктов \{#getting-products\}
В RevenueCat используется следующая структура: `Purchases.shared.getOfferings`, затем `self.offering?.availablePackages`.
В Adapty вы сначала запрашиваете пейвол (см. выше), чтобы получить мгновенный доступ к [Remote Config](customize-paywall-with-remote-config) Adapty, а затем запрашиваете продукты через [`Adapty.getPaywallProducts`](fetch-paywalls-and-products#fetch-products).
### Совершение покупки \{#making-a-purchase\}
Замените `Purchases.shared.purchase` на [`Adapty.makePurchase`](making-purchases#make-purchase).
### Проверка уровня доступа (entitlement) \{#checking-access-level-entitlement\}
Получите профиль пользователя (см. выше) и замените
`customerInfo?.entitlements["premium"]?.isActive == true`
на
[`profile.accessLevels["premium"]?.isActive == true`](subscription-status#retrieving-the-access-level-from-the-server).
### Восстановление покупки \{#restore-purchase\}
Замените `Purchases.shared.restorePurchases` на [`Adapty.restorePurchases`](restore-purchase).
### Проверка авторизации пользователя \{#check-if-the-user-is-logged-in\}
Замените `Purchases.shared.isAnonymous` на `if profile.customerUserId == nil`.
### Вход пользователя \{#log-in-user\}
Замените `Purchases.shared.logIn` на [`Adapty.identify`](identifying-users#set-customer-user-id-after-configuration).
### Выход пользователя \{#log-out-user\}
Замените `Purchases.shared.logOut` на [`Adapty.logout`](identifying-users#logging-out-and-logging-in).
## Переключите серверные уведомления App Store на Adapty \{#switch-app-store-server-side-notifications-to-adapty\}
Как это сделать — читайте [здесь](migrate-to-adapty-from-another-solutions#changing-apple-server-notifications).
## Протестируйте и выпустите новую версию приложения \{#test-and-release-a-new-version-of-your-app\}
Если вы дошли до этого пункта, значит вы уже:
- [x] Настроили дашборд Adapty
- [x] Установили Adapty SDK
- [x] Заменили логику SDK на функции Adapty
- [x] Переключили серверные уведомления App Store на Adapty и при необходимости включили пересылку raw-событий в RevenueCat
- [ ] Совершили покупку в песочнице
- [ ] Выпустили новую версию приложения
Если все пункты выше отмечены, просто совершите тестовую покупку в песочнице, а затем выпустите приложение.
:::info
Пройдите [чеклист перед релизом](release-checklist).
Выполните финальную проверку по нашему списку, чтобы убедиться в корректности интеграции или добавить дополнительные функции, например [атрибуцию](attribution-integration) или интеграцию с [аналитикой](analytics-integration).
:::
## (Опционально) Экспортируйте исторические данные RevenueCat в формате CSV \{#optional-export-your-revenuecat-historical-data-in-csv-format\}
:::warning
Не торопитесь с импортом исторических данных
Подождите не менее недели после релиза с SDK, прежде чем импортировать исторические данные. За это время мы получим из SDK информацию о ценах покупок, и импортируемые данные станут более актуальными.
:::
Экспортируйте исторические данные из RevenueCat в формате CSV, следуя инструкциям в [официальной документации RevenueCat](https://www.revenuecat.com/docs/integrations/scheduled-data-exports).
## (Опционально) Запросите у поддержки RevenueCat токены Google Purchase Tokens \{#optional-ask-revenuecat-support-for-google-purchase-tokens\}
Если вам нужно импортировать транзакции Google Play, обратитесь в поддержку RevenueCat через их [страницу поддержки](https://app.revenuecat.com/settings/support) и запросите CSV-файл с Google Purchase Tokens. Google Purchase Token — это уникальный идентификатор, предоставляемый Google Play для каждой транзакции; он необходим для точного отслеживания и верификации покупок в Adapty. Эта информация не включается в стандартный экспортный файл. Файл содержит три столбца:
- `user_id`
- `google_purchase_token`
- `google_product_id`
## Напишите нам для импорта исторических данных \{#write-us-to-import-your-historical-data\}
Свяжитесь с нами через мессенджер на сайте или по электронной почте [support@adapty.io](mailto:support@adapty.io), прикрепив ваши CSV-файлы.
1. Отправьте CSV-файл, экспортированный из RevenueCat, напрямую в нашу службу поддержки.
2. Если вы импортируете транзакции Google Play, приложите CSV-файл с Google Purchase Tokens, полученный от поддержки RevenueCat.
3. Укажите, какой идентификатор пользователя следует использовать в качестве Customer User ID (основного идентификатора пользователя в Adapty): `rc_original_app_user_id` или `rc_last_seen_app_user_id_alias`.
Наша команда поддержки импортирует ваши транзакции в Adapty. Для каждой транзакции будут импортированы следующие данные:
| Параметр | Описание |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| user_id | Customer User ID — основной идентификатор пользователя в Adapty и вашей системе. |
| apple_original_transaction_id | Для цепочек подписок — это дата покупки исходной транзакции, связанная через `store_original_transaction_id`. |
| google_product_id | Идентификатор продукта в Google Play Store. |
| google_purchase_token | Уникальный идентификатор, предоставляемый Google Play для каждой транзакции; необходим для валидации. |
| country | Страна пользователя. |
| created_at | Дата и время создания пользователя. |
| subscription_expiration_date | Дата и время окончания подписки. |
| email | Email конечного пользователя. |
| phone_number | Номер телефона конечного пользователя. |
| idfa | Identifier for Advertisers (IDFA) — идентификатор устройства пользователя, присваиваемый Apple. |
| idfv | Identifier for Vendors (IDFV) — код, присваиваемый всем приложениям одного разработчика и используемый совместно на одном устройстве. |
| advertising_id | Уникальный идентификатор, предоставляемый ОС Android и используемый рекламодателями для отслеживания. |
| attribution_channel | Название маркетингового канала. |
| attribution_campaign | Название маркетинговой кампании. |
| attribution_ad_group | Группа объявлений атрибуции. |
| attribution_ad_set | Набор объявлений атрибуции. |
| attribution_creative | Ключевое слово креатива атрибуции. |
Кроме того, будут импортированы идентификаторы интеграций для следующих сервисов: Amplitude, Mixpanel, AppsFlyer, Adjust и FacebookAds.
## FAQ \{#faq\}
### Я успешно установил Adapty SDK и выпустил новую версию приложения. Что произойдёт с моими действующими подписчиками, которые не обновили приложение до версии с Adapty SDK? \{#i-successfully-installed-adapty-sdk-and-released-a-new-app-version-with-it-what-will-happen-to-my-legacy-subscribers-who-did-not-update-to-a-version-with-adapty-sdk\}
Большинство пользователей заряжают телефоны на ночь — именно тогда App Store обычно автоматически обновляет все приложения, так что это не должно стать проблемой. Небольшое количество платных подписчиков всё же может не обновиться, но они по-прежнему сохранят доступ к премиум-контенту. Беспокоиться об этом не нужно, и принудительно заставлять их обновляться тоже.
### Нужно ли мне как можно скорее экспортировать исторические данные из RevenueCat, или я рискую их потерять? \{#do-i-need-to-export-my-historical-data-from-revenuecat-as-quickly-as-possible-or-will-i-lose-it\}
Торопиться не нужно: сначала выпустите приложение с Adapty SDK, а потом передайте нам исторические данные. Мы восстановим историю платежей ваших пользователей и заполним [профили](profiles-crm) и [графики](charts).
### Я использую MMP (AppsFlyer, Adjust и др.) и аналитику (Mixpanel, Amplitude и др.). Как убедиться, что всё будет работать? \{#i-use-mmp-appsflyer-adjust-etc-and-analytics-mixpanel-amplitude-etc-how-do-i-make-sure-that-everything-will-work\}
Сначала нужно передать нам идентификаторы сторонних сервисов через наш SDK — тех, которым вы хотите отправлять данные. Ознакомьтесь с гайдом по [интеграции атрибуции](attribution-integration) и [интеграции аналитики](analytics-integration). Для исторических данных и существующих пользователей **обязательно передайте нам эти идентификаторы из данных, экспортированных из RevenueCat.**
---
# File: migration-from-superwall
---
---
title: "Миграция с Superwall"
description: "Мигрируйте с Superwall на Adapty с помощью пошагового руководства, которое сопоставляет каждый SDK-вызов и концепцию."
---
Большинство миграций с Superwall на Adapty занимают около двух часов. Вы заменяете SDK, направляете серверные уведомления стора на Adapty и выпускаете новую версию приложения. Платные подписчики сохраняют доступ — Adapty восстанавливает его из чеков App Store и Google Play при первом запуске.
:::info
Ваши подписчики мигрируют автоматически
Все пользователи, когда-либо активировавшие подписку, переходят на Adapty сразу после открытия новой версии приложения с SDK Adapty. Валидация статуса подписки и доступ к премиум-функциям восстанавливаются автоматически.
:::
## Структура руководства \{#how-this-guide-is-organized\}
Миграция состоит из шести шагов:
1. [Сопоставьте концепции Superwall с Adapty](#map-your-superwall-concepts-to-adapty)
2. [Установите SDK Adapty](#install-the-adapty-sdk)
3. [Замените SDK-вызовы](#replace-sdk-calls)
4. [Переключите серверные уведомления App Store и Google Play](#switch-app-store-and-google-play-server-notifications)
5. [Протестируйте и выпустите релиз](#test-and-release)
6. [(Опционально) Импортируйте исторические данные](#optional-import-historical-data)
## Сопоставьте концепции Superwall с Adapty \{#map-your-superwall-concepts-to-adapty\}
Большинство концепций Superwall имеют прямой аналог в Adapty:
| Superwall | Adapty | Что меняется |
| :------------------- | :------------------------------------------------ | :--------------------------------------------------------------------------- |
| Campaign | [Плейсмент](placements) + [Аудитория](audience) | Логика кампании разделяется на плейсмент (место показа) и аудиторию (правило). |
| Placement | [Плейсмент](placements) | Та же концепция, то же название. |
| Audience filter | [Аудитория](audience) | Наборы правил живут внутри плейсмента. |
| Entitlement | [Уровень доступа](access-level) | Именованный идентификатор (например, `premium`). |
| WebView paywall | [Пейвол Paywall Builder](adapty-paywall-builder) | Отрисовывается SDK Adapty нативно вместо `WKWebView`. |
| `PurchaseController` | Встроенный | Протокол реализовывать не нужно — Adapty обрабатывает покупки самостоятельно. |
| Feature gating | Проверка [уровня доступа](access-level) | Проверяйте `profile.accessLevels["premium"]?.isActive`. |
Перед тем как касаться кода, стоит осмыслить два ключевых отличия:
- **Получение и показ — это отдельные шаги**: `register` в Superwall за один вызов получает пейвол, оценивает кампанию и показывает UI. Adapty разделяет эти шаги — вы получаете пейвол, загружаете его конфигурацию, а затем показываете. Это добавляет несколько строк кода, но позволяет предзагружать конфигурации, показывать собственное состояние загрузки или отменять показ по вашей логике.
- **Статус подписки привязан к уровню доступа**: Superwall предоставляет единственное публикуемое свойство `subscriptionStatus`. Adapty возвращает [`AdaptyProfile`](https://swift.adapty.io/documentation/adapty/adaptyprofile) с именованными уровнями доступа, так что один пользователь может одновременно иметь уровни доступа `sports` и `science`. Для синхронного чтения кешируйте профиль из `AdaptyDelegate`, а не вызывайте `getProfile()` при каждой загрузке экрана.
## Установите SDK Adapty \{#install-the-adapty-sdk\}
Установите SDK Adapty для вашей платформы — [iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity) или [Capacitor](sdk-installation-capacitor) — и одновременно удалите SuperwallKit из проекта.
## Замените SDK-вызовы \{#replace-sdk-calls\}
Пройдитесь по каждой части интеграции и замените вызовы Superwall на эквиваленты Adapty. Ссылки в конце каждого подраздела охватывают все семь платформенных SDK — перейдите по той, которая соответствует вашему приложению.
### Инициализация SDK \{#initialize-the-sdk\}
Замените `Superwall.configure` на `Adapty.activate`.
Смотрите руководство по установке для вашей платформы — [iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity) или [Capacitor](sdk-installation-capacitor).
### Идентификация и выход пользователей \{#identify-and-log-out-users\}
Замените `Superwall.shared.identify` на `Adapty.identify`, а `Superwall.shared.reset` — на `Adapty.logout`. Оба SDK генерируют анонимный профиль при первом запуске, поэтому эти вызовы нужны только при входе или выходе пользователя. После идентификации заново получайте пейволы — новый пользователь может попасть в другую аудиторию.
Смотрите руководство по идентификации для вашей платформы — [iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), [Kotlin Multiplatform](kmp-identifying-users), [Unity](unity-identifying-users) или [Capacitor](capacitor-identifying-users).
### Получение и показ пейвола \{#fetch-and-present-a-paywall\}
Замените `Superwall.shared.register` на двухшаговый флоу: получите пейвол через `Adapty.getPaywall`, загрузите конфигурацию его вида через `AdaptyUI.getPaywallConfiguration`, а затем покажите его.
Два важных отличия:
- **Feature gating заменяет замыкание `feature:`**: после закрытия пейвола проверьте активный уровень доступа в возвращённом профиле (или через `Adapty.getProfile`) и разветвляйте логику оттуда.
- **Пейволы отрисовываются SDK**: Superwall рендерит пейволы внутри `WKWebView`. Adapty рендерит пейволы Paywall Builder нативно — шрифты, информация о продуктах и кнопки отрисовываются SDK.
Смотрите быстрый старт по пейволам для вашей платформы — [iOS](ios-quickstart-paywalls), [Android](android-quickstart-paywalls), [React Native](react-native-quickstart-paywalls), [Flutter](flutter-quickstart-paywalls), [Kotlin Multiplatform](kmp-quickstart-paywalls), [Unity](unity-quickstart-paywalls) или [Capacitor](capacitor-quickstart-paywalls).
### Проверка статуса подписки \{#check-subscription-status\}
Замените `Superwall.shared.subscriptionStatus` на проверку именованного уровня доступа в профиле: `profile.accessLevels["premium"]?.isActive`. Отслеживайте изменения через `AdaptyDelegate.didLoadLatestProfile(_:)` вместо паттерна с `@Published`-свойством, и кешируйте профиль на своей стороне для синхронного чтения.
Смотрите руководство по статусу подписки для вашей платформы — [iOS](ios-check-subscription-status), [Android](android-check-subscription-status), [React Native](react-native-check-subscription-status), [Flutter](flutter-check-subscription-status), [Kotlin Multiplatform](kmp-check-subscription-status), [Unity](unity-check-subscription-status) или [Capacitor](capacitor-check-subscription-status).
### Обработка покупок и восстановлений \{#handle-purchases-and-restores\}
При использовании Paywall Builder оба SDK обрабатывают покупки автоматически внутри UI пейвола — **этот шаг можно пропустить**.
Для кастомных пейволов Superwall требует реализации `PurchaseController`. В Adapty этого не нужно: замените `PurchaseController.purchase` на `Adapty.makePurchase`, а `PurchaseController.restorePurchases` — на `Adapty.restorePurchases`. SDK самостоятельно выполняет валидацию.
Смотрите быстрый старт по кастомным пейволам для вашей платформы — [iOS](ios-quickstart-manual), [Android](android-quickstart-manual), [React Native](react-native-quickstart-manual), [Flutter](flutter-quickstart-manual), [Kotlin Multiplatform](kmp-quickstart-manual), [Unity](unity-quickstart-manual) или [Capacitor](capacitor-quickstart-manual).
### Установка атрибутов пользователя \{#set-user-attributes\}
Замените `Superwall.shared.setUserAttributes` на `Adapty.updateProfile`.
Смотрите руководство по атрибутам пользователя для вашей платформы — [iOS](setting-user-attributes), [Android](android-setting-user-attributes), [React Native](react-native-setting-user-attributes), [Flutter](flutter-setting-user-attributes), [Kotlin Multiplatform](kmp-setting-user-attributes), [Unity](unity-setting-user-attributes) или [Capacitor](capacitor-setting-user-attributes).
## Переключите серверные уведомления App Store и Google Play \{#switch-app-store-and-google-play-server-notifications\}
Направьте серверные уведомления стора на Adapty. Adapty работает и без них, но аналитика, сторонние интеграции и метрики A/B-тестов зависят от этих уведомлений:
- **App Store**: следуйте инструкции [Включить серверные уведомления App Store](enable-app-store-server-notifications).
- **Google Play**: следуйте инструкции [Включить уведомления для разработчиков в реальном времени](enable-real-time-developer-notifications-rtdn).
Если вы хотите запускать Superwall и Adapty параллельно в процессе выкатки, используйте [переадресацию необработанных событий](enable-app-store-server-notifications#raw-events-forwarding) — Adapty проксирует события стора обратно в Superwall, пока вы проверяете новую интеграцию.
## Протестируйте и выпустите релиз \{#test-and-release\}
Перед релизом убедитесь, что выполнены все пункты:
- [x] Настроен дашборд Adapty (продукты, пейволы, плейсменты, уровни доступа)
- [x] Установлен SDK Adapty
- [x] Вызовы Superwall SDK заменены на эквиваленты Adapty
- [x] Серверные уведомления App Store и Google Play направлены на Adapty
- [ ] Совершена покупка в песочнице
- [ ] Отправлен новый релиз приложения
Пройдите [чеклист перед релизом](release-checklist) для финальной проверки.
## (Опционально) Импортируйте исторические данные \{#optional-import-historical-data\}
Superwall не хранит ваш статус подписки — это делают App Store и Google Play. Adapty валидирует чеки при первом запуске, поэтому платные пользователи сохраняют доступ без какого-либо импорта.
Если вы хотите, чтобы исторические транзакции были добавлены в аналитику Adapty, следуйте инструкции [Импорт исторических данных в Adapty](importing-historical-data-to-adapty). Подождите не менее недели после выпуска SDK, чтобы он успел собрать актуальные цены покупок.
## FAQ \{#faq\}
### Что произойдёт с подписчиками, которые не обновят приложение? \{#what-happens-to-subscribers-who-dont-update-the-app\}
Большинство пользователей обновляют приложения автоматически в ночное время, поэтому доля пользователей на старой версии быстро сокращается. Подписчики на старой версии сохраняют доступ напрямую через App Store или Google Play — принудительное обновление не требуется.
### Перенесутся ли аудитории моих кампаний Superwall? \{#do-my-superwall-campaign-audiences-carry-over\}
Нет. Фильтры аудиторий Superwall и аудитории Adapty настраиваются в разных дашбордах и используют разные идентификаторы. Воссоздайте свой таргетинг в виде [аудиторий](audience) внутри [плейсментов](placements) Adapty. В большинстве приложений используется один-два плейсмента (онбординг и общий внутриприложенческий триггер), поэтому пересборка обычно занимает немного времени.
### Есть ли в Adapty аналог `getPresentationResult`? \{#does-adapty-have-an-equivalent-to-getpresentationresult\}
Не в виде единственного вызова. Чтобы проверить, будет ли показан пейвол для плейсмента, вызовите `Adapty.getPaywall(placementId:)` и разветвляйте логику по результату. Если вызов успешен, значит для аудитории этого пользователя назначен пейвол. Если вызов завершается с ошибкой из-за отсутствия настроенного пейвола, пропустите показ и выполните резервную логику.
---
# File: importing-historical-data-to-adapty
---
---
title: "Импорт исторических данных в Adapty"
description: "Импортируйте исторические данные в Adapty для детальной аналитики."
---
После установки SDK Adapty и публикации приложения вы можете просматривать своих пользователей и подписчиков в разделе [Profiles](profiles-crm). Но что, если у вас есть устаревшая инфраструктура и нужно мигрировать на Adapty, или вы просто хотите видеть существующие данные в Adapty?
:::note
Импорт данных не обязателен
Adapty автоматически предоставит уровни доступа историческим пользователям и восстановит их события покупок, как только они откроют приложение с интегрированным SDK Adapty. Для этого сценария импорт исторических данных не нужен. Тем не менее импорт данных обеспечивает точную аналитику, если у вас большой объём исторических транзакций, хотя в целом он не является обязательным условием миграции.
:::
Чтобы импортировать данные в Adapty:
1. Экспортируйте транзакции в CSV-файл (для iOS, Android и Stripe нужны отдельные файлы). Подробные требования к формату файла описаны в разделе [Формат файла импорта](importing-historical-data-to-adapty#import-file-format) ниже.
2. Если какой-либо файл превышает 1 ГБ, подготовьте выборку данных примерно из 100 строк.
3. Загрузите все файлы на Google Drive (можно сжать их, но держите отдельно).
4. Для транзакций iOS убедитесь, что раздел **In-app purchase API** в [**App settings**](https://app.adapty.io/settings/ios-sdk) заполнен **Issuer ID**, **Key ID** и **Private key** (файл .P8) — даже если вы используете StoreKit 1. Подробные инструкции см. в разделах [Укажите Issuer ID и Key ID](app-store-connection-configuration#step-2-provide-issuer-id-and-key-id) и [Загрузите файл In-App Purchase Key](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file).
5. Поделитесь ссылками с нашей командой по [email](mailto:support@adapty.io) или через онлайн-чат в дашборде Adapty.
Не беспокойтесь: импорт исторических данных не создаст дубликатов, даже если данные пересекаются с уже существующими записями в Adapty.
## Известные ограничения для Android \{#known-limitations-for-android\}
1. Восстанавливаются только активные подписки; истёкшие транзакции восстановлены не будут.
2. Восстанавливаются только последние продления подписки; вся цепочка покупок восстановлена не будет.
3. Если цена продукта изменилась с момента покупки, будет использоваться текущая цена, что может привести к некорректным данным о стоимости.
:::note
Если у вас большой объём Android-транзакций, перед началом импорта может потребоваться [запросить увеличение квоты Google Play Developer API](google-play-quota-increase), чтобы не превысить лимит по умолчанию.
:::
## Формат файла импорта \{#import-file-format\}
:::tip
Если вы мигрируете с RevenueCat, можно отправить файл экспорта RevenueCat напрямую — конвертация не нужна. Инструкции по экспорту см. в [документации RevenueCat](https://www.revenuecat.com/docs/integrations/scheduled-data-exports).
:::
Подготовьте данные в файле или нескольких файлах, соответствующих следующим требованиям:
- [ ] Формат файла — .CSV.
- [ ] Отдельные файлы для Android, iOS и Stripe.
- [ ] Каждый файл импорта содержит все [обязательные столбцы](importing-historical-data-to-adapty#required-fields).
- [ ] Столбцы в файлах импорта имеют заголовки.
- [ ] Заголовки столбцов точно соответствуют значениям в колонке **Column name** в таблице ниже. Проверьте наличие опечаток.
- [ ] Необязательные столбцы могут отсутствовать в файле. Не добавляйте пустые столбцы для данных, которых у вас нет.
- [ ] Файлы импорта не должны содержать дополнительных столбцов, не указанных в таблице. Если они есть, удалите их.
- [ ] Значения разделены запятыми.
- [ ] Значения не заключены в кавычки.
- [ ] Если у одного пользователя несколько **apple_original_transaction_id**, добавьте их отдельными строками для каждого **apple_original_transaction_id**. В противном случае мы можем не восстановить расходуемые покупки.
В качестве примеров используйте следующие файлы для [iOS](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/adapty_import_ios_sample.csv) и [Android](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/adapty_import_android_sample.csv).
### Доступные столбцы файла импорта \{#available-import-file-columns\}
| Название столбца | Наличие | Описание |
|-----------|--------|-----------|
| **user_id** | обязательный | ID вашего пользователя |
| **apple_original_transaction_id** | обязательный для iOS | Оригинальный идентификатор транзакции или OTID ([подробнее](https://developer.apple.com/documentation/appstoreserverapi/originaltransactionid)), используется в механизме импорта StoreKit 2. Поскольку у одного пользователя может быть несколько OTID, для успешного импорта достаточно указать хотя бы один.
**Примечание:** Для этого импорта необходимо настроить учётные данные In-app purchase API в дашборде Adapty. Как это сделать — [здесь](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file).
| | **google_product_id** | обязательный для Google | ID продукта в Google Play Store. | | **google_purchase_token** | обязательный для Google | Уникальный идентификатор, представляющий пользователя и ID продукта для приобретённой встроенной покупки | | **google_is_subscription** | обязательный для Google | Возможные значения: `1` \| `0` | | **stripe_token** | обязательный для Stripe | Токен объекта Stripe, представляющий уникальную покупку. Может быть токеном подписки Stripe (`sub_...`) или Payment Intent (`pi_...`). | | **subscription_expiration_date** | необязательный | Дата истечения подписки, т.е. следующая дата списания, дата и время с часовым поясом (2020-12-31T23:59:59-06:00) | | **created_at** | необязательный | Дата и время создания профиля (2019-12-31 23:59:59-06:00) | | **birthday** | необязательный | Дата рождения пользователя в формате 2000-12-31 | | **email** | необязательный | Электронная почта вашего пользователя | | **gender** | необязательный | Пол пользователя | | **phone_number** | необязательный | Номер телефона вашего пользователя | | **country** | необязательный | формат [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) | | **first_name** | необязательный | Имя вашего пользователя | | **last_name** | необязательный | Фамилия вашего пользователя | | **last_seen** | необязательный | Дата и время с часовым поясом (2020-12-31T23:59:59-06:00) | | **idfa** | необязательный | Идентификатор для рекламодателей (IDFA) — случайный идентификатор устройства, назначаемый Apple. Применяется только для iOS-приложений | | **idfv** | необязательный | Идентификатор для поставщиков (IDFV) — уникальный код, назначаемый всем приложениям одного разработчика. Применяется только для iOS-приложений | | **advertising_id** | необязательный | Advertising ID — уникальный код, назначаемый операционной системой Android, который рекламодатели могут использовать для уникальной идентификации устройства пользователя | | **amplitude_user_id** | необязательный | ID пользователя из Amplitude | | **amplitude_device_id** | необязательный | ID устройства из Amplitude | | **mixpanel_user_id** | необязательный | ID пользователя из Mixpanel | | **appmetrica_profile_id** | необязательный | ID профиля пользователя из AppMetrica | | **appmetrica_device_id** | необязательный | ID устройства из AppMetrica | | **appsflyer_id** | необязательный | Уникальный идентификатор из AppsFlyer | | **adjust_device_id** | необязательный | ID устройства из Adjust | | **facebook_anonymous_id** | необязательный | Уникальный идентификатор, генерируемый Facebook для пользователей, анонимно взаимодействующих с вашим приложением или сайтом, то есть не вошедших в Facebook | | **branch_id** | необязательный | Уникальный идентификатор из Branch | | **attribution_source** | необязательный | Источник интеграции атрибуции, например appsflyer | | **attribution_status** | необязательный | organic | | **attribution_channel** | необязательный | Канал атрибуции, привлёкший транзакцию | | **attribution_campaign** | необязательный | Кампания атрибуции, привлёкшая транзакцию | | **attribution_ad_group** | необязательный | Группа объявлений атрибуции, привлёкшая транзакцию | | **attribution_ad_set** | необязательный | Набор объявлений атрибуции, привлёкший транзакцию | | **attribution_creative** | необязательный | Конкретные визуальные или текстовые элементы рекламного объявления или маркетинговой кампании, которые отслеживаются для оценки эффективности достижения целевых действий: кликов, конверсий или установок | | **custom_attributes** | необязательный | Определите до 30 пользовательских атрибутов в виде JSON-словаря в формате ключ-значение:Формат: `"{'string_value': 'some_value', 'float_value': 123.0, 'int_value': 456}"`.
Обратите внимание на использование двойных и одинарных кавычек в формате. Имейте в виду, что булевы значения и целые числа будут преобразованы в числа с плавающей точкой.
| ### Обязательные поля \{#required-fields\} Для каждой платформы существует 2 группы обязательных полей: **user_id** и данные, идентифицирующие покупки для соответствующей платформы. Обязательные поля по платформам указаны в таблице ниже. | Платформа | Обязательные поля | |--------|---------------| | iOS |user_id
apple_original_transaction_id
| | Android |user_id
google_product_id
google_purchase_token
google_is_subscription
| | Stripe |user_id
stripe_token
| Без этих полей Adapty не сможет получить транзакции. Для точной аналитики по когортам укажите `created_at`. Если это поле не заполнено, датой установки будет считаться дата первой покупки. ### Импорт данных в Adapty \{#import-data-to-adapty\} Свяжитесь с нами и поделитесь файлами импорта через [support@adapty.io](mailto:support@adapty.io) или через онлайн-чат в [дашборде Adapty](https://app.adapty.io/overview). --- # File: migrate-integrations-to-adapty --- --- title: "Миграция интеграций на Adapty" description: "Переключите интеграции с аналитикой и атрибуцией с устаревшего решения на Adapty без дублирования событий и нарушения работы кампаний." --- Миграция на Adapty — это не только смена SDK. Сторонние инструменты аналитики и атрибуции, такие как Amplitude и Adjust, тоже требуют скоординированного переключения. При правильном подходе количество дублирующихся или пропущенных событий будет минимальным, а кампании не пострадают. ## Сопоставьте события \{#map-your-events\} В большинстве интеграций Adapty названия событий можно настраивать. Вы можете задать те же имена, которые уже используются в ваших дашбордах и кампаниях — аналитика и отчёты по кампаниям продолжат работать с теми же названиями событий после переключения. Полный список доступных событий в Adapty см. в разделе [События](events). Для Adjust интеграция использует идентификаторы событий вместо пользовательских названий. Перенесите существующие идентификаторы событий из дашборда Adjust в настройки интеграции Adapty. Подробнее см. в [руководстве по интеграции с Adjust](adjust). ## Как Adapty создаёт события интеграции \{#how-adapty-creates-integration-events\} Чтобы отправить событие в интеграцию, Adapty должен иметь профиль пользователя. Профиль создаётся одним из двух способов: - **Исторический импорт**: профиль создаётся при [импорте исторических данных о транзакциях](importing-historical-data-to-adapty) до запуска SDK. - **Взаимодействие через SDK**: профиль создаётся автоматически, когда пользователь впервые открывает приложение с SDK Adapty. Adapty узнаёт о покупках, совершённых в устаревшей системе, в режиме реального времени. Однако отправить событие в интеграцию он может только после того, как профиль покупателя будет создан. Профиль создаётся при первом запуске приложения с SDK Adapty. Пользователи, не обновившие приложение, не будут генерировать события интеграции. ## Подготовка перед днём миграции \{#prepare-before-migration-day\} ### Исключите исторические события \{#exclude-historical-events\} Включите **Exclude Historical Events** в [настройках интеграции](configuration). Это предотвратит отправку в интеграцию событий, относящихся к периоду до первой сессии пользователя с SDK Adapty. Этот параметр особенно важен при [историческом импорте](importing-historical-data-to-adapty), когда Adapty единовременно обрабатывает большой объём прошлых транзакций. Без него эти транзакции сгенерируют огромное количество событий в вашем инструменте аналитики. ### Настройте интеграцию заранее \{#set-up-the-integration-in-advance\} Adapty позволяет настраивать и тестировать интеграцию, не включая её. Вы можете задать учётные данные, маппинг событий и фильтры, не активируя интеграцию до нужного момента. Настройки сохраняются при включении, поэтому ничего не теряется, пока интеграция отключена. Чтобы найти нужную интеграцию, см. разделы [Интеграции атрибуции](attribution-integration), [Интеграции аналитики](analytics-integration), [Интеграции сервисов рассылок](messaging) или [Webhook и ETL-интеграции](webhook-and-etl). ## Переключение в день миграции \{#switch-on-migration-day\} Отключите интеграцию в устаревшем решении и одновременно включите её в Adapty. Работа обоих решений одновременно приведёт к дублированию событий. В день миграции приостановите крупные кампании по привлечению пользователей. Это снизит риск ошибок оптимизации кампаний из-за событий в окне перехода. ## Чего ожидать \{#what-to-expect\} Некоторое количество пропущенных или дублирующихся событий интеграции при миграции неизбежно. При правильном переключении число затронутых событий будет незначительным. Основная причина пробелов — описанная выше особенность: Adapty может отправлять события интеграции по покупке только после создания профиля пользователя. Покупки, совершённые в устаревшей системе, не генерируют события интеграции Adapty до тех пор, пока покупатель не откроет приложение с SDK Adapty. ## Интеграции и серверные уведомления \{#integrations-vs-server-to-server-notifications\} Adapty рекомендует использовать интеграции, а не пересылать сырые серверные уведомления от сторов напрямую в инструменты аналитики или атрибуции. Преимущества интеграций: - **Единый формат**: события из всех сторов — App Store, Google Play, Stripe — используют одинаковый формат. - **Обогащённые данные**: события включают данные, которые собирает Adapty, — например, состояние подписки и атрибуты пользователя. Сырые уведомления этого не содержат. --- # File: whats-new --- --- title: "Что нового" description: "Будьте в курсе последних возможностей и улучшений в Adapty" --- Узнавайте о последних функциях, улучшениях, обновлениях SDK и изменениях в документации, которые помогут оптимизировать монетизацию вашего приложения. На этой странице собраны самые важные релизы каждого месяца. :::note Есть отзывы о новых функциях? Будем рады услышать вас! Свяжитесь с нами через [доску обратной связи](https://adapty.featurebase.app/en?b=69831ba5e82e7a3391632ec2). ::: ## Июль 2026 \{#july-2026\} - **Виртуальные валюты**: определяйте внутриигровые валюты — токены, монеты, кристаллы, — начисляйте и отслеживайте баланс каждого пользователя и читайте эти балансы с сервера через server-side API. [Подробнее](virtual-currencies) - **AI-агент в Apple Ads Manager**: задавайте вопросы советнику-чату о производительности ваших Apple Ads и получайте ответы на основе данных ваших кампаний — без ручного составления отчётов. [Подробнее](ads-manager-ai-agent) - **Новые автоматизации в Apple Ads Manager**: Автоматизируйте изменения на уровне кампаний и групп объявлений с двумя новыми типами правил — в дополнение к существующим автоматизациям по ключевым словам и поисковым запросам. [Правила кампаний](ads-manager-automations-campaign-rules) | [Правила групп объявлений](ads-manager-automations-ad-group-rules) - **Профили в Adapty Mail**: Представление каждого подписчика, где в одном месте отображается его путь, текущий статус подписки и статус отписки. [Подробнее](mail-profiles) - **SDK v4 для React Native, Flutter, Capacitor и Kotlin Multiplatform**: SDK v4 с поддержкой флоу уже доступны. React Native, Flutter и Capacitor вышли в общий доступ, а Kotlin Multiplatform v4 запущен — каждый со своим гайдом по миграции. [React Native](migration-to-react-native-sdk-v4) | [Flutter](migration-to-flutter-sdk-v4) | [Capacitor](migration-to-capacitor-sdk-v4) | [Kotlin Multiplatform](migration-to-kmp-sdk-v4) - **Новые поля вебхуков**: Вебхук-пейлоады теперь содержат исходную цену и скидку по каждой транзакции — так удобнее отслеживать promotional offer и introductory offer в downstream-системах. Эти поля доступны только в вебхуках. [Подробнее](webhook-event-types-and-fields) - **Зачёркнутые цены во флоу**: Показывайте перечёркнутую исходную цену рядом со скидочной, с бейджем скидки, прямо в Flow Builder. [Подробнее](strikethrough-price) - **Галерея шаблонов флоу**: Начните новый флоу с профессионально оформленного шаблона вместо пустого холста, а затем настройте его под своё приложение. [Подробнее](paywall-builder-templates) - **Кнопка Install tools**: В каждой статье документации теперь есть кнопка **Install tools** в шапке. Она открывает модальное окно с готовыми командами для установки навыка интеграции Adapty SDK в Claude Code, Copilot CLI, Gemini CLI, Codex и другие AI-ассистенты для разработки. [Подробнее](adapty-sdk-integration-skill) - **Новый способ установки Unity SDK**: Теперь Unity SDK можно установить через Swift Package Manager — добавлено руководство по устранению типичных проблем при настройке. [Подробнее](sdk-installation-unity) - **Нижний контейнер во Flow Builder**: Прикреплённая панель внизу экрана, которая остаётся на месте, пока остальной контент прокручивается — удобно для кнопок CTA, юридических текстов и ссылок. [Подробнее](builder-containers#footer) - **Видеоуроки по Flow Builder**: Растущий плейлист на YouTube с пошаговыми руководствами по созданию флоу, теперь встроенный в гайды по Flow Builder. [Подробнее](adapty-flow-builder) ## Июнь 2026 \{#june-2026\} - **Flows теперь работают на Android**: Визуальный no-code редактор для пейволов и онбордингов теперь поддерживает Android SDK v4 и выше, наряду с iOS. Экраны отображаются нативно, без веб-вью. [Подробнее](adapty-flow-builder) - **CPP A/B-тесты в Apple Ads Manager**: Сравнивайте custom product pages друг с другом прямо в Apple Ads. Выберите от 2 до 4 страниц — включая текущую дефолтную — и Apple Ads будет распределять трафик между ними и показывать, какая из них лучше конвертирует. [Подробнее](ads-manager-cpp-ab-tests) - **Adapty Mail API**: Отправляйте профили пользователей и транзакции напрямую в Adapty Mail с вашего сервера, без прохождения данных через SDK. Используйте это для наполнения базы подписчиков, переноса подписчиков из других ваших приложений или для использования вашего бэкенда как единого источника данных. [Подробнее](mail-send-data-via-api) - **Показывать пейвол с таргетингом Apple Ads при первом запуске**: атрибуция Apple Ads поступает после активации SDK, поэтому пейвол, запрошенный слишком рано, не попадёт в аудиторию Apple Ads. Используйте `AdaptyProfile.appliedAttributionSources`, чтобы показать пейвол с таргетингом Apple Ads сразу после получения данных атрибуции. [iOS](ios-show-aa-targeted-paywall) | [React Native](react-native-show-aa-targeted-paywall) | [Capacitor](capacitor-show-aa-targeted-paywall) - **Автосохранение во Flow Builder**: Flow Builder теперь автоматически сохраняет прогресс раз в минуту — несохранённые изменения больше не теряются при уходе со страницы. Вы по-прежнему можете сохранить черновик вручную сочетанием **Cmd/Ctrl + S**. [Подробнее](builder-save-publish) - **Новые видеоуроки по Flow Builder**: Два новых руководства охватывают построение навигации между экранами флоу и настройку состояний элементов — выбранного, активного и отключённого. [Навигация во флоу](onboarding-navigation-branching) | [Состояния элементов](builder-element-states) - **Документация на японском и вьетнамском языках**: Документация Adapty теперь доступна на японском (日本語) и вьетнамском (Tiếng Việt) языках. Переключайте языки с помощью селектора в верхней навигации. ## Май 2026 \{#may-2026\} - **Флоу (бета)**: Создавайте целые последовательности экранов в визуальном no-code конструкторе — одноэкранные пейволы, многошаговые онбординги и всё, что между ними, — всё в одном флоу. Экраны рендерятся нативно без веб-вью, а обновлять тексты, дизайн и логику можно без выпуска нового релиза приложения. Поддерживаются iOS, Android, React Native, Flutter и Capacitor SDK версии 4 и выше. [Подробнее](adapty-flow-builder) - **Autopilot теперь адаптируется к результатам тестов**: Выступая в роли AI-менеджера по росту, он обновляет план роста после каждого завершённого раунда. Следующая гипотеза строится на основе того, какие эксперименты уже проведены, какие из них выиграли и какие направления ещё стоит исследовать — вместо следования фиксированной последовательности. [Узнать больше](autopilot-how-it-works#how-ai-growth-advisor-decides-what-to-recommend) - **Activation ARPU в Autopilot Market Insights**: Новый график сравнивает средний доход с одной новой установки вашего приложения со средним значением по категории. Используйте его вместе с воронкой конверсии — высокая конверсия при низком Activation ARPU может указывать на заниженную цену офферов. [Подробнее](autopilot-analysis#activation-arpu) - **Аналитика в Adapty Mail**: Сравнивайте метрики доставки и выручку, атрибутированную письмам, для каждой кампании в одном представлении. Группируйте, детализируйте и фильтруйте по кампании, сегменту, варианту A/B-теста, сообщению или триггеру, а затем переходите к любой строке для детального анализа. [Подробнее](mail-analytics) - **Профиль бренда в Adapty Mail**: Единый профиль, который определяет текст писем, тон, визуальное оформление и контент веб-пейвола. Adapty формирует его на основе страницы вашего приложения в сторе, лендинга, юридических страниц и профилей в соцсетях — вы можете просматривать и редактировать каждый раздел прямо на месте. [Узнать больше](mail-brand) - **Прогнозы в Adapty UA**: прогнозируемый доход, ROAS, прибыль от рекламы, ARPU и ARPPU для каждой когорты — чтобы сравнивать кампании до того, как они успеют созреть. Прогнозы строятся на основе исторических данных когорт вашего приложения, обновляются ежедневно и доступны для периодов когорт от D0 до D360 или любого произвольного дня. [Подробнее](ua-predicted-metrics) - **Новые поля в кастомном S3-экспорте Adapty UA**: Теперь кастомный S3-экспорт включает поля `bundle_id`, `device_brand`, `device_model`, `os_version`, `app_version` и `sdk_version`. Сегментируйте и объединяйте данные атрибуции по устройству и версии приложения на стороне получателя. [Подробнее](ua-custom-s3) - **Аудитории плейсментов в CLI**: Команды `adapty placements create` и `adapty placements update` теперь поддерживают флаг `--audiences` — JSON-массив из записей `{segment_ids, paywall_id, priority}` — с его помощью можно нацеливать разные пейволы на разные сегменты прямо из терминала. Новая команда `adapty paywalls placements` выводит список всех плейсментов, в которых используется заданный пейвол, чтобы вы могли оценить последствия замены ещё до её применения. [Подробнее](developer-cli-reference#placements) - **Документация на испанском языке**: Документация Adapty теперь доступна на испанском языке (Español). Переключить язык можно с помощью селектора языка в верхней навигации. ## Апрель 2026 \{#april-2026\} - **Adapty Mail**: AI-генерируемые email-кампании, которые превращают пользователей триала в платных подписчиков. Создавайте, отправляйте и отслеживайте атрибуцию кампаний прямо из вашего проекта в Adapty — без отдельной email-платформы. [Подробнее](adapty-mail) - **Диагностика пейвола в Autopilot**: узнайте, что нужно улучшить на пейволе, ещё до того, как запускать тест. Загрузите скриншот — Autopilot вернёт рекомендации на основе бенчмарков лучших приложений в вашей категории, а также AI-предложения по макету и тексту. Рекомендации на основе бенчмарков становятся раундами A/B-тестов в вашем плане роста. [Подробнее](autopilot-analysis#paywall-analysis) - **Более понятные рекомендации для каждого предложения Autopilot**: Теперь каждая гипотеза содержит объяснение того, почему это важно (анализ на основе данных о том, как ваш пейвол отклоняется от устоявшихся паттернов), что нужно изменить и как настроить A/B-тест, а также какие метрики отслеживать — в новом разделе «Как интерпретировать результаты». [Подробнее](autopilot-execute-plan#step-1-view-the-hypothesis) - **Поддерживайте актуальность плана роста Autopilot**: Обновляйте анализ, чтобы получать свежие рыночные данные и новые предложения, и при необходимости обращайтесь к предыдущим версиям в истории версий. Гипотезы сгруппированы по вкладкам: Top priority, All, Pricing, Visual, Geo-pricing и Archived. [Подробнее](autopilot-growth-plan) - **Распределение выручки по длительности в Autopilot**: Посмотрите, не сконцентрирована ли ваша выручка в одной длительности подписки. На новом графике Market Insights отображается ваш доход по длительностям рядом со среднеотраслевым показателем для вашей категории и страны. [Подробнее](autopilot-analysis#revenue-distribution-by-duration) - **Обновлённые прогнозы LTV и дохода**: прогнозируемые LTV и доход теперь используют данные когортного удержания вашего приложения при наличии достаточной истории, а в остальных случаях — средние значения по другим приложениям. Так даже новые приложения получают полезные прогнозы в аналитике и A/B-тестах. [Подробнее](predicted-ltv-and-revenue) - **Отправка всех событий в Adapty UA**: Дайте Meta и TikTok полную картину конверсий для более точного моделирования аудиторий. Adapty теперь поддерживает пересылку установок и транзакций от органических и неатрибутированных пользователей в ваш пиксель, а не только от пользователей, привязанных к кампании. [Meta](ua-facebook#send-all-events) | [TikTok](ua-tiktok#send-all-events) - **Документация на русском и турецком**: Документация Adapty теперь доступна на русском (Русский) и турецком (Türkçe) языках. Переключайте язык с помощью селектора языка в верхней навигации. ## Март 2026 \{#march-2026\} - **Developer CLI**: Управляйте аккаунтом Adapty прямо из терминала, не открывая дашборд. CLI позволяет создавать приложения, задавать уровни доступа, настраивать продукты, создавать пейволы и конфигурировать плейсменты — всё это поддаётся автоматизации в скриптовых окружениях. Также доступен [Adapty CLI skill](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) для AI-ассистентов, помогающий им работать с CLI. [Подробнее](developer-cli) - **Обзорная страница в Apple Ads Manager**: все ключевые метрики Apple Ads в одном месте, каждая с графиком тренда. Фильтруйте по приложению через выпадающий список в шапке, настраивайте набор метрик, тип графика и отображение выручки. [Подробнее](ads-manager-overview) - **Market Intelligence в Apple Ads Manager**: смотрите, по каким ключевым словам конкуренты запускают рекламу в 50+ странах, и добавляйте лучшие ключевые слова прямо в свои кампании. [Подробнее](ads-manager-market-intelligence) - **Полная автоматизация управления ключевыми словами в Apple Ads Manager**: автоматически корректируйте ставки, приостанавливайте или активируйте ключевые слова и перемещайте их между группами объявлений на основе заданных вами правил эффективности. [Подробнее](ads-manager-automations-keyword-rules) - **История ставок в Apple Ads Manager**: просматривайте полный журнал изменений ставки CPT для любого ключевого слова — когда произошло каждое изменение, предыдущее и новое значения, а также какое правило автоматизации его вызвало. [Подробнее](ads-manager-manage-keywords#bid-history) - **Визуальные раунды в Autopilot**: предложения по дизайну пейвола теперь являются полноценными раундами в вашем плане роста — они отображаются в боковой панели рядом с монетизационными раундами. Каждый визуальный раунд включает макет дизайна, описание ситуаций, в которых этот паттерн работает лучше всего, и ключевые метрики, на которые он влияет. [Подробнее](autopilot-growth-plan#view-the-growth-plan) - **Добавляйте собственные гипотезы в Autopilot**: расширяйте план роста кастомными раундами. Укажите название, описание, тип раунда (монетизация или визуальный), целевые метрики, а для монетизационных раундов — задействованные продукты. [Подробнее](autopilot-growth-plan#add-your-own-hypothesis) - **Меняйте порядок раундов Autopilot**: перетаскивайте этапы плана роста и выстраивайте их в том порядке, который лучше всего соответствует вашей стратегии. [Подробнее](autopilot) - **Гео-прайсинг раунды в Autopilot**: Тестируйте изменения цен для отдельных стран как новый тип раунда в плане роста. На основе данных Market Insights Autopilot рекомендует, повысить, снизить или оставить цены без изменений в каждой стране. Добавьте рекомендацию как раунд гео-прайсинга, чтобы запустить её как A/B-тест — одновременно можно запускать до 5 раундов. [Подробнее](autopilot-growth-plan#geo-pricing-hypotheses) - **Автоматизация поисковых запросов в Apple Ads Manager**: Автоматически продвигайте выигрышные поисковые запросы в ключевые слова с точным совпадением и исключайте их из источника — без ручной загрузки отчётов. Правила можно создавать из шаблонов или строить с нуля с произвольными условиями и расписанием. [Подробнее](ads-manager-automations-search-terms) - **Maximize Conversions bidding в Apple Ads Manager**: При создании кампаний теперь можно выбрать стратегию ставок Maximize Conversions. Алгоритм Apple максимизирует количество загрузок в рамках вашего бюджета с учётом опционального целевого CPA. [Подробнее](ads-manager-create-campaign) - **Интеграция FunnelFox в Adapty UA**: В Adapty UA доступна новая интеграция с FunnelFox. [FunnelFox](ua-funnelfox) - **Документация на китайском**: Документация Adapty теперь доступна на китайском языке (中文). Переключайте языки с помощью селектора в верхней навигации. ## Февраль 2026 \{#february-2026\} - **Цены на продукты по странам**: устанавливайте разные цены для каждой страны прямо в дашборде Adapty — Adapty автоматически синхронизирует изменения с App Store Connect и Google Play. Каждое обновление цены фиксируется в журнале аудита, так что ни одно изменение не останется незамеченным. [Подробнее](edit-product) - **Цены конкурентов по странам в Autopilot**: сравнивайте цены своих подписок с ценами конкурентов на ключевых рынках. [Подробнее](autopilot-analysis#market-and-competitor-analysis) - **Контроль версий онбординга**: Отслеживайте версии онбордингов и управляйте ими с полной историей изменений. Просматривайте правки и откатывайтесь при необходимости. - **Графики конверсии пейволов в аналитике**: Два новых графика конверсии — Paywall view → Trial и Paywall view → Paid — показывают, как ваши пейволы конвертируют посетителей в подписчиков. [Подробнее](analytics-conversion) - **Дублирование сегментов**: Копируйте существующий сегмент со всеми его фильтрами, не создавая похожий с нуля. Удобно при запуске нескольких кампаний или A/B-тестов с пересекающимися аудиториями. [Подробнее](segments#duplicate-segments) - **Push-уведомления в мобильном приложении Adapty**: Настраивайте push-уведомления для 14 типов событий прямо в iOS-приложении Adapty, чтобы следить за активностью подписок, не открывая дашборд. [Подробнее](push-notifications) - **Kotlin Multiplatform SDK 3.15**: Добавлена поддержка онбординга, веб-пейволов и улучшения API. [Подробнее](migration-to-kmp-315) - **Capacitor SDK 3.16**: Добавлена поддержка Capacitor 8. Проекты на Capacitor 7 следует оставить на SDK v3.15. [Подробнее](migration-to-capacitor-316) - **Гайды по интеграции SDK с помощью LLM**: Пошаговые гайды по интеграции Adapty с помощью AI-ассистентов. Каждый гайд проведёт вашу LLM через полную реализацию — от настройки дашборда до покупок. [iOS](adapty-cursor) | [Android](adapty-cursor-android) | [React Native](adapty-cursor-react-native) | [Flutter](adapty-cursor-flutter) | [Unity](adapty-cursor-unity) | [Kotlin Multiplatform](adapty-cursor-kmp) | [Capacitor](adapty-cursor-capacitor). Для автоматического флоу в одну команду попробуйте новый **adapty-sdk-integration skill** (бета): [iOS](adapty-sdk-integration-skill) | [Android](adapty-sdk-integration-skill-android) | [React Native](adapty-sdk-integration-skill-react-native) | [Flutter](adapty-sdk-integration-skill-flutter) | [Unity](adapty-sdk-integration-skill-unity) | [Kotlin Multiplatform](adapty-sdk-integration-skill-kmp) | [Capacitor](adapty-sdk-integration-skill-capacitor) ## Январь 2026 \{#january-2026\} - **Capacitor SDK официально выпущен**: Capacitor SDK теперь готов к использованию в продакшне после масштабного тестирования. Создавайте приложения с подписками для iOS и Android на базе Capacitor с полной поддержкой интеграции Adapty. [Подробнее](capacitor-sdk-overview) - **Autopilot для новых приложений**: Анализ Autopilot теперь доступен даже если у вашего приложения ещё нет обширной истории транзакций. Получайте рекомендации по оптимизации цен на основе данных и стройте план роста с первого дня. [Подробнее](autopilot) - **Глобальные возможности ценообразования в Autopilot**: выявляйте потенциал роста выручки на ваших ключевых рынках с помощью рекомендаций по ценам для отдельных стран. Autopilot анализирует конверсию и покупательную способность для пяти наиболее перспективных стран и на основе индекса Adapty Pricing Index даёт рекомендации: повысить, снизить или оставить цены без изменений. [Подробнее](autopilot) - **Метрики конверсии при восстановлении оплаты**: Новые графики аналитики отслеживают доход, восстановленный после проблем с оплатой и льготных периодов. Отслеживайте «Billing issue converted», «Billing issue converted revenue», «Grace period converted» и «Grace period converted revenue», чтобы оценивать эффективность удержания пользователей. - **Прямое управление рекламой в Apple Ads Manager**: Создавайте и управляйте кампаниями Apple Ads прямо внутри Adapty, не переключаясь между платформами. [Подробнее](ads-manager-manage-ads) - **Аналитика Apple Ads Manager**: Получите доступ к подробным метрикам эффективности на уровне объявлений и данным атрибуции в Adapty. Просматривайте эффективность кампаний, аналитику групп объявлений и данные атрибуции в едином дашборде. [Подробнее](adapty-ads-manager-analytics) - **Графики атрибуции Apple Ads**: Объединяйте несколько метрик атрибуции в настраиваемых графиках для анализа эффективности Apple Ads вместе с данными по подпискам. [Подробнее](adapty-ads-manager-analytics#charts) - **Сегменты на основе данных атрибуции Apple Ads**: Создавайте сегменты пользователей на основе данных атрибуции Apple Ads — всего два клика. Таргетируйте пользователей по кампании, группе объявлений или ключевому слову для более точного анализа и экспериментов. [Подробнее](ads-manager-create-segments) - **Новая платформа документации**: Сайт документации переехал на новую платформу — теперь функции обновляются быстрее, а работать с документацией стало удобнее: улучшен поиск, навигация и структура контента. ## Декабрь 2025 \{#december-2025\} - **Документация Apple Ads Manager**: Совместите данные рекламных кампаний Apple Search Ads с метриками выручки в едином дашборде аналитики. Новая документация охватывает создание кампаний, управление группами объявлений и способы отслеживания ROI рекламных расходов вместе с показателями подписок. [Подробнее](ads-manager) - **Встроенные веб-пейволы**: Показывайте веб-пейволы прямо в приложении через встроенный браузер — без переходов во внешние ссылки. [iOS](ios-web-paywall#open-web-paywalls-in-an-in-app-browser) | [Android](android-web-paywall#open-web-paywalls-in-an-in-app-browser) | [React Native](react-native-web-paywall#open-web-paywalls-in-an-in-app-browser) | [Flutter](flutter-web-paywall#open-web-paywalls-in-an-in-app-browser) - **Скользящие сегменты**: Создавайте динамические сегменты аудитории, которые автоматически обновляются на основе скользящих временных окон. Например, можно создать сегмент «пользователи, установившие приложение за последние 7 дней» — он будет постоянно обновляться и всегда отражать самых новых клиентов. [Подробнее](segments#available-attributes) - **Гайды по настройке кампаний в Meta и TikTok**: Пошаговые инструкции по созданию и отслеживанию кампаний в Meta (Facebook и Instagram) и TikTok с настройкой отслеживания конверсий и интеграцией аналитики. [Meta](meta-create-campaign) | [TikTok](tiktok-create-campaign) - **Гайды по быстрому старту для ручной реализации пейволов**: Интегрируйте встроенные покупки быстрее с помощью пошаговых гайдов по интеграции SDK Adapty в ваш собственный UI пейвола. [iOS](ios-implement-paywalls-manually) | [Android](android-implement-paywalls-manually) | [React Native](react-native-implement-paywalls-manually) | [Flutter](flutter-implement-paywalls-manually) | [Unity](unity-implement-paywalls-manually) | [Kotlin Multiplatform](kmp-quickstart-manual) | [Capacitor](capacitor-quickstart-manual) - **Встроенный браузер для ссылок в онбордингах**: Внешние ссылки в онбордингах теперь по умолчанию открываются во встроенном браузере, не уводя пользователей из приложения. При необходимости можно настроить открытие в стороннем браузере. [iOS](ios-present-onboardings#customize-how-links-open-in-onboardings) | [Android](android-present-onboardings#customize-how-links-open-in-onboardings) | [React Native](react-native-present-onboardings#customize-how-links-open-in-onboardings) - **Улучшенные подсказки Autopilot**: Autopilot теперь даёт более точные рекомендации по оптимизации цен на основе углублённого анализа данных о подписках. [Попробуйте Autopilot](autopilot) - **Тёмная тема документации**: В документации теперь поддерживается тёмная тема — она переключается автоматически по системным настройкам или вручную в правом верхнем углу. --- # File: adapty-ecosystem --- --- title: "Экосистема Adapty" description: "Adapty — платформа для встроенных покупок в мобильных приложениях. Узнайте, что делает каждый продукт и как они связаны между собой." --- Adapty — платформа для встроенных покупок в мобильных приложениях, созданная с единой целью: сделать приложения прибыльными. Здесь есть всё для роста дохода: привлечение пользователей, их конвертация, удержание подписчиков и возврат тех, кто ушёл. Одна регистрация открывает доступ ко всей экосистеме Adapty с первого дня. Просто нажмите на логотип Adapty, чтобы переключаться между продуктами: - **Core** — обрабатывайте покупки без StoreKit и Google Play Billing, создавайте пейволы без кода и отслеживайте выручку в реальном времени. Остальные продукты строятся на этой основе. - **Adapty Ads Manager** — запускайте и оптимизируйте Apple Ads, ориентируясь на реальную выручку от подписок. - **Adapty Attribution** — узнайте, какие рекламные каналы действительно приносят доход, без MMP. - **Adapty Mail** — конвертируйте триалы и возвращайте ушедших пользователей с помощью автоматических email-рассылок. Ещё два продукта дополняют основную четвёрку: **FunnelFox** (воронки web-to-app и размещённый чекаут) и **Adapty Finance** (авансы в счёт будущей выручки от подписок). ## Как продукты связаны друг с другом \{#how-the-products-fit-together\} Каждый продукт взаимодействует с пользователем на определённом этапе жизненного цикла. Наведите курсор на любой выделенный элемент, чтобы увидеть краткое определение, или перейдите по ссылке к документации.
3. В открывшемся окне **Generate In-App Purchase Key** введите название ключа для вашего удобства. В Adapty оно использоваться не будет.
4. Нажмите кнопку **Generate**. После закрытия окна **Generate in-App Purchase Key** созданный ключ появится в списке **Active**.
5. После генерации API-ключа нажмите кнопку **Download In-App Purchase Key**, чтобы скачать ключ в виде файла.
6. В окне **Download in-App Purchase Key** нажмите кнопку **Download**. Файл будет сохранён на вашем компьютере.
Храните этот файл в надёжном месте — он понадобится для последующей загрузки в дашборд Adapty. Обратите внимание: сгенерированный файл можно скачать только один раз, поэтому убедитесь в его сохранности до момента загрузки. Сгенерированный .p8-ключ из раздела **In-App Purchase** будет использоваться при [настройке начальной интеграции Adapty с App Store](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file).
**Что дальше:**
- [Настройка интеграции с App Store](app-store-connection-configuration)
---
# File: app-store-connection-configuration
---
---
title: "Настройка интеграции с App Store"
description: "Настройте подключение к App Store для удобного отслеживания подписок."
---
3. Скопируйте **Issuer ID** и вставьте его в поле **In-app purchase Issuer ID** в дашборде Adapty.
4. Скопируйте **Key ID** и вставьте его в поле **In-app purchase Key ID** в дашборде Adapty.
## Шаг 3. Загрузите файл In-App Purchase Key \{#step-3-upload-in-app-purchase-key-file\}
Загрузите файл **In-App Purchase Key**, скачанный в разделе [Создание In-App Purchase Key в App Store Connect](generate-in-app-purchase-key),
в поле **Private key (.p8 file)** в дашборде Adapty.
## Шаг 4. Для пробных периодов и специальных предложений — настройте promotional offers \{#step-4-for-trials-and-special-offers--set-up-promotional-offers\}
:::important
Этот шаг обязателен, если в вашем приложении есть [пробные периоды или другие promotional offers](offers).
:::
1. Скопируйте тот же Key ID, который вы использовали на [Шаге 2](#step-2-provide-issuer-id-and-key-id), в поле **Subscription key ID** в разделе **App Store promotional offers**.
2. Загрузите тот же файл **In-App Purchase Key**, который вы использовали на [Шаге 3](#step-3-upload-in-app-purchase-key-file), в область **Subscription key (.p8 file)** в разделе **App Store promotional offers**.
## Шаг 5. Введите общий секрет App Store \{#step-5-enter-app-store-shared-secret\}
**App Store shared secret**, также известный как App Store Connect Shared Secret, — это 32-символьная шестнадцатеричная строка, используемая для встроенных покупок и валидации чеков подписки.
1. Откройте [App Store Connect](https://appstoreconnect.apple.com/apps). Выберите своё приложение и перейдите в раздел **General** → **App Information**.
2. Прокрутите вниз до подраздела **App-Specific Shared Secret**.
:::info
Если подраздел **App-Specific Shared Secret** отсутствует, убедитесь, что у вас есть роль Account Holder или Admin. Если у вас роль Admin, но подраздел всё равно не отображается, попросите Account Holder приложения (того, кто создал приложение в App Store Connect) сгенерировать App Store Shared Secret для приложения. После этого подраздел станет видим и для Admins.
:::
3. Нажмите кнопку **Manage**.
4. В открывшемся окне **App-Specific Shared Secret** скопируйте **Shared Secret**. Если общий секрет не отображается, сначала нажмите кнопку **Manage** или **Generate** (в зависимости от того, какая доступна), а затем скопируйте **Shared Secret**.
5. Вставьте скопированный **Shared Secret** в поле **App Store shared secret** в дашборде Adapty.
6. Нажмите кнопку **Save** в дашборде Adapty, чтобы сохранить изменения.
## Шаг 6. Добавьте ключ App Store Connect API \{#step-6-add-app-store-connect-api-key\}
Создайте ключ App Store Connect API и добавьте его в Adapty, чтобы [управлять продуктами в App Store прямо из дашборда Adapty](create-product#create-product-and-push-to-store):
1. В App Store Connect перейдите в [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api) и нажмите **+**.
2. В окне **Generate API key window** введите имя ключа и предоставьте ему доступ уровня **Admin**.
3. Нажмите **Download** рядом с ключом. Обратите внимание, что скачать его можно только один раз.
4. В дашборде Adapty перейдите в [**App settings > iOS SDK**](https://app.adapty.io/settings/ios-sdk) и нажмите **Connect API key**.
5. Заполните поля в открывшемся окне:
- **Issuer ID**: скопируйте из [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api). Он находится над таблицей **API keys**.
- **Key ID**: Скопируйте из [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api). Он находится в таблице **API keys** рядом с вашим ключом.
- **API key**: Загрузите файл API-ключа, скачанный из App Store Connect.
6. Нажмите **Connect**.
**Что дальше**
- [Включить серверные уведомления App Store](enable-app-store-server-notifications)
---
# File: enable-app-store-server-notifications
---
---
title: "Включение уведомлений сервера App Store"
description: "Включите уведомления сервера App Store для отслеживания событий подписки в режиме реального времени."
---
Настройка уведомлений сервера App Store необходима для обеспечения точности данных: они позволяют получать обновления из App Store в режиме реального времени, включая информацию о возвратах средств и других событиях.
:::important
Для полной поддержки App Store Server Notifications V2 требуется Adapty iOS SDK версии 2.10.0 или выше.
:::
1. Скопируйте **URL for App Store server notification** в дашборде Adapty.
2. Откройте [App Store Connect](https://appstoreconnect.apple.com/apps). Выберите приложение и перейдите в раздел **General** → **App Information**, подраздел **App Store Server Notifications**.
3. Вставьте скопированный **URL for App Store server notification** в поля **Production Server URL** и **Sandbox Server URL**.
## Пересылка необработанных событий \{#raw-events-forwarding\}
Иногда вам всё равно может понадобиться получать необработанные S2S-события от Apple. Чтобы продолжать их получать при использовании Adapty, просто добавьте свой endpoint в поле **URL for forwarding raw Apple events** — мы будем пересылать события в том виде, в котором получаем их от Apple.
**Что дальше**
Настройте SDK Adapty для:
- [iOS](sdk-installation-ios)
- [React Native](sdk-installation-reactnative)
- [Flutter](sdk-installation-flutter)
- [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)
- [Unity](sdk-installation-unity)
---
# File: troubleshoot-app-store-integration
---
---
title: "Устранение неполадок интеграции App Store"
description: "Решение распространённых проблем с настройкой Apple App Store — незакрытые соглашения, задержки серверных уведомлений и расхождения цен."
---
В этой статье описаны распространённые проблемы с интеграцией App Store. В каждом разделе указаны симптомы, причина и способ решения.
## Продукты не отображаются \{#products-dont-appear\}
Оба симптома указывают на одну и ту же причину:
- API-ключ App Store Connect настроен правильно, но Adapty не может получить продукты.
- Продукты есть в App Store Connect, но в Adapty они не отображаются — или отображаются не все. При попытке покупки SDK сообщает «Product Id not found».
Наиболее частая причина — **неподписанные соглашения Apple**: платное соглашение, налоговые формы или банковские реквизиты в статусе ожидания или не подписаны. Когда соглашения не подписаны, App Store Connect API молча возвращает 403 на запросы к продуктовым эндпоинтам. Никакой явной ошибки Adapty не видит — продукты просто отфильтровываются без предупреждения.
Перейдите в **App Store Connect → Agreements, Tax, and Banking** и подпишите все ожидающие соглашения. Затем выполните повторную синхронизацию в разделе **App settings → iOS SDK** дашборда Adapty.
## Уведомления App Store Server Notifications отображаются как «Delayed» \{#app-store-server-notifications-show-delayed\}
В App Store Connect статус уведомлений App Store Server Notifications может отображаться как **Delayed**. Это означает, что Apple задерживает отправку уведомлений о событиях подписки — продления, отмены и проблемы с оплатой ставятся в очередь и поступают с опозданием.
На статистику установок это не влияет. Adapty считает установки с первого запуска приложения, а не на основе серверных уведомлений.
Если данные о продлениях или отменах запаздывают, статус Delayed — наиболее вероятная причина. Обычно он устраняется автоматически по мере того, как Apple обрабатывает накопившуюся очередь.
## Цены в Adapty не совпадают с App Store \{#prices-in-adapty-dont-match-app-store\}
Поле **price** на странице редактирования продукта в Adapty ведёт себя по-разному в зависимости от того, как продукт был добавлен.
Если вы создаёте продукт в Adapty и публикуете его в сторе через дашборд, эта цена используется как начальная цена в сторе.
Если вы добавляете продукт, который уже существует в сторе, эта цена является заглушкой. Аналитика, интеграции и SDK Adapty используют реальные цены, полученные из App Store. Изменения цен в App Store не синхронизируются и не обновляют заглушку, и на данный момент отредактировать её через дашборд нельзя.
## CSV-экспорт цен пуст \{#csv-price-export-is-empty\}
Если CSV-экспорт цен вернул только заголовки столбцов, значит ключ API App Store Connect настроен не полностью. См. [Шаг 6 — Добавьте ключ API App Store Connect](app-store-connection-configuration#step-6-add-app-store-connect-api-key).
## Не получается отправить новые продукты в App Store \{#cant-push-new-products-to-app-store\}
Adapty может автоматически отправлять новые продукты в App Store Connect при их создании в дашборде. Эта возможность недоступна, если интеграция с App Store настроена не полностью. Необходимы два параметра:
- **Apple app ID**: настройте в [Шаг 1 — Укажите Bundle ID и Apple app ID](app-store-connection-configuration#step-1-provide-bundle-id-and-apple-app-id).
- **App Store Connect API key**: настройте в [Шаг 6 — Добавьте ключ App Store Connect API](app-store-connection-configuration#step-6-add-app-store-connect-api-key).
---
# File: enabling-of-devepoler-api
---
---
title: "Включение Developer APIs в Google Play Console"
description: "Включите Developer API от Adapty для автоматизации управления подписками в вашем приложении."
---
3. Откройте страницу [**Google Play Android Developer API**](https://console.cloud.google.com/apis/library/androidpublisher.googleapis.com).
4. Нажмите кнопку **Enable** и дождитесь появления статуса **Enabled**. Это означает, что Google Android Developer API включён.
5. Откройте страницу [**Google Play Developer Reporting API**](https://console.cloud.google.com/apis/library/playdeveloperreporting.googleapis.com).
6. Нажмите кнопку **Enable** и дождитесь появления статуса **Enabled**.
7. Откройте страницу [**Cloud Pub/Sub API**](https://console.cloud.google.com/marketplace/product/google/pubsub.googleapis.com).
8. Нажмите кнопку **Enable** и дождитесь появления статуса **Enabled**.
Developer APIs включены.
Проверить это можно на странице [**APIs & Services**](https://console.cloud.google.com/apis/dashboard) в Google Cloud Console. Прокрутите страницу вниз и убедитесь, что в таблице в нижней части страницы присутствуют все 3 API:
- Google Play Android Developer API
- Google Play Developer Reporting API
- Cloud Pub/Sub API
**Что дальше**
- [Создание сервисного аккаунта в Google Cloud Console](create-service-account)
---
# File: create-service-account
---
---
title: "Создание сервисного аккаунта в Google Cloud Console"
description: "Узнайте, как создать сервисный аккаунт для безопасного доступа к API в Adapty."
---
Чтобы Adapty мог автоматически получать данные, в Google Play Console необходим сервисный аккаунт.
1. Откройте раздел [**IAM & Admin** -> **Service accounts**](https://console.cloud.google.com/iam-admin/serviceaccounts) в Google Cloud Console. Убедитесь, что выбран нужный проект.
2. В окне **Service accounts** нажмите кнопку **Create service account**.
3. В подразделе **Service account details** окна **Create service account** введите желаемое имя в поле **Service Account Name**. Рекомендуем включить в него слово «Adapty», чтобы было понятно назначение аккаунта. Поле **Service account ID** заполнится автоматически.
4. Скопируйте адрес электронной почты сервисного аккаунта и сохраните его для дальнейшего использования.
5. Нажмите кнопку **Create and continue**.
6. В выпадающем списке **Select a role** подраздела **Grant this service account access to project** выберите **Pub/Sub -> Pub/Sub Admin**. Эта роль необходима для включения уведомлений разработчика в реальном времени.
7. Нажмите кнопку **Add another role**.
8. В появившемся выпадающем списке **Role** выберите **Monitoring -> Monitoring Viewer**. Эта роль необходима для мониторинга очереди уведомлений.
9. Нажмите кнопку **Continue**.
10. Нажмите кнопку **Done**, не внося никаких изменений. Откроется окно **Service accounts**.
**Что дальше**
- [Предоставьте разрешения сервисному аккаунту в Google Play Console](grant-permissions-to-service-account)
---
# File: grant-permissions-to-service-account
---
---
title: "Предоставление прав сервисному аккаунту в Google Play Console"
description: "Предоставьте права сервисным аккаунтам для безопасного и эффективного доступа через API."
---
Предоставьте необходимые права сервисному аккаунту, который Adapty будет использовать для управления подписками и валидации покупок.
1. Откройте страницу [**Users and permissions**](https://play.google.com/console/u/0/developers/8970033217728091060/users-and-permissions) в Google Play Console и нажмите кнопку **Invite new users**.
2. На странице **Invite user** введите email сервисного пользователя, которого вы создали.
3. Перейдите на вкладку **Account permissions**.
4. Выберите следующие права:
- View app information and download bulk reports (read-only)
- View financial data, orders, and cancellation survey responses
- Manage orders and subscriptions
- Manage store presence
5. Нажмите кнопку **Invite user**.
6. В окне **Send invite?** нажмите кнопку **Send invite**. Сервисный аккаунт появится в списке пользователей.
**Что дальше**
- [Создайте файл ключа сервисного аккаунта в Google Play Console](create-service-account-key-file)
---
# File: create-service-account-key-file
---
---
title: "Создание файла ключа сервисного аккаунта в Google Play Console"
description: "Узнайте, как создать файл ключа сервисного аккаунта для интеграции с Adapty."
---
Чтобы связать мобильное приложение в Play Store с Adapty, нужно создать специальные файлы ключей сервисного аккаунта в Google Play Console и загрузить их в Adapty. Эти файлы обеспечивают безопасность приложения и защищают его от несанкционированного доступа.
:::warning
Обычно новый сервисный аккаунт становится активным не раньше чем через 24 часа. Однако есть [лайфхак](https://stackoverflow.com/a/60691844). После создания сервисного аккаунта в [Google Play Console](https://play.google.com/apps/publish/) откройте любое приложение и перейдите в **Monetize** -> **Products** -> **Subscriptions/In-app products**. Отредактируйте описание любого продукта и сохраните изменения. Это должно активировать сервисный аккаунт сразу, а изменения после этого можно откатить.
:::
1. Откройте раздел [**Service accounts**](https://console.cloud.google.com/iam-admin/serviceaccounts) в Google Play Console. Убедитесь, что выбран нужный проект.
2. В открывшемся окне нажмите **Add key** и выберите **Create new key** в выпадающем меню.
3. В окне **Create private key for [Your_project_name]** нажмите **Create**. Приватный ключ будет сохранён на ваш компьютер в виде JSON-файла. Найти его можно по имени, указанному в окне **Private key saved to your computer**.
4. В окне **Create private key for Your_project_name** нажмите кнопку **Create**. Приватный ключ будет сохранён на ваш компьютер в виде JSON-файла. При необходимости найти его можно по имени, указанному в открывшемся окне **Private key saved to your computer**.
Этот файл понадобится вам при [настройке интеграции с Google Play Store](google-play-store-connection-configuration).
:::warning
Обычно новый сервисный аккаунт становится активным не раньше чем через 24 часа. Однако есть [лайфхак](https://stackoverflow.com/a/60691844). После создания сервисного аккаунта в [Google Play Console](https://play.google.com/apps/publish/) откройте любое приложение и перейдите в **Monetize** -> **Products** -> **Subscriptions/In-app products**. Отредактируйте описание любого продукта и сохраните изменения. Это должно активировать сервисный аккаунт сразу, а изменения после этого можно откатить.
:::
**Что дальше**
- [Настройка интеграции с Google Play Store](google-play-store-connection-configuration)
---
# File: google-play-store-connection-configuration
---
---
title: "Настройка интеграции с Google Play Store"
description: "Настройте подключение Google Play Store в Adapty для корректной обработки встроенных покупок."
---
В этом разделе описан процесс интеграции вашего мобильного приложения, распространяемого через Google Play, с Adapty. Вам нужно ввести данные конфигурации приложения из Play Store в дашборд Adapty. Этот шаг необходим для валидации покупок и получения обновлений подписок из Play Store в Adapty.
Вы можете выполнить этот процесс во время первоначального онбординга или внести изменения позже в разделе **App Settings** дашборда Adapty.
:::danger
Изменение конфигурации допустимо только до выпуска мобильного приложения с интегрированными пейволами Adapty. Изменения после релиза нарушат интеграцию, и пейволы перестанут отображаться в вашем приложении.
:::
## Шаг 1. Укажите Package name \{#step-1-provide-package-name\}
Package name — это уникальный идентификатор вашего приложения в Google Play Store. Он необходим для базовой функциональности Adapty, например для обработки подписок.
1. Откройте [Google Play Developer Console](https://play.google.com/console/u/0/developers).
2. Выберите приложение, ID которого вам нужен. Откроется окно **Dashboard**.
3. Найдите идентификатор продукта под названием приложения и скопируйте его.
4. Откройте [**App settings**](https://app.adapty.io/settings/android-sdk) в верхнем меню Adapty.
5. На вкладке **Android SDK** окна **App settings** вставьте скопированный **Package name**.
## Шаг 2. Загрузите файл ключа аккаунта \{#step-2-upload-the-account-key-file\}
1. Загрузите файл закрытого ключа сервисного аккаунта в формате JSON, созданный на шаге [Создание файла ключа сервисного аккаунта](create-service-account), в поле **Service account key file**.
Не забудьте нажать кнопку **Save**, чтобы сохранить изменения.
**Что дальше**
- [Включите уведомления разработчика в реальном времени (RTDN) в Google Play Console](enable-real-time-developer-notifications-rtdn)
---
# File: enable-real-time-developer-notifications-rtdn
---
---
title: "Включение уведомлений в реальном времени (RTDN) в Google Play Console"
description: "Будьте в курсе важных событий и обеспечьте точность данных, включив уведомления в реальном времени (RTDN) в Google Play Console для Adapty. Узнайте, как настроить RTDN для получения мгновенных обновлений о возвратах и других событиях из Play Store"
---
Настройка уведомлений в реальном времени (RTDN) необходима для обеспечения точности данных: она позволяет мгновенно получать обновления из Play Store, включая информацию о возвратах и других событиях.
## Включение уведомлений \{#enable-notifications\}
1. Убедитесь, что **Google Cloud Pub/Sub** включён. Перейдите по [этой ссылке](https://console.cloud.google.com/flows/enableapi?apiid=pubsub) и выберите проект вашего приложения. Если вы ещё не включили **Google Cloud Pub/Sub**, сделайте это здесь.
2. Перейдите в [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) из верхнего меню Adapty и скопируйте содержимое поля **Enable Pub/Sub API** рядом с заголовком **Google Play RTDN topic name**.
:::note Если содержимое поля **Enable Pub/Sub API** имеет неправильный формат (правильный формат начинается с `projects/...`), обратитесь к разделу [Исправление неправильного формата в поле Enable Pub/Sub API](enable-real-time-developer-notifications-rtdn#fixing-incorrect-format-in-enable-pubsub-api-field) за помощью. ::: 3. Откройте [Google Play Console](https://play.google.com/console/), выберите своё приложение и перейдите в **Monetize with Play** -> **Monetization setup**. В разделе **Google Play Billing** установите флажок **Enable real-time notifications**. 4. Вставьте содержимое поля **Enable Pub/Sub API**, скопированное в **App Settings** Adapty, в поле **Topic name**. 5. Нажмите **Save changes** в Google Play Console.
## Тестирование уведомлений \{#test-notifications\}
Чтобы проверить, успешно ли вы подписались на уведомления в реальном времени:
1. Сохраните изменения в настройках Google Play Console.
2. В Google Play Console под полем **Topic name** нажмите **Send test notification**.
3. Перейдите в [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) в Adapty. Если тестовое уведомление было отправлено, вы увидите его статус над названием топика.
## Исправление неправильного формата в поле Enable Pub/Sub API \{#fixing-incorrect-format-in-enable-pubsub-api-field\}
Если содержимое поля **Enable Pub/Sub API** имеет неправильный формат (правильный формат начинается с `projects/...`), выполните следующие шаги для устранения проблемы:
### 1. Проверка активации API и прав доступа \{#1-verify-api-enablement-and-permissions\}
Убедитесь, что все необходимые API включены и права доступа к сервисному аккаунту настроены правильно. Даже если вы уже выполняли эти шаги, пройдите их повторно, чтобы не пропустить ни одного. Повторите шаги из следующих разделов:
1. [Включение API разработчика в Google Play Console](enabling-of-devepoler-api)
2. [Создание сервисного аккаунта в Google Cloud Console](create-service-account)
3. [Выдача прав сервисному аккаунту в Google Play Console](grant-permissions-to-service-account)
4. [Создание файла ключа сервисного аккаунта в Google Play Console](create-service-account-key-file)
5. [Настройка интеграции с Google Play Store](google-play-store-connection-configuration)
### 2. Изменение политик домена \{#2-adjust-domain-policies\}
Измените политики **Domain restricted contacts** и **Domain restricted sharing**:
1. Откройте [Google Cloud Console](https://console.cloud.google.com/) и выберите проект, в котором создан сервисный аккаунт для управления вашим приложением.
2. В разделе **Quick Access** выберите **IAM & Admin**.
3. На левой панели выберите **Organization Policies**.
4. Найдите политику **Domain restricted contacts**.
5. Нажмите кнопку с многоточием в столбце **Actions** и выберите **Edit policy**.
6. В окне редактирования политики:
1. В разделе **Policy source** выберите переключатель **Override parent's policy**.
2. В разделе **Policy enforcement** выберите переключатель **Replace**.
3. В разделе **Rules** нажмите кнопку **ADD A RULE**.
4. В разделе **New rule** -> **Policy values** выберите **Allow All**.
5. Нажмите **SET POLICY**.
7. Повторите шаги 4–6 для политики **Domain restricted sharing**.
После этого пересоздайте содержимое поля **Enable Pub/Sub API** рядом с заголовком **Google Play RTDN topic name**. Теперь поле будет в правильном формате.
Не забудьте вернуть **Policy source** в значение **Inherit parent's policy** для обновлённых политик после успешного включения уведомлений в реальном времени (RTDN).
## Переадресация необработанных событий \{#raw-events-forwarding\}
В некоторых случаях вам может потребоваться получать необработанные S2S-события от Google. Чтобы продолжать их получать при использовании Adapty, просто добавьте свой эндпоинт в поле **URL for forwarding raw Google events** — мы будем передавать события в том виде, в котором они приходят от Google.
---
**Что дальше**
Настройте Adapty SDK для:
- [Android](sdk-installation-android)
- [React Native](sdk-installation-reactnative)
- [Flutter](sdk-installation-flutter)
- [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)
- [Unity](sdk-installation-unity)
---
# File: stripe
---
---
title: "Начальная интеграция со Stripe"
description: "Интегрируйте Stripe с Adapty для бесперебойной обработки платежей по подпискам."
---
Adapty поддерживает web2app-флоу подписок, отслеживая веб-платежи и подписки, оформленные через [Stripe](https://stripe.com/).
Интеграция охватывает покупки, инициированные через веб (Stripe Checkout, hosted payment pages или кастомные веб-флоу), и синхронизирует их с доступом в мобильном приложении и аналитикой.
Она полезна в следующих сценариях:
- Автоматическое предоставление доступа к платным функциям пользователям, которые оплатили на сайте, а затем установили приложение и вошли в аккаунт
- Хранение всей аналитики подписок в едином дашборде Adapty (включая когорты, прогнозы и весь остальной аналитический инструментарий)
Несмотря на то что веб-покупки становятся всё популярнее для приложений, Apple App Store разрешает использование альтернативных платёжных систем вместо встроенных покупок только для цифровых товаров и только в США. Убедитесь, что вы не продвигаете веб-подписки внутри приложения для других стран — иначе приложение может быть отклонено или заблокировано.
Ниже описаны шаги по настройке интеграции со Stripe.
:::important
Эта интеграция ориентирована на отслеживание и синхронизацию веб-покупок через Stripe. Если вам нужно направить пользователей из приложения на веб-страницу оплаты, см. [Веб-пейволы](web-paywall).
:::
## 1\. Подключите Stripe к Adapty \{#1-connect-stripe-to-adapty\}
Интеграция в основном базируется на том, что Adapty получает данные о подписках от Stripe через вебхук. Поэтому нужно связать аккаунт Adapty с аккаунтом Stripe: предоставить API-ключи и настроить URL вебхука Adapty в Stripe. Чтобы автоматизировать настройку вебхука, установите приложение Adapty в Stripe:
:::note
Шаги ниже одинаковы как для Production-, так и для Test-режима Stripe, однако для каждого из них потребуются разные API-ключи.
:::
0. Определите, в каком режиме вы подключаете Stripe — тестовом или боевом. Если сначала вы настраиваете в тестовом режиме, шаги ниже нужно будет повторить и для боевого.
1. Перейдите в [Stripe App Marketplace](https://marketplace.stripe.com/apps/adapty) и установите приложение Adapty. Обратите внимание, что режим песочницы не поддерживает установку приложений — это можно сделать только в Production- или Test-режиме.
2. Выдайте приложению необходимые разрешения — это позволит Adapty получать доступ к данным и истории подписок. Затем нажмите **Continue to app settings**, чтобы продолжить.
В нижней части всплывающего окна с разрешениями можно выбрать, устанавливать приложение в Live- или Test-режиме.
3. Во всплывающем окне сгенерируйте новый ограниченный ключ. Для этого потребуется подтвердить личность через email, Touch ID или ключ безопасности. После генерации ключ больше не будет доступен для просмотра, поэтому сразу сохраните его в менеджере паролей или защищённом хранилище.
4. Скопируйте сгенерированный ключ из всплывающего окна и перейдите в [App Settings → Stripe](https://app.adapty.io/settings/stripe) в Adapty. Вставьте ключ в поле **Stripe App Restricted API Key** соответствующего режима. Обратите внимание, что для Test- и Live-режима нужны разные ключи.
Готово! Теперь создайте продукты в Stripe и добавьте их в Adapty.
2. Нажмите кнопку **Reveal live (test) key button** рядом с заголовком **Secret key**, скопируйте ключ и перейдите в [App Settings → Stripe](https://app.adapty.io/settings/stripe) в Adapty. Вставьте ключ туда:
3. Затем скопируйте URL вебхука из нижней части той же страницы в Adapty. Перейдите в [**Developers** → **Webhooks**](https://dashboard.stripe.com/webhooks) в Stripe и нажмите кнопку **Add endpoint**:
4. Вставьте URL вебхука из Adapty в поле **Endpoint URL**. Выберите **Latest API version** в поле **Version** вебхука. Затем выберите следующие события:
- charge.refunded
- customer.subscription.created
- customer.subscription.deleted
- customer.subscription.paused
- customer.subscription.resumed
- customer.subscription.updated
- invoice.created
- invoice.updated
- payment_intent.succeeded
5. Нажмите «Add endpoint», затем нажмите «Reveal» под разделом «Signing secret». Этот ключ используется для декодирования данных вебхука на стороне Adapty — скопируйте его после раскрытия:
6. Наконец, вставьте этот ключ в App Settings → Stripe в Adapty в поле «Stripe Webhook Secret»:
:::warning
На данный момент Adapty поддерживает только тарифы **Flat rate** ($9,99/месяц) и **Package pricing** ($9,99/10 единиц), так как они аналогичны моделям из сторов. Варианты **Tiered pricing**, **Usage-based fee** и **Customer chooses price** не поддерживаются.
:::
## 3\. Добавьте продукты Stripe в Adapty \{#3-add-stripe-products-to-adapty\}
:::warning
Продукты обязательны! Обязательно создайте продукты Stripe в дашборде Adapty. Adapty отслеживает события только для транзакций, связанных с этими продуктами, поэтому не пропускайте этот шаг — иначе события транзакций не будут создаваться.
:::
Мы относимся к Stripe так же, как к App Store и Google Play: это просто ещё один стор, где вы продаёте цифровые продукты. Настройка аналогична: просто добавьте продукты Stripe (а именно их `product_id` и `price_id`) в раздел Products в Adapty:
ID продуктов в Stripe выглядят как `prod_...`, а ID цен — как `price_...`. Их легко найти для каждого продукта в [Product Catalog](https://dashboard.stripe.com/products?active=true) в Stripe, открыв любой продукт:
После добавления всех необходимых продуктов следующий шаг — сообщить Stripe, какой пользователь совершает покупку, чтобы Adapty мог её зафиксировать.
## 4\. Обогатите покупки на сайте идентификатором пользователя \{#4-enrich-purchases-made-on-the-web-with-your-user-id\}
Adapty полагается исключительно на вебхуки от Stripe для предоставления и обновления уровней доступа пользователей. Однако для корректной работы интеграции вам нужно передавать дополнительную информацию со своей стороны при работе со Stripe.
Чтобы уровни доступа были согласованы на всех платформах (веб и мобайл), необходимо использовать единый идентификатор пользователя, который Adapty сможет распознать из вебхуков. Это может быть email пользователя, номер телефона или любой другой ID из вашей системы авторизации.
Определите, какой идентификатор вы хотите использовать для идентификации пользователей. Затем найдите в коде место, где инициируется платёж через Stripe, и добавьте этот идентификатор в объект `metadata` объекта [Stripe Subscription](https://docs.stripe.com/api/subscriptions/object#subscription_object-metadata) (`sub_...`) или [Checkout Session](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-metadata) (`ses_...`) как `customer_user_id`:
```json showLineNumbers title="Stripe Metadata contents"
{'customer_user_id': "YOUR_USER_ID"}
```
Это единственное дополнение в коде, которое вам нужно сделать. После этого Adapty будет разбирать все вебхуки от Stripe, извлекать `metadata` и корректно связывать подписки с вашими пользователями.
:::warning
Идентификатор пользователя обязателен
В противном случае у нас нет возможности сопоставить пользователя и предоставить ему уровень доступа на мобильном устройстве.
Если вы не передаёте `customer_user_id` в `metadata`, у вас будет возможность настроить Adapty так, чтобы он искал `customer_user_id` в других местах: в поле `email` объекта Customer в Stripe или в поле `client_reference_id` объекта Session в Stripe.
Подробнее о настройке поведения при создании профиля читайте [ниже](stripe#profile-creation-behavior).
:::
:::note
Объект Customer в Stripe также обязателен
Если вы используете Checkout Sessions, [убедитесь, что создаёте Customer в Stripe](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-customer_creation), установив `customer_creation` в значение `always`.
:::
## 5\. Предоставьте доступ пользователям на мобильном устройстве \{#5-provide-access-to-users-on-the-mobile\}
Чтобы мобильные пользователи, пришедшие с веба, могли получить доступ к платным функциям, просто вызовите `Adapty.activate()` или `Adapty.identify()` с тем же `customer_user_id`, который вы передали на предыдущем шаге (см.
2. Введите название ключа и установите срок его действия. Чтобы API-ключ работал с Adapty, необходимо предоставить ему разрешение **Read** для всех сущностей. Нажмите **Save**.
3. Нажмите **Copy key**.
4. В дашборде Adapty перейдите в [App Settings → Paddle](https://app.adapty.io/settings/paddle) и вставьте ключ в поле **Paddle API key**.
:::warning
Если вы задали срок действия для Paddle API key, вам нужно вручную сгенерировать новый ключ и обновить его в Adapty до истечения срока. Когда ключ истечёт, интеграция прекратит работу без каких-либо предупреждений, и пользователи не смогут совершать покупки.
:::
### 1.2. Добавьте события, которые будут отправляться в Adapty \{#12-add-events-that-will-be-sent-to-adapty\}
1. Скопируйте **Webhook URL** с той же страницы **Paddle** в Adapty.
2. В Paddle перейдите в [**Developer Tools → Notifications**](https://vendors.paddle.com/notifications-v2) и нажмите **New destination**, чтобы добавить вебхук.
3. Введите понятное название для вебхука. Рекомендуем включить в него «Adapty», чтобы легко найти его при необходимости.
4. Вставьте **Webhook URL** из Adapty в поле **URL**. Убедитесь, что используете вебхук для нужного окружения.
5. Установите **Notification type** в значение **Webhook**.
6. Выберите следующие события:
- `subscription.created`
- `subscription.updated`
- `transaction.created`
- `transaction.updated`
- `adjustment.created`
- `adjustment.updated`
7. Нажмите **Save destination**, чтобы завершить настройку вебхука.
### 1.3. Получите и добавьте секретный ключ webhook \{#retrieve-and-add-the-webhook-secret-key\}
1. В окне **Notifications** нажмите на три точки рядом с только что созданным webhook и выберите **Edit destination**.
2. В панели **Edit destination** появится новое поле **Secret key**. Скопируйте его.
3. В Adapty перейдите в [App Settings → Paddle](https://app.adapty.io/settings/paddle) и вставьте ключ в поле **Notification secret key**. Этот ключ используется для проверки данных вебхука в Adapty.
### 1.4. Сопоставление клиентов Paddle с профилями Adapty \{#14-match-paddle-customers-with-adapty-profiles\}
Adapty должен связать каждую покупку с [профилем клиента](profiles-crm), чтобы её можно было использовать в вашем приложении. По умолчанию профили создаются автоматически, когда Adapty получает вебхуки от Paddle. Вы можете выбрать, какое значение использовать в качестве `customer_user_id` в Adapty:
1. **По умолчанию и рекомендуется:** `customer_user_id`, который вы передаёте в поле `custom_data` (см. [документацию Paddle](https://developer.paddle.com/build/transactions/custom-data))
2. `email` из объекта Paddle Customer (см. [документацию Paddle](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open/#parameters))
3. Paddle Customer ID в формате `ctm-...` (см. [документацию Paddle](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open/#parameters))
4. Не создавать профили. Выберите этот вариант, если хотите самостоятельно управлять профилями пользователей.
Вы можете настроить, какое значение использовать, в поле **Profile creation behavior** в [App Settings → Paddle](https://app.adapty.io/settings/paddle).
## 2. Добавьте продукты Paddle в Adapty
:::warning
Обязательно добавьте ваши продукты Paddle в дашборд Adapty или добавьте Paddle product ID к уже существующим продуктам. Adapty отслеживает события только для транзакций, связанных с этими продуктами. Если пропустить этот шаг, события транзакций создаваться не будут.
:::
Paddle работает в Adapty так же, как App Store и Google Play — это ещё одна платформа для продажи цифровых продуктов. Чтобы настроить её, добавьте нужные значения `product_id` и `price_id` из Paddle в разделе [Products](https://app.adapty.io/products) в Adapty.
В Paddle идентификаторы продуктов выглядят как `pro_...`, а идентификаторы цен — как `pri_...`. Их можно найти в [каталоге продуктов Paddle](https://vendors.paddle.com/products-v2), открыв конкретный продукт:
После того как продукты добавлены, следующий шаг — убедиться, что Adapty сможет связать покупку с нужным пользователем.
## 3\. Предоставьте доступ пользователям на мобильном устройстве \{#3-provide-access-to-users-on-the-mobile\}
Чтобы пользователи, совершившие покупку на сайте, получили доступ в мобильном приложении, вызовите `Adapty.activate()` или `Adapty.identify()` с тем же `customer_user_id`, который был передан при оформлении покупки. Подробнее см. в разделе [Идентификация пользователей](identifying-users).
## 4\. Протестируйте интеграцию \{#4-test-your-integration\}
После завершения настройки можно протестировать интеграцию. Транзакции в Test-окружении Paddle будут отображаться в Adapty со статусом **Test**, а транзакции из Production — со статусом **Production**.
Интеграция завершена. Пользователи могут оформлять подписки на вашем сайте и автоматически получать доступ к премиум-функциям в мобильном приложении, а вы отслеживаете всю аналитику подписок в едином дашборде Adapty.
## Важные замечания \{#important-considerations\}
- В аналитике Adapty суммы транзакций включают налоги и комиссии Paddle, что отличается от дашборда Paddle, где суммы отображаются после вычета налогов и комиссий. Поэтому числа в Adapty будут выше, чем в вашем дашборде Paddle.
- В отличие от других сторов, возвраты в Paddle затрагивают только конкретную транзакцию и не отменяют подписку автоматически. Подписка остаётся активной, если её не отменить явно.
- Вы также можете передавать `variation_id` в поле `custom_data`, чтобы атрибутировать покупки конкретным экземплярам пейвола. Adapty обработает эти данные из вебхуков и учтёт их в аналитике.
### Платные триалы \{#paid-trials\}
При работе с платными триалами в Paddle нужно создать два продукта в Adapty:
1. Создайте разовую покупку и свяжите её с ценой Paddle, которая списывает оплату за триальный период.
2. Затем создайте продукт-подписку (Monthly/Weekly/и т. д.) и свяжите его с ценой Paddle, в которой настроен бесплатный триал.
С точки зрения Paddle, это один продукт с двумя ценами в рамках одной транзакции: одна цена — за триальный период (например, $0.99), другая — за бесплатный триал ($0.00).
С точки зрения Adapty это создаёт два отдельных события: разовая покупка для пробного платежа и событие начала пробного периода для продукта-подписки.
Например, когда пользователь начинает платный пробный период за $0,99 для подписки за $9,99/месяц, Paddle создаёт одну транзакцию с обеими ценами, тогда как Adapty обрабатывает это как разовую покупку на $0,99 (немедленный платёж) и событие начала пробного периода на $0,00 (будущая подписка за $9,99/месяц).
:::note
Когда пользователи отменяют платный пробный период, вы получаете события **Trial expired** и **Trial renewal canceled**.
:::
## Больше возможностей с данными Paddle \{#get-more-from-your-paddle-data\}
:::important
Чтобы события Paddle работали с интеграциями, ваши пользователи должны хотя бы раз войти в приложение через аккаунт App Store/Google Play.
:::
После интеграции с Paddle Adapty сразу готов предоставлять аналитику. Чтобы максимально использовать данные Paddle, можно настроить дополнительные интеграции Adapty для передачи событий Paddle — это объединит всю аналитику подписок в едином дашборде Adapty.
Интеграции для передачи и анализа событий Paddle:
- [AppsFlyer](appsflyer)
- [Webhook](webhook)
- [Posthog](posthog)
## Текущие ограничения \{#current-limitations\}
- **Отмены**: Paddle предлагает два варианта отмены подписки:
1. Немедленная отмена: подписка отменяется сразу.
2. Отмена в конце периода: подписка отменяется по истечении текущего расчётного периода (аналогично встроенным подпискам в сторах).
- **Возвраты**: Adapty отслеживает полные и частичные возвраты средств.
- **Grace period**: По умолчанию Paddle применяет фиксированный льготный период в 30 дней при проблемах с оплатой, в течение которого подписка остаётся активной. Вы можете [настроить продолжительность льготного периода и действие по его окончании (приостановка или отмена подписки)](https://developer.paddle.com/build/retain/configure-payment-recovery-dunning#prerequisites).
**Пробные периоды**: если оплата не проходит после окончания пробного периода, статус подписки меняется на `past_due`. В production Paddle's Retain применяет окно повторных попыток оплаты (dunning window), чтобы попытаться восстановить платёж до того, как подписка будет отменена или приостановлена. В песочнице Retain недоступен, поэтому повторные попытки оплаты не предпринимаются, и подписка остаётся в статусе `past_due` бессрочно.
---
**См. также:**
- [Валидация покупки в Paddle, получение уровня доступа и импорт истории транзакций из Paddle через серверный API](api-adapty/operations/validatePaddlePurchase)
---
# File: custom-store
---
---
title: "Начальная интеграция с другими сторами"
description: "Начальная интеграция Adapty с App Store: краткое руководство"
---
Рады видеть вас в Adapty! Наша главная цель — помочь вам быстро стартовать и добиться наилучших результатов для вашего приложения.
Начальная интеграция нужна только для [App Store](initial_ios), [Google Play](initial-android), [Stripe](stripe) и [Paddle](paddle), поскольку Adapty проверяет ваши приложения, продукты и предложения именно в этих сторах.
Adapty не валидирует данные из других сторов и не обрабатывает покупки, совершённые через них. Тем не менее вы можете помечать продукты, проданные через другие сторы, чтобы Adapty предоставлял доступ к платному контенту после успешной покупки, отображал транзакции в аналитике и передавал их через интеграции.
:::important Убедитесь, что ваш бэкенд обрабатывает покупку и отправляет транзакцию в Adapty через [серверный API Adapty](getting-started-with-server-side-api). Adapty предоставит доступ, инициирует событие транзакции, отправит его в интеграции и отобразит в аналитике только после получения транзакции. ::: Чтобы пометить продукт как проданный через кастомный стор, выберите нужный стор при создании продукта. Если нужного стора нет в списке, создайте его следующим образом: 1. На странице **Products** откройте продукт, который хотите продавать через кастомный стор. 2. Выберите стор, через который будете продавать. Если его нет в списке, нажмите кнопку **Create Custom Store**.
3. Введите **Title** и **Store ID** стора.
4. Нажмите кнопку **Create store**.
Если ваш бэкенд настроен правильно, Adapty будет получать транзакции продуктов из этого кастомного стора, отображать их в аналитике, в [**Event Feed**](event-feed) и [интеграциях](https://app.adapty.io/integrations), а также предоставлять доступ соответствующим образом.
## Максимальная польза от данных кастомного стора \{#get-more-from-your-custom-store-data\}
:::important
Чтобы события кастомного стора работали с интеграциями, ваши пользователи должны хотя бы один раз войти в приложение через аккаунт App Store или Google Play.
:::
После настройки интеграции с кастомным стором Adapty сразу готов предоставлять аналитику. Чтобы извлечь максимум из ваших данных, настройте дополнительные интеграции Adapty для передачи событий кастомного стора — так вся аналитика по подпискам окажется в едином дашборде Adapty.
Интеграции для передачи и анализа событий кастомного стора:
- [AppsFlyer](appsflyer)
- [Webhook](webhook)
- [Posthog](posthog)
---
# File: transfer-apps
---
---
title: "Передача приложения другому владельцу"
description: "Смените владельца приложения в Adapty"
---
Передайте приложение другому владельцу, если ваша компания поглощена, вы продаёте приложение или реструктурируете бизнес. Процесс передачи включает согласованные изменения в Adapty, App Store Connect и Google Play Console, чтобы сервис работал без перебоев.
## Передача приложения \{#transfer-app-ownership\}
Сначала выполните передачу в сторе, затем — в Adapty. Такой порядок гарантирует, что покупки продолжают работать на протяжении всего перехода.
:::note
Не удаляйте и не пересоздавайте продукты в процессе передачи. Не меняйте идентификаторы продуктов до тех пор, пока не убедитесь, что передача прошла успешно.
:::
### Передача App Store (iOS) \{#app-store-ios-transfer\}
:::important
Ключи API App Store Connect (Issuer ID, Key ID, файл .p8) привязаны к аккаунту, а не к приложению. После передачи необходимо сгенерировать новые ключи API в аккаунте нового владельца и обновить их в Adapty.
App-specific shared secret продолжает валидировать чеки в течение периода передачи, однако новый владелец также должен перегенерировать его и обновить в Adapty после завершения передачи.
:::
1. **Новый владелец:** Создайте аккаунт в Adapty на [app.adapty.io](https://app.adapty.io), если у вас его ещё нет.
2. **Старый владелец:** Инициируйте передачу приложения в App Store Connect, следуя [руководству Apple по передаче](https://developer.apple.com/help/app-store-connect/transfer-an-app/overview-of-app-transfer).
3. **Новый владелец:** Примите передачу в App Store Connect.
4. **Старый владелец:** Напишите на [support@adapty.io](mailto:support@adapty.io), чтобы передать приложение в Adapty. Укажите название приложения и адрес электронной почты нового владельца.
5. **Новый владелец:** После получения приложения в Adapty пройдите [руководство по интеграции с App Store](initial_ios), чтобы сгенерировать и настроить все учётные данные в рамках вашего аккаунта.
### Перенос Google Play (Android) \{#google-play-android-transfer\}
1. **Новый владелец:** Создайте аккаунт Adapty на [app.adapty.io](https://app.adapty.io), если у вас его ещё нет.
2. **Оба владельца:** Убедитесь, что оба аккаунта Google Play Developer полностью зарегистрированы.
3. **Старый владелец:** Отправьте запрос на передачу через Google Play Console или Google Play Developer Support. Google может запросить дополнительные документы: номера DUNS, договоры или подтверждение сделки.
4. **Новый владелец:** Проверьте и подтвердите запрос на передачу.
5. **Google:** Команда поддержки Google обрабатывает передачу — обычно в течение нескольких рабочих дней, но срок может увеличиться в зависимости от верификации аккаунта, сложности подписок и настройки платежей.
6. **Старый владелец:** После того как Google завершит передачу, напишите на [support@adapty.io](mailto:support@adapty.io) с просьбой перенести приложение в Adapty. Укажите название приложения и email нового владельца.
7. **Новый владелец:** Получив приложение в Adapty, выполните [инструкцию по интеграции с Google Play](initial-android), чтобы сгенерировать и настроить все учётные данные в своём аккаунте.
Передача включает пользователей, подписки, статистику, оценки и описание приложения в сторе. Непрерывность выставления счетов для существующих подписчиков сохраняется, но выплаты переключаются на торговый счёт нового владельца только после завершения передачи. Отчёты о выплатах и заказы до передачи остаются в исходном аккаунте. Подробные требования см. в [руководстве по передаче](https://support.google.com/googleplay/android-developer/answer/6230247) от Google.
## Снижение рисков и тайминг \{#risk-mitigation-and-timing\}
**Что продолжает работать во время передачи:**
- Покупки и продления (app-specific shared secret продолжает валидировать чеки в течение периода передачи)
- Доступ для существующих подписчиков
- SDK продолжает работать
**Что временно перестаёт работать:**
- Вызовы App Store Connect API (до настройки новых ключей)
- Серверные уведомления (до перенастройки эндпоинта)
- В аналитике возможны пробелы во время смены учётных данных
**Рекомендуемое время для переноса:**
- Проводите перенос в период низкой активности пользователей (3:00–6:00 по основному часовому поясу)
- Убедитесь, что новый владелец готов сразу настроить учётные данные после принятия переноса стора
- Закладывайте 15–30 минут между принятием переноса и завершением интеграции с Adapty
**После завершения переноса:**
- Немедленно протестируйте валидацию чеков
- В течение 48 часов следите за успешностью авторебновлений
- Убедитесь, что серверные уведомления доходят до ваших систем
- Проверьте, что новые покупки отслеживаются корректно
## Проверка успешной передачи \{#verify-transfer-completed-successfully\}
После завершения передачи как в Adapty, так и в сторе:
1. **Проверьте доступ к дашборду:** Новый владелец должен видеть приложение в своём дашборде Adapty.
2. **Проверьте подключение ключа API:** Убедитесь, что новый ключ API App Store Connect или сервисный аккаунт Google Play успешно подключается в Adapty.
3. **Протестируйте подключение SDK:** Запустите приложение и убедитесь, что SDK Adapty инициализируется без ошибок.
---
# File: installation-of-adapty-sdks
---
---
title: "Установка Adapty SDK"
description: "Установите Adapty SDK для iOS, Android и кросс-платформенных приложений."
---
У вас есть три способа начать работу в зависимости от ваших предпочтений:
- **Следуйте платформенным гайдам по быстрому старту**: Гайды содержат готовые к использованию фрагменты кода, поэтому реализация не займёт много времени.
- [iOS](ios-sdk-overview)
- [Android](android-sdk-overview)
- [React Native](react-native-sdk-overview)
- [Flutter](flutter-sdk-overview)
- [Unity](unity-sdk-overview)
- [Kotlin Multiplatform](kmp-sdk-overview)
- [Capacitor](capacitor-sdk-overview)
- **Используйте LLM**: Наша документация оптимизирована для работы с языковыми моделями. Прочитайте наш [гайд](adapty-cursor) о том, как максимально эффективно использовать LLM с документацией Adapty.
- **Изучите примеры приложений**:
- [iOS (Swift)](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples)
- [Android (Kotlin)](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app)
- [React Native (базовый пример на чистом RN)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/BasicExample)
- [React Native (расширенный пример — удобен для разработки, так как позволяет работать с более сложными случаями)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/AdaptyDevtools)
- [React Native (Expo dev build)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo)
- [React Native (Expo Go & Web)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock)
- [Flutter (Dart)](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example)
- [Unity (C#)](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets)
- [Kotlin Multiplatform](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example)
- [Capacitor](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples)
---
# File: sample-apps
---
---
title: "Примеры приложений"
description: ""
---
Чтобы помочь вам начать работу с Adapty SDK, мы подготовили примеры приложений, которые демонстрируют интеграцию и использование ключевых возможностей. В них реализованы готовые примеры пейволов, покупок и отслеживания аналитики.
## Зачем использовать примеры приложений? \{#why-use-sample-apps\}
- **Быстрая интеграция:** посмотрите, как Adapty SDK работает в реальном приложении.
- **Лучшие практики:** следуйте рекомендованным паттернам реализации.
- **Отладка и тестирование:** используйте примеры приложений для устранения проблем и экспериментов перед интеграцией Adapty в собственный проект.
## Доступные примеры приложений \{#available-sample-apps\}
- [iOS (Swift)](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples)
- [Android (Kotlin)](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app)
- [React Native (базовый пример на чистом RN)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/BasicExample)
- [React Native (расширенный пример — удобен при разработке, позволяет работать с более сложными сценариями)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/AdaptyDevtools)
- [React Native (Expo dev build)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo)
- [React Native (Expo Go & Web)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock)
- [Flutter (Dart)](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example)
- [Unity (C#)](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets)
- [Kotlin Multiplatform](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example)
- [Capacitor (React)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-react-example)
- [Capacitor (Vue.js)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-vue-example)
- [Capacitor (Angular)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-angular-example)
- [Capacitor (расширенные инструменты разработки)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/adapty-devtools)
---
# File: paywall-builder-templates
---
---
title: "Создание флоу"
description: "Начните новый флоу с готового шаблона из галереи или с минимального стартового варианта."
---
Флоу можно создать из шаблона или с нуля.
:::link
Хотите узнать больше о создании флоу? Смотрите пошаговые видеоуроки в нашем [плейлисте на YouTube](https://www.youtube.com/playlist?list=PLMksWqaZiWtM).
:::
## Создание флоу \{#create-flow\}
1. Откройте страницу **Flows**.
2. Нажмите **Create flow**.
3. Выберите вариант:
- **Browse templates** (открывает библиотеку шаблонов)
- **Start from scratch** (создаёт пустой флоу)
4. Переименуйте флоу в редакторе. Нажмите на название флоу в заголовке и введите новое имя.
:::warning
Adapty допускает одинаковые названия флоу. Переименовывайте каждый новый флоу, иначе получите несколько флоу с названием **Untitled**, которые сложно различить.
:::
### Использование шаблона \{#use-a-template\}
Библиотека шаблонов содержит несколько готовых шаблонов, которые служат отправной точкой для вашего флоу. Каждый из них — полноценный флоу с несколькими экранами, интерактивными элементами и настроенной навигацией. Любой элемент можно отредактировать под свои нужды.
Чтобы применить шаблон:
1. В библиотеке шаблонов просмотрите карточки. На каждой карточке показаны скриншоты из флоу.
2. Нажмите **Use as template** на нужной карточке.
Шаблон загружается в конструктор. Отсюда вы можете изменить любой элемент, экран или свойство.
### Начать с нуля \{#start-from-scratch\}
Начать с нуля — создать флоу с одним пустым экраном. Оформите экран с помощью элементов из [библиотеки элементов](builder-elements).
## Смена шаблона \{#change-the-template\}
Шаблон можно сменить прямо в конструкторе. Откройте панель **Screens** и нажмите кнопку **Templates** Templates, чтобы снова открыть библиотеку шаблонов, затем выберите новый шаблон.
:::warning
Применение нового шаблона заменяет текущий черновик флоу. Adapty запросит подтверждение — нажмите **Use template**, чтобы продолжить, или **Cancel**, чтобы оставить черновик. После подтверждения восстановить предыдущий черновик невозможно. Опубликованный флоу остаётся активным и не затрагивается.
:::
## Кастомные шрифты в шаблонах \{#custom-fonts-in-templates\}
:::link
Основная статья: [Кастомные шрифты во Flow Builder](using-custom-fonts-in-flow-builder)
:::
Шаблоны, отмеченные чипом **Custom font**, используют кастомные шрифты. Эти шрифты не входят в состав SDK. Наведите курсор на чип, чтобы увидеть, какие шрифты использует шаблон.
Чтобы типографика корректно отображалась на устройстве, добавьте файлы шрифтов в бандл приложения. Старые версии приложения, в которых нет этих шрифтов, будут использовать системный шрифт.
Чтобы сменить шрифт, не затронув старые версии, продублируйте флоу, измените шрифт в копии и ограничьте копию [пользователями на версиях приложения, где есть этот шрифт](segments).
---
# File: builder-ui
---
---
title: "Интерфейс Flow Builder"
description: "Обзор интерфейса и рабочей области Flow Builder."
---
Основной интерфейс Flow Builder включает все инструменты, необходимые для добавления визуальных элементов, редактирования их свойств и изменения логики пользовательского флоу. В этой статье описан каждый раздел интерфейса: что он делает и где его найти.
:::link
Хотите узнать больше о создании флоу? Смотрите пошаговые видеоуроки в нашем [плейлисте на YouTube](https://www.youtube.com/playlist?list=PLMksWqaZiWtM).
:::
## Элементы управления проектом и полезные сочетания клавиш (верхняя панель инструментов) \{#project-controls-and-useful-shortcuts-top-toolbar\}
* **Close** Close: Выйти из редактора флоу и вернуться на страницу флоу.
* **App name** App: Показывает, к какому приложению относится флоу.
* **All flows** Flows: Открыть список всех флоу для этого приложения.
* **Flow status**: Иконка слева от названия флоу показывает текущий [статус флоу](builder-save-publish#flow-status):
- **Draft** Draft
- **Publishing** (крутящийся индикатор загрузки)
- **Failed** Failed
- или **Live** Live.
* **Rename the flow**: Нажмите на название флоу, чтобы переименовать его. Несколько флоу могут иметь одинаковые названия — [давайте каждому новому флоу уникальное имя](paywall-builder-templates#create-flow).
* **View mode toggle**: Переключайтесь между режимом дизайна Cursor и [режимом Remote Config](customize-flow-with-remote-config)Remote Config.
* **Undo/Redo**: Нажмите на стрелки, чтобы отменить Undo или повторить Redo изменения во флоу. Также можно использовать ⌘Z / Ctrl+Z для отмены.
* **Save draft / Publish**: Нажмите **Save draft**, чтобы сохранить прогресс без публикации (⌘ / Ctrl+S). Откройте выпадающий список Open dropdown, чтобы получить доступ к кнопке [**Publish**](builder-save-publish). Добавить флоу в [плейсмент](create-placement) можно только после публикации.
## Область предпросмотра (центр) \{#preview-area-center\}
Центральная область рабочего пространства показывает, как выглядит ваш флоу на мобильном устройстве.
* Чтобы выбрать элемент и изменить его свойства, нажмите на него. Чтобы выбрать дочерний элемент внутри контейнера, сначала нажмите на контейнер, затем на дочерний элемент.
* Чтобы изменить свойства самого экрана, нажмите в пустое место за пределами любого элемента или выберите экран на панели Screens and Layers.
* Чтобы изменить порядок элемента, перетащите его строку вверх или вниз на панели Screens and Layers.
:::warning
Редактор флоу создан для адаптивных макетов. Поэтому вы **не можете вручную изменять положение элементов** — можно только менять их порядок. Настройки макета каждого контейнера определяют, как распределяются находящиеся внутри него элементы.
:::
### Панель активного экрана (над превью устройства) \{#active-screen-bar-above-the-device-preview\}
- **Screen name** — плашка с именем текущего экрана.
- **Toggle animations** Toggle animations — включает или отключает предпросмотр анимаций элементов; они воспроизводятся непрерывно, пока не отключены. Отображается только если на активном экране есть хотя бы одна [анимация](builder-styling#animation). Не влияет на отображение анимаций на реальном устройстве.
- **Add element** Plus — открывает [библиотеку элементов](builder-elements) для текущего экрана. Аналог кнопки **+** в верхней части панели «Screens and Layers» — удобно использовать, когда панель свёрнута.
### Элементы управления видом (нижняя панель инструментов) \{#view-controls-bottom-toolbar\}
Инструменты нижней панели позволяют управлять предпросмотром.
* **Device**: Выберите одну из доступных моделей iPhone или Android, чтобы изменить размеры области просмотра и отображение устройства.
* **Screen orientation**: Переключайтесь между портретным Portrait и альбомным Landscape режимами, чтобы просмотреть флоу в разных ориентациях.
* **Color scheme**: Переключайтесь между светлой Light mode и тёмной Dark mode темами, чтобы увидеть, как дизайн адаптируется к разным схемам оформления.
* **Locale**: Выберите локаль, чтобы просмотреть флоу с локализованным контентом.
* **View options**: Включайте или отключайте отображение рамки устройства и направляющих безопасной зоны.
## Свойства экрана и элементов (правая панель) \{#screen-and-element-properties-right-panel\}
### Настройки экрана и макет \{#screen-settings-and-layout\}
:::link
Основная статья: [Экраны и слои](paywall-layout-and-products)
:::
Когда ни один элемент не выбран, правая панель позволяет настраивать свойства активного [экрана флоу](paywall-layout-and-products), в том числе:
* Взаимодействие с системным UI (например, отображение строки состояния)
* Правила автоматической компоновки
* Фон (цвет, изображение или видео)
* Размер отступов
* Поведение вертикальной прокрутки
Если экран содержит определённые элементы, например [интерактивные викторины](onboarding-quizzes), этот список расширится соответствующими свойствами.
### Свойства элемента \{#element-properties\}
При выборе элемента правая панель позволяет изменить его стилевые и интерактивные свойства.
#### Свойства дизайна \{#design-properties\}
:::link
Подробнее: [Расположение и позиционирование](manage-paywall-ui-elements), [Стили и внешний вид](builder-styling)
:::
Вкладка **Design** позволяет настроить внешний вид и расположение выбранного элемента:
* **Visibility**: Показать или скрыть элемент. Включите **Conditional** visibility, чтобы задать правила отображения элемента.
* **Position**: Выберите тип позиционирования: Relative, Absolute или Fixed.
* **Content** (только для текстовых элементов): редактируйте текстовое содержимое элемента, вставляйте [переменные](#variables) и управляйте локализациями.
* **Typography** (только для текстовых элементов): настройте шрифт, начертание, размер, цвет, выравнивание, оформление и обрезку текста.
* **Spacing**: задайте внешние и внутренние отступы элемента.
* **Effects**: добавьте внешние тени, внутренние тени, размытие фона или размытие слоя.
* **Animation**: добавьте анимационные эффекты (например, Pulse) и настройте их продолжительность и интенсивность.
* **Appearance**: отрегулируйте прозрачность и угол поворота.
* **Layout**: выберите направление раскладки (вертикальное или горизонтальное) и задайте распределение дочерних элементов.
#### Свойства взаимодействий \{#interactions-properties\}
:::link
Подробнее: [Действия](onboarding-actions), [Навигация и взаимодействие](onboarding-navigation-branching)
:::
Вкладка **Interactions** позволяет задать, что происходит при взаимодействии пользователя с выбранным элементом. Каждое взаимодействие состоит из **триггера** и одного или нескольких **действий**:
* **Триггеры** определяют *когда* что-то происходит — например, **On Tap** (пользователь нажимает на элемент).
* **Действия** определяют *что* происходит — например, переход на другой экран или изменение значения переменной. Добавьте несколько действий к одному триггеру, чтобы выполнять их последовательно.
К одному элементу можно добавить несколько триггеров для выполнения нескольких действий по порядку.
## Левая панель \{#left-panel\}
Левая панель меняет своё содержимое в зависимости от активной кнопки. Доступные разделы:
* [Экраны и слои](#screens-and-layers)
* [Добавить элемент](#element-selection)
* [Продукты](#products)
* [Стили](#saved-styles)
* [Переменные](#variables)
* [Локализация](#localization)
### Экраны и слои
:::link
Основная статья: [Экраны и слои](paywall-layout-and-products)
:::
Кнопка Layers открывает панель «Экраны и слои» (отображается по умолчанию при открытии конструктора флоу).
Здесь каждый экран представлен в виде дерева слоёв. Каждый элемент на экране — это слой, а контейнеры содержат вложенные дочерние элементы. Слои можно перетаскивать, чтобы изменить их порядок.
### Выбор элементов \{#element-selection\}
:::link
Основная статья: [Элементы](builder-elements)
:::
Если нажать кнопку плюс Plus, в левой панели появится список доступных UI-элементов и их вариантов. Кликните на нужный элемент, чтобы добавить его на текущий экран как новый слой.
### Продукты \{#products\}
:::link
Основная статья: [Продукты](paywall-product-block)
:::
Кнопка продуктов Products открывает список продуктов. В нём показано, какие продукты назначены каждому экрану вашего флоу.
Список доступен только для чтения. Чтобы назначить продукты экрану, добавьте элемент «Продукт» и настройте его в правой панели. Чтобы создать или изменить продукты, используйте страницу **Products** в дашборде Adapty.
### Сохранённые стили \{#saved-styles\}
:::info
Подробнее:
- [Стили и оформление](builder-styling)
- [Текстовое содержимое](onboarding-text)
- [Тёмный режим](paywall-dark-mode)
:::
Кнопка «Стили» Styles открывает панель сохранённых стилей.
Здесь можно редактировать и управлять глобальными стилями. Если несколько элементов вашего флоу используют одинаковую типографику или цвет, сохраните эти настройки как глобальный стиль — после этого их можно применять одним кликом.
В настоящее время Flow Builder поддерживает два типа глобальных стилей — стили шрифтов и стили цветов. Для каждого стиля цвета можно задать отдельное значение для тёмного режима.
### Переменные \{#variables\}
:::link
Основная статья: [Переменные](onboarding-variables)
:::
Кнопка с угловыми скобками Variables открывает панель переменных.
Здесь можно создавать переменные для флоу и управлять ими. Во время выполнения SDK подставляет вместо плейсхолдеров переменных реальные значения — атрибуты пользователя, цены продуктов, локализованные строки и другое.
Переменные сгруппированы на двух вкладках:
* **Custom**: переменные, которые вы создаёте и контролируете через действия.
* **Elements**: значения, определяемые взаимодействием пользователя — например, ответы на вопросы викторины, состояния переключателей или выбор вкладки.
Переменные продукта — цена, название и другие данные продукта — в этой панели не отображаются. Ссылайтесь на них напрямую при редактировании текстового элемента.
Используйте переменные для:
* **Привязывать текст**: отображать динамический контент вместо статических строк.
* **Управлять видимостью**: показывать или скрывать элементы на основе условий (например, скрывать кнопку апгрейда для премиум-пользователей).
* **Взаимодействовать с пользователем**: считывать данные из полей ввода, например из форм или опросов.
### Локализация \{#localization\}
:::link
Основная статья: [Локализация](add-flow-remote-config-locale)
:::
Вкладка Localization позволяет управлять всеми переводимыми элементами флоу. Здесь отображается таблица всех текстовых строк и изображений, сгруппированных по экранам, с отдельным столбцом для каждой локали. В этом разделе можно:
* Добавлять новые локали и редактировать переведённые строки прямо в таблице.
* Отслеживать статус перевода — каждая строка помечена как **Done** или **Missing**.
* Фильтровать по экрану или показывать только незаполненные переводы.
* Использовать **AI Translate** для автоматического перевода или **Import/Export** для массовой загрузки и выгрузки переводов.
---
# File: flow-builder-recipes
---
---
title: "Типовые рецепты для флоу"
description: "Пошаговые гайды по созданию типовых шаблонов экранов в Flow Builder."
---
В этом разделе описано, как создавать наиболее распространённые шаблоны экранов во Flow Builder — элемент за элементом, от выбора макета до настройки взаимодействий. Каждый гайд самодостаточен и использует стандартные элементы Flow Builder.
3. Кнопки покупок, ссылки и кнопки закрытия поставляются с предварительно настроенными действиями. Для ссылок [задайте URL для перехода](#links). Для кнопок других типов откройте панель **Interactions**. Там в разделе **Button triggers** настройте [действия](onboarding-actions), которые должна выполнять кнопка.
4. Настройте [оформление кнопки](builder-styling) в панели **Design**.
## Типы кнопок \{#button-types\}
### Кнопки покупки \{#purchase-buttons\}
:::link
Чтобы кнопки покупки работали, привяжите продукты к экранам и добавьте элемент **Products**. Смотрите [гайд](paywall-product-block).
:::
Кнопка покупки запускает встроенную покупку для того продукта, который пользователь выбрал на экране. SDK обрабатывает транзакцию автоматически — вам не нужно писать для этого код в приложении.
Чтобы добавить кнопку покупки:
1. Нажмите **+** и выберите **Button**, затем выберите пресет кнопки.
2. Выделив кнопку, откройте вкладку **Interactions** на правой панели.
3. Нажмите **Add trigger** > **On tap**, затем нажмите **Add action**.
4. Установите **Action** на **Purchase**, а **Product** на `products.selectedProduct`. Переменная `products.selectedProduct` всегда указывает на текущий выбранный продукт на экране.
:::tip
Вы можете привлечь больше внимания к кнопкам покупки, добавив анимацию. Paywall Builder в настоящее время поддерживает тип анимации **Pulse**.
Настройте стиль анимации в панели **Design**.
:::
### Ссылки \{#links\}
:::important
Кнопки **Terms of Use** и **Privacy Policy** имеют встроенное действие **Open URL**. Укажите целевой URL именно там. Незаполненные Open URL и [встроенные ссылки](onboarding-text#inline-link) блокируют предпросмотр и публикацию.
:::
Чтобы соответствовать требованиям некоторых сторов, вы можете добавить ссылки на:
- Условия использования
- Политику конфиденциальности
- Восстановление покупок
Чтобы добавить ссылки:
1. Нажмите **+** и выберите **Button > Links**. На экране появится строка инлайн-кнопок с предустановленными действиями: восстановление покупок или открытие URL. Если часть кнопок не нужна, удалите их на панели слоёв.
2. Теперь настройте действия кнопок:
- Кнопка **Restore purchases** уже обрабатывает восстановление покупок.
- Для каждой оставшейся ссылки:
1. Нажмите на кнопку, чтобы выбрать её, и перейдите на вкладку **Interactions** справа.
2. Вставьте URL в поле.
3. По умолчанию URL открывается во встроенном браузере для удобства пользователей. Если вы хотите перенаправлять пользователей во внешний браузер, установите флажок **Open in external browser**.
### Кнопка закрытия флоу \{#close-flow\}
Кнопка **Close** закрывает флоу автоматически.
Чтобы добавить кнопку закрытия, нажмите **+** и выберите **Button > Close flow**.
:::tip
Используйте позиционирование **Absolute**, чтобы разместить кнопку закрытия в углу экрана.
:::
Вы также можете настроить любую другую кнопку для закрытия флоу с помощью [действий](onboarding-actions).
### Пользовательские кнопки \{#custom-buttons\}
Любую добавленную кнопку можно настроить на выполнение нужного действия при нажатии:
- Перейти на следующий экран
- Показать предупреждение
- Задать [переменную](onboarding-variables)
- [Показать или скрыть элементы экрана](onboarding-element-visibility)
- Открыть URL
- Восстановить покупки
- Выполнить условные действия
---
# File: builder-tabs
---
---
title: "Вкладки"
description: "Добавьте навигацию по вкладкам, переключающую панели контента в флоу."
---
**Вкладки** делят раздел экрана на переключаемые панели контента — пользователь нажимает на заголовок вкладки, и панель ниже обновляется соответственно.
{/* TODO: on-device GIF */}
## Добавление, удаление и выбор вкладок \{#add-remove-and-select-tabs\}
Каждая вкладка состоит из двух частей:
- **Заголовок вкладки** — кликабельная метка (Tab 1, Tab 2 и т. д.).
- **Содержимое вкладки** — один контейнер на каждую вкладку. Всё, что вы помещаете в контейнер, отображается при выборе соответствующей вкладки.
Нажмите **Add tab**, чтобы добавить новую вкладку. Для каждой новой вкладки автоматически создаётся соответствующий контейнер содержимого.
Чтобы определённая вкладка была активной при первом открытии экрана, включите переключатель **Selected by default**.
## Стилизация вкладок \{#style-the-tabs\}
### Шаблоны \{#templates\}
Flow Builder предлагает три готовых шаблона для вкладок:
- **Segment control** — переключатель в виде «пилюли» с закруглёнными углами вокруг активной вкладки.
- **Button Tabs** — отдельные вкладки в виде кнопок.
- **Underline** — текстовые метки с подчёркиванием активной вкладки.
### Состояния вкладок \{#tab-states\}
У каждой вкладки есть переключатель состояний (**Default / Selected**), позволяющий отдельно настроить стили активного и неактивного состояния — типографику, цвета, заливку и рамку для каждого из них.
## Выбираемая группа \{#selectable-group\}
Вкладки — это **одиночная выбираемая группа**: в каждый момент активна ровно одна вкладка. Управлять группой можно в панели **Screen settings** в разделе [Selectable groups](paywall-layout-and-products#selectable-groups).
Группа предоставляет две переменные:
- `tabs.selectedOptionId` — ID выбранной вкладки. Используйте в условиях.
- `tabs.selectedOptionTitle` — метка выбранной вкладки. Используйте в динамическом тексте.
Замените `tabs` на свой **Group ID**, если переименовали группу.
Подробнее см. в разделе [Выбираемые элементы и группы](flow-selectable-elements).
---
# File: builder-toggles
---
---
title: "Переключатели"
description: "Добавьте переключатели в платёжные флоу."
---
:::warning
Apple может отклонить приложение, если в нём используется предварительно включённый переключатель пробного периода. Переключатель, установленный в положение «вкл.» по умолчанию, может быть расценён как манипулятивный тёмный паттерн согласно рекомендациям App Store Review Guidelines — это подразумевает согласие пользователя на пробный период без явного выбора.
Чтобы избежать отклонения, установите переключатель в положение **выкл.** по умолчанию и позвольте пользователям самостоятельно подключаться к пробному периоду.
:::
Переключатель пробного периода — это бинарный переключатель, позволяющий пользователям выбирать между стандартными продуктами и продуктами с пробным периодом на пейволе. При изменении его состояния может запускаться действие — например, замена групп продуктов, обновление переменных или показ/скрытие элементов — мгновенно.
Чтобы добавить переключатель пробного периода, нажмите **+** на целевом экране и выберите **Trial toggle**.
Каждый переключатель пробного периода является выбираемым элементом типа **Toggle**. Каждому выбираемому элементу назначается переменная, отражающая его состояние — например, переключатель с именем `trial` получает переменную `trial.is_selected` со значением `True` или `False`.
Чтобы другие элементы реагировали на состояние переключателя, задайте условное [действие](onboarding-actions) или [условную видимость](onboarding-element-visibility) на основе этой переменной.
---
# File: builder-reviews-and-testimonials
---
---
title: "Отзывы и рекомендации"
description: "Добавляйте отзывы, рейтинги и социальное доказательство на пейвол."
---
Категория элементов **User Engagement** предоставляет четыре шаблона для демонстрации отзывов, рейтингов и социального доказательства на пейволе. Каждый шаблон — это полностью редактируемая композиция: замените текст-заполнитель и примените свои [цветовые стили](builder-styling) и [типографику](onboarding-text), чтобы всё выглядело единообразно с остальным флоу.
## Обзор \{#review\}
Карточка с оценкой, цитатой и подписью автора. Используется для демонстрации запоминающейся пользовательской цитаты.
## Рейтинг \{#rating\}
Счётчик и строка со звёздами, например «17000+ рейтингов». Используйте, чтобы подчеркнуть количество оценок.
## Рейтинг приложения \{#app-rating\}
Отображает итоговую оценку с указанием количества отзывов, например «4.9 / На основе 1000+ отзывов». Используйте, чтобы подчеркнуть высокий общий рейтинг.
## Социальное доказательство \{#social-proof\}
Группа аватаров с указанием количества участников — например, «Присоединяйтесь к 50 000+ пользователей». Используйте, чтобы подчеркнуть масштаб сообщества.
---
# File: flow-timer
---
---
title: "Таймер обратного отсчёта"
description: "Добавьте таймер обратного отсчёта на пейвол."
---
**Таймер обратного отсчёта** ведёт отсчёт от заданной продолжительности до нуля — когда он достигает нуля, отображение замирает.
## Шаблоны \{#templates\}
Категория предлагает четыре визуальных варианта:
- **Blocks** — дни, часы, минуты и секунды в отдельных подписанных ячейках.
- **Inline Units** — однострочный текст с суффиксами единиц времени.
- **Inline** — только цифры.
- **Badge** — отображение цифр в виде таблетки.
## Настройки \{#settings\}
### Установите продолжительность \{#set-the-duration\}
В разделе **Countdown** правой панели укажите начальную продолжительность в днях, часах, минутах и секундах.
### Настройка поведения \{#configure-the-behavior\}
Выпадающий список **Behavior** управляет тем, когда запускается таймер:
- **Every appear** — перезапускается каждый раз, когда пользователь открывает экран. Поведение по умолчанию.
- **First appear** — запускается при первом открытии экрана в текущей сессии приложения. Продолжает отсчёт, если пользователь возвращается в той же сессии; сбрасывается при новом запуске приложения.
- **First appear (persisted)** — запускается при первом открытии экрана и продолжает отсчёт между запусками приложения.
### Запустить действие по окончании таймера \{#trigger-an-action-when-the-timer-ends\}
:::link
Основная статья: [Действия](onboarding-actions)
:::
Добавьте триггер **On timer end**, чтобы запустить действие, когда обратный отсчёт достигает нуля, — например, перейти на другой экран или скрыть значок скидки.
---
# File: onboarding-quizzes
---
---
title: "Квизы во флоу"
description: "Добавляйте интерактивные квизы в флоу Adapty, чтобы собирать предпочтения пользователей и выстраивать персонализированные флоу — без написания кода."
---
Квизы позволяют предлагать пользователям готовые варианты ответов. В отличие от полей ввода, у квизов нет текстовых полей — пользователь выбирает из тех вариантов, которые вы задали. Используйте их для сбора предпочтений, сегментации пользователей или разветвления флоу в зависимости от выбранных ответов.
### Добавить викторину \{#add-a-quiz\}
1. Нажмите **+** в верхнем левом углу.
2. Выберите **Quiz**.
3. Выберите тип викторины:
- **Icon/image/emoji options:** вертикальный список вариантов для выбора, каждый из которых содержит иконку, изображение или эмодзи рядом с текстовой подписью.
- **Icon/image/emoji grid:** сетка вариантов для выбора, каждый из которых содержит иконку, изображение или эмодзи.
- **Rating:** шкала, по которой пользователи могут выразить оценку — числовую или в виде звёзд.
### Настройка условной навигации \{#set-up-conditional-navigation\}
Чтобы направлять пользователей по разным маршрутам в зависимости от их выбора, задайте условное действие на **кнопке навигации**, а не на варианте ответа:
1. Выберите кнопку навигации.
2. На панели **Interactions** добавьте триггер **On Tap** с действием **Conditional**.
3. В диалоге **Edit Action** настройте строку **if**:
- Слева нажмите `{}` и выберите **Elements → Screen → `
2. Нажмите **Create product** в правом верхнем углу. Adapty поддерживает все типы продуктов: подписки, нерасходуемые покупки \(включая пожизненный доступ\) и расходуемые покупки.
3. Выберите **Create a new product and push to stores**.
4. Введите следующие данные:
- **Product name**: введите название продукта, которое будет отображаться в дашборде Adapty. Это название нужно в первую очередь для вас, поэтому выбирайте то, которое вам удобнее всего использовать в дашборде Adapty.
- **Access Level**: выберите [уровень доступа](access-level), к которому относится продукт. Уровень доступа определяет, какие функции станут доступны после покупки продукта. Обратите внимание, что в этом списке отображаются только уже созданные уровни доступа. Уровень доступа `premium` создаётся в Adapty по умолчанию, но вы также можете [добавить дополнительные уровни доступа](access-level).
- **Subscription duration**: выберите длительность подписки из списка.
- **Weekly/Monthly/2 Months/3 Months/6 Months/Annual**: длительность подписки.
- **Lifetime**: используйте этот период для продуктов, которые открывают премиум-функции приложения навсегда.
- **Non-Subscriptions**: для продуктов, которые не являются подписками и поэтому не имеют длительности, используйте non-subscriptions. Это могут быть продукты для разблокировки дополнительных функций, расходуемые покупки и т. д.
- **Consumables**: расходуемые покупки можно приобретать несколько раз. Они расходуются в процессе использования приложения. Примеры — внутриигровая валюта и дополнения. Учтите, что расходуемые покупки не влияют на уровни доступа. Чтобы предоставить уровень доступа при разовой покупке, используйте **Non-Subscriptions**.
- **Price (USD)**: цена продукта в долларах США. Эта цена будет использоваться как базовая для автоматического расчёта и установки цен во всех странах. Позже вы сможете [настроить цену для отдельных стран и регионов](edit-product#set-country-specific-prices).
5. Нажмите **Save & Continue**.
6. Настройте информацию о продукте для App Store, если планируете публиковаться там:
- **Product ID**: Создайте постоянный уникальный идентификатор продукта.
- **Product group**: Выберите существующую группу продуктов, созданную в App Store Connect, или нажмите **Create new Product Group** и задайте её название. После того как Adapty создаст её, вы сможете выбрать её из выпадающего списка.
- **Screenshot**: Загрузите скриншот встроенной покупки, на котором чётко показан предлагаемый товар или услуга. Этот скриншот используется только для проверки в App Store и не отображается в App Store. Требования к размеру и формату скриншота смотрите [здесь](https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications/).
7. Нажмите **Push data to App Store**.
:::warning
Если это ваш первый продукт для данного приложения, вам нужно вручную отправить его на проверку в App Store Connect. В дальнейшем этого не потребуется. После завершения проверки статус продукта в Adapty обновится автоматически.
:::
8. Настройте информацию о продукте для Google Play, если планируете публикацию там:
- **Base Product ID**: Создайте постоянный уникальный идентификатор продукта.
- **Subscription**: Выберите существующую группу подписок, созданную в Google Play Console, или нажмите **Create new Product Group** и задайте её название и ID. После того как Adapty создаст её, вы сможете выбрать её из выпадающего списка.
:::note
Льготный период и период удержания аккаунта будут автоматически установлены по умолчанию согласно правилам Play Store. Изменить их можно позже в Google Play Console.
:::
9. Нажмите **Push data to Play Store**.
10. Для iOS настройте introductory offer — бесплатный пробный период — выбрав **Free duration** из выпадающего списка. На этом начальном этапе можно добавить introductory offer с бесплатным пробным периодом. После того как основной продукт будет одобрен сторами, вы сможете [добавить другие офферы](offers) (например, promotional или win-back), привязав их существующие ID из консоли стора.
:::important
Introductory offer не синхронизируются с Google Play автоматически. В отличие от App Store, в Google Play нет отдельного типа «introductory offer» — пробные периоды и скидочные предложения настраиваются как **офферы** базового плана. [Создайте оффер в Google Play Console и привяжите его к продукту Adapty](google-play-offers).
:::
11. Наконец, нажмите **Save**, чтобы подтвердить создание продукта.
## Создайте продукт и подключите существующие продукты из стора \{#create-product-and-connect-existing-store-products\}
:::warning
Перед началом убедитесь, что вы:
- Настроили интеграцию со сторами, которые вам нужны:
- [App Store](initial_ios)
- [Google Play](initial-android)
- Создали продукты в нужных сторах:
- [App Store](app-store-products)
- [Google Play](android-products)
**Если у вас ещё нет продуктов**, воспользуйтесь гайдом [Загрузить в сторы](#create-product-and-push-to-store) — он позволяет создать продукты одновременно в Adapty и сторах.
:::
2. Нажмите **Create product** в правом верхнем углу. Adapty поддерживает все типы продуктов: подписки, неизрасходуемые покупки \(включая пожизненный доступ\) и расходуемые покупки.
3. Выберите **Connect an existing store product**.
4. Введите следующие данные:
- **Product name**: введите название продукта, которое будет использоваться в дашборде Adapty. Название нужно прежде всего вам, поэтому выбирайте то, которое удобнее всего использовать в дашборде Adapty.
- **Access Level ID**: Выберите [уровень доступа](access-level), к которому относится продукт. Уровень доступа определяет, какие функции открываются после покупки продукта. Обратите внимание, что в этом списке отображаются только ранее созданные уровни доступа. Уровень доступа `premium` создаётся в Adapty по умолчанию, но вы также можете [добавить дополнительные уровни доступа](access-level).
- **Subscription duration** (Длительность подписки): выберите длительность подписки из списка.
- **Weekly/Monthly/2 Months/3 Months/6 Months/Annual**: длительность подписки.
- **Lifetime**: используйте пожизненный период для продуктов, которые навсегда открывают премиум-функции приложения.
- **Non-Subscriptions**: для продуктов, которые не являются подписками и поэтому не имеют длительности, используйте non-subscriptions. Они могут открывать дополнительные функции, расходуемые покупки и т. д.
- **Consumables**: расходуемые покупки можно приобретать несколько раз. Они расходуются в ходе использования приложения. Примеры: внутриигровая валюта и дополнения. Учтите, что расходуемые покупки не влияют на уровни доступа. Чтобы предоставить уровень доступа через разовую покупку, используйте **Non-Subscriptions**.
- **Price (USD)**: цена продукта в долларах США. Если ваш продукт уже есть в сторе, это значение не влияет на его реальную цену в сторе — можно выбрать любое значение из списка. Позже вы можете [настроить цены для разных регионов](edit-product#set-country-specific-prices) прямо в дашборде Adapty.
5. Нажмите **Continue**.
6. Настройте информацию о продукте из каждого стора:
- **App Store:**
- **App Store Product ID:** Уникальный идентификатор для доступа к продукту на устройствах. Выберите его из списка. Если его нет в списке, проверьте настройки в App Store Connect и убедитесь, что идентификатор корректен и принадлежит этому приложению.
- **Play Store:**
- **Google Play Product ID:** Идентификатор продукта в Play Store. Выберите его из списка. Если его нет в списке, проверьте настройки в Google Play Console и убедитесь, что идентификатор корректен и принадлежит этому приложению.
- **Base Plan ID:** Идентификатор базового плана продукта в Play Store. При добавлении Product ID подписки в Play Store необходимо указать Base Plan ID. Базовый план определяет основные параметры подписки: расчётный период, тип продления (автоматическое или предоплаченное) и цену. Обратите внимание: в Adapty каждая комбинация одной и той же подписки с разными базовыми планами считается отдельным продуктом.
- **Legacy fallback product**: Резервный продукт используется исключительно в приложениях на устаревших версиях Adapty SDK (2.5 и ниже). Отметив продукт как обратно совместимый в Google Play Console, вы позволяете Adapty определить, можно ли его приобрести в старых версиях SDK. В этом поле укажите значение в формате `
## Установка цен для разных стран \{#set-country-specific-prices\}
Вы можете задать разные цены для разных регионов прямо в дашборде Adapty — они автоматически применятся к вашим продуктам в App Store Connect и/или Google Play Console.
Чтобы установить цены для разных стран:
1. [Откройте продукт для редактирования](#edit-product).
2. Нажмите **Download**, чтобы выгрузить текущие цены из сторов в нужном формате, или создайте новый CSV-файл.
3. Обновите цены в CSV-файле, соблюдая [формат](#csv-file-format). Если цена для какой-либо страны не изменилась или не включена в файл, ничего не произойдёт. При загрузке CSV Adapty сравнивает цены и обновляет только те, которые отличаются.
4. В окне **Edit** нажмите **Upload** и выберите CSV-файл.
5. Если вы хотите, чтобы изменения применились и к существующим подписчикам, выберите **Apply to existing subscribers**.
6. Просмотрите изменения, которые будут применены, и нажмите **Save changes**.
### Формат CSV-файла \{#csv-file-format\}
:::tip
Если у вас похожие продукты в одном приложении или вы хотите установить одинаковые цены в разных приложениях, можно использовать один и тот же CSV-файл.
:::
Проще всего редактировать цены в CSV, [скачав файл с текущими ценами и отредактировав его напрямую](#set-country-specific-prices).
Если вы создаёте файл самостоятельно, он должен содержать следующие столбцы:
- `region_name`
- `region_code`
- `app_store_currency`
- `app_store_requested_price`
- `play_store_currency`
- `play_store_requested_price`
Пример:
```
region_name,region_code,app_store_currency,app_store_requested_price,play_store_currency,play_store_requested_price
United States,US,,8.99,,8.99
United Arab Emirates,AE,USD,8.99,AED,39.99
Germany,DE,USD,8.99,USD,8.99
```
## Просмотр журнала аудита \{#view-audit-log\}
Adapty записывает все изменения цен для каждого продукта, поэтому вы можете отслеживать, кто и когда вносил изменения. Чтобы открыть журнал аудита:
1. Откройте **[Products](https://app.adapty.io/products)** в главном меню Adapty.
2. Нажмите на три точки рядом с продуктом и выберите **Audit log**.
В таблице журнала аудита отображается каждое изменение цены с датой, именем и ролью участника команды, а также количеством изменений.
Чтобы скачать подробную CSV-разбивку события, нажмите на значок загрузки в соответствующей строке.
---
# File: delete-product
---
---
title: "Удаление продукта"
description: "Узнайте, как удалить продукт с подпиской в Adapty, не нарушая поток доходов вашего приложения."
---
Удалить можно только те продукты, которые не используются в пейволах.
Чтобы удалить продукт:
1. Перейдите в раздел **[Products](https://app.adapty.io/products)** в главном меню Adapty.
2. Нажмите кнопку **3-dot** рядом с продуктом и выберите **Delete**.
2. Введите название продукта, который вы собираетесь удалить.
3. Нажмите **Delete forever**.
---
# File: add-product-to-paywall
---
---
title: "Добавление продукта на пейвол"
description: "Узнайте, как добавлять продукты на пейволы в Adapty и управлять ими."
---
Чтобы продукт отображался на [пейволе](paywalls) и был доступен для выбора пользователями вашего приложения, выполните следующие шаги:
1. При [настройке пейвола](create-paywall) нажмите **Add product** под заголовком **Products**.
2. В открывшемся выпадающем списке выберите продукты, которые будут показаны пользователям. Список содержит только ранее созданные продукты. Порядок продуктов сохраняется на стороне SDK, поэтому при настройке пейвола важно учитывать желаемый порядок их отображения. При необходимости можно также указать offer для продукта.
3. Нажмите **Create as draft** или **Save and publish** в зависимости от статуса пейвола.
Обратите внимание: после создания пейвола не рекомендуется редактировать, добавлять или удалять продукты, поскольку это может повлиять на метрики пейвола.
---
# File: virtual-currencies
---
---
title: "Виртуальные валюты"
description: "Определяйте внутриигровые валюты в Adapty, привязывайте их к продуктам для автоматического начисления кредитов и отслеживайте баланс каждого пользователя."
---
Чтобы создать оффер в Google Play Console:
1. Нажмите **Add offer** и выберите базовый план из списка.
2. Введите ID оффера. Он будет использоваться в аналитике и дашборде Adapty, поэтому дайте ему понятное имя.
3. Выберите критерии доступности:
1. **New customer acquisition**: оффер будет доступен только новым подписчикам, если они ранее не использовали этот оффер. Это наиболее распространённый вариант, который рекомендуется использовать по умолчанию.
2. **Upgrade**: оффер будет доступен пользователям, переходящим с другой подписки. Используйте его, когда хотите продвигать более дорогие планы существующим подписчикам — например, при переходе с бронзового на золотой уровень подписки.
3. **Developer determined**: вы можете управлять тем, кто может использовать этот оффер, через код приложения. Будьте осторожны при использовании в продакшене — есть риск мошенничества: пользователи могут снова и снова активировать бесплатную или скидочную подписку. Хороший сценарий для этого типа оффера — возврат отписавшихся пользователей.
4. Добавьте до двух ценовых фаз к офферу. Доступны три типа фаз:
1. **Free trial**: подписка бесплатна в течение заданного периода (минимум 3 дня). Это наиболее распространённый тип оффера.
2. **Single payment**: подписка дешевле при единовременной оплате. Например, обычно месячный план стоит $9.99, но с этим типом оффера первые три месяца обойдутся в $19.99 — скидка 30%.
3. **Discounted recurring payment**: подписка дешевле в течение первых `n` периодов. Например, обычно месячный план стоит $9.99, но с этим типом оффера каждый из первых трёх месяцев стоит $4.99 — скидка 50%.
Оффер может иметь две фазы. В таком случае первая фаза должна быть Free trial, а вторая — либо Single payment, либо Discounted recurring payment. Они применяются именно в этом порядке.
:::important
Обратите внимание: пейволы, созданные с помощью Adapty Paywall Builder, отображают только первую фазу многофазного оффера Google подписки. При этом при совершении покупки пользователем все фазы оффера будут применены согласно настройкам в Google Play.
:::
5. Активируйте оффер, чтобы использовать его в приложении.
6. Перейдите к [добавлению оффера в Adapty](create-offer).
:::note
ID офферов могут совпадать для разных базовых планов.
:::
## Следующие шаги \{#next-steps\}
После добавления офферов продолжите настройку:
- Если у вас есть **приложения в App Store**, перейдите к [гайду по App Store](app-store-offers).
- Если у вас **только приложения в Google Play**, следуйте [этому гайду](create-offer), чтобы добавить офферы в Adapty.
---
# File: create-offer
---
---
title: "Добавление офферов в Adapty"
description: "Создавайте специальные офферы для подписок и управляйте ими с помощью инструментов Adapty."
---
Adapty позволяет предлагать пробные периоды или скидки новым, текущим или ушедшим подписчикам.
После настройки в App Store Connect или Google Play Console нужно добавить их в Adapty в два шага:
1. [Добавьте офферы к продуктам в Adapty, используя идентификаторы офферов из сторов.](#1-create-offer)
2. [Отобразите оффер во флоу или на пейволе.](#2-display-offer)
:::warning
Introductory offers (App Store) применяются автоматически, если пользователь имеет на них право. Не добавляйте их к продуктам в Adapty.
В этом гайде объясняется, как настроить promotional offers (App Store), win-back offers (App Store) и все офферы Google Play.
:::
## 0. Прежде чем начать \{#before-you-start\}
Прежде чем настраивать офферы в Adapty, убедитесь в следующем:
1. Вы создали все необходимые офферы в сторе:
- [App Store](app-store-offers)
- [Google Play](google-play-offers)
2. Вы создали [продукты](create-product) в Adapty и добавили их идентификаторы.
3. Для App Store: вы загрузили [ключ встроенных покупок для promotional offer](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers).
## 1. Добавьте оффер к продукту в Adapty \{#1-add-offer-to-product-in-adapty\}
Как только ваш promotional offer (для Play Store и App Store) или win-back offer (для App Store) настроен в сторах, добавить его в Adapty несложно:
1. Откройте [**Products**](https://app.adapty.io/products) в главном меню Adapty. Найдите продукт, к которому хотите добавить оффер.
2. Найдите нужный продукт. В колонке **Actions** нажмите кнопку **3-dot** рядом с продуктом и выберите **Edit**.
3. В окне **Edit product** нажмите **+** и выберите **Add offers**.
4. Нажмите **Add offer**.
5. Введите данные offer для продукта.
Поля для offer:
- **Offer name**: Дайте офферу название, чтобы легко находить его в Adapty. Используйте любое удобное для вас название.
- **App Store Offer type**: Выберите тип оффера App Store: Promotional или Win-back. (Introductory offers добавлять не нужно — они применяются автоматически, если доступны.)
- **App Store Offer ID**: Уникальный идентификатор оффера, [который вы задали в App Store](app-store-products).
- **Play Store Offer ID**: Аналогично — уникальный идентификатор оффера, [который вы задали в Play Store](android-products).
:::tip
Если поле **App Store Offer ID** или **Play Store Offer ID** неактивно, перейдите на вкладку **Products** и выберите ID продукта.
:::
6. (Опционально) Добавьте другие офферы, нажав **Add offer**.
7. Нажмите **Save**, чтобы сохранить офферы для продукта.
## 2. Покажите предложение \{#2-display-offer\}
Once an offer is attached to a product, surface it where users see that product — in a flow or in a paywall.
### Добавление оффера во флоу \{#add-offer-to-flow\}
В [Flow Builder](adapty-flow-builder) оффер привязывается к продукту в элементе Products. Сначала добавьте элемент продукта и назначьте ему продукты — см. [Настройка покупок](paywall-product-block).
Чтобы привязать оффер:
1. На холсте выберите карточку продукта, для которой нужно показать оффер.
2. На правой панели в разделе **Product** выберите продукт, затем выберите оффер из выпадающего списка **Select offer (optional)**.
### Добавление оффера на пейвол \{#add-offer-to-paywall\}
:::info
Нельзя добавлять офферы на пейволы в статусе **live**. Если вы хотите добавить оффер на существующий пейвол, [создайте его копию](duplicate-paywalls) и настройте продукты в новом пейволе.
:::
Чтобы оффер стал виден и доступен для выбора пользователями в [пейволе](paywalls), выполните следующие шаги:
1. При создании или редактировании пейвола на вкладке **General** добавьте продукт, к которому вы только что добавили офер.
2. Выберите ранее созданный офер для этого продукта из списка **Offer**. Список доступен только для продуктов, у которых есть оферы.
3. При необходимости добавьте другие продукты и оферы, но для каждого продукта можно добавить только один офер.
## Как Adapty работает с офферами \{#how-adapty-works-with-offers\}
Обратите внимание на то, как работают офферы в Adapty:
- Когда пользователь имеет право на оффер, Adapty автоматически применяет настроенный вами оффер при совершении покупки.
- Если продукт содержит как introductory offer, так и promotional offers, настроенные в App Store, подходящие пользователи сначала получат introductory offer. После окончания его периода, если пользователь по-прежнему имеет право на promotional offer и вы настроили этот оффер в Adapty, он будет применён при следующей попытке приобрести продукт.
- Если вам нужен более тонкий контроль над применением офферов или необходимо продавать продукт без офферов в отдельных случаях, у вас есть несколько вариантов:
- Настройте критерии eligibility в App Store или Google Play Console
- Создайте отдельный продукт без офферов в App Store или Google Play Console
- Создайте отдельный продукт без офферов в Adapty, добавьте пейволы с обоими вариантами продукта в [плейсмент](placements) и используйте [сегменты](segments) аудитории, чтобы управлять тем, какой пейвол показывается разным пользователям. Например, можно создать сегменты на основе **Subscription product** или **Paid access level**, либо использовать [кастомные атрибуты](profiles-crm) для реализации собственной логики.
---
# File: create-access-level
---
---
title: "Создание уровня доступа"
description: "Создавайте и назначайте уровни доступа в Adapty для более точной сегментации пользователей."
---
Уровни доступа позволяют управлять тем, что пользователи могут делать в вашем приложении, без жёсткой привязки к конкретным идентификаторам продуктов. Каждый продукт определяет, на какой срок пользователь получает тот или иной уровень доступа. Таким образом, при каждой покупке Adapty предоставляет доступ к приложению на определённый период (для подписок) или навсегда (для покупок с пожизненным доступом).
При создании приложения в дашборде Adapty автоматически генерируется уровень доступа `premium`. Он является уровнем доступа по умолчанию и не может быть удалён.
:::tip
Вы также можете создавать уровни доступа программно с помощью [Developer CLI](developer-cli-reference#adapty-access-levels-create).
:::
Чтобы создать новый уровень доступа:
1. Перейдите в раздел **[Products](https://app.adapty.io/access-levels)** из главного меню Adapty и выберите вкладку **Access levels**.
2. Нажмите **Create access level**.
3. В открывшемся окне **Create access level** задайте идентификатор уровня доступа. Этот ID будет использоваться в вашем мобильном приложении для предоставления доступа к дополнительным функциям после покупки, а также для отличия одного уровня доступа от других. Выбирайте понятный и легко читаемый идентификатор.
4. Нажмите **Create access level**, чтобы подтвердить создание уровня доступа.
---
# File: assigning-access-level-to-a-product
---
---
title: "Привязка уровня доступа к продукту"
description: "Привязывайте уровни доступа к продуктам для удобного управления подписками."
---
Каждый [продукт](product) должен быть связан с уровнем доступа — это гарантирует, что после покупки пользователь получит доступ к нужному контенту. Adapty автоматически определяет длительность подписки и использует её как дату истечения уровня доступа. Если пользователь приобретает продукт с пожизненным доступом, уровень доступа остаётся активным бессрочно.
Чтобы привязать уровень доступа к продукту:
1. При [настройке продукта](create-product) выберите нужный уровень доступа из списка **Access Level ID**.
2. Нажмите **Save**.
---
# File: give-access-level-to-specific-customer
---
---
title: "Выдать уровень доступа конкретному пользователю"
description: "Назначайте определённые уровни доступа пользователям с помощью инструментов Adapty."
---
Вы можете вручную изменить уровень доступа для конкретного пользователя прямо в дашборде Adapty. Это удобно, например, в сценариях поддержки — скажем, если вы хотите продлить премиум-доступ пользователю на неделю в знак благодарности за отличный отзыв.
## Выдать уровень доступа конкретному пользователю в дашборде Adapty \{#give-access-level-to-a-specific-customer-in-the-adapty-dashboard\}
1. Перейдите в раздел **[Profiles and Segments](https://app.adapty.io/placements)** главного меню Adapty.
2. Нажмите на пользователя, которому хотите предоставить доступ.
3. Нажмите **Add access level**.
4. Выберите уровень доступа для предоставления и срок его действия для данного пользователя.
5. Нажмите **Apply**.
## Выдать уровень доступа конкретному пользователю через API \{#give-access-level-to-a-specific-customer-via-api\}
Вы также можете назначить уровень доступа пользователю со своего сервера через Adapty API. Это удобно, если у вас есть бонусы за рефералов или другие события, связанные с вашими продуктами. Подробнее — на странице [Выдача уровня доступа через серверный API](api-adapty/operations/grantAccessLevel).
---
# File: local-access-levels
---
---
title: "Локальные уровни доступа"
description: "Управляйте уровнями доступа в случае временных сбоев."
---
:::important
Обратите внимание на следующее:
- Локальные уровни доступа поддерживаются в Adapty SDK начиная с версии 3.12.
- По умолчанию локальные уровни доступа отключены на Android из соображений безопасности. Если они вам нужны, включите их при инициализации SDK: [Android](sdk-installation-android#enable-local-access-levels), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter#enable-local-access-levels-android).
:::
Каждый настроенный вами продукт связан с [**уровнем доступа**](access-level). Когда пользователь совершает покупку, Adapty SDK присваивает уровень доступа [профилю](profiles-crm) пользователя — именно по нему вы определяете, может ли пользователь получить доступ к платному контенту в приложении.
Adapty SDK очень надёжен, и его серверы крайне редко бывают недоступны. Но даже в этом редком случае ваши пользователи ничего не заметят.
Если пользователь совершил покупку, но Adapty не может получить ответ, SDK переключается на прямую проверку покупок в сторе. В этом случае уровень доступа предоставляется локально в приложении — никаких дополнительных настроек для этого не требуется. SDK делает всё это автоматически в фоновом режиме, и пользователи получат доступ к тому, за что заплатили, как обычно.
Обратите внимание на особенности работы локальных уровней доступа:
- Когда пользователи снова выходят в сеть, информация о транзакциях автоматически передаётся на серверы Adapty, которые применяют транзакции к профилю пользователя и возвращают обновлённый профиль в SDK.
- Обновлённые данные не появятся в аналитике Adapty до тех пор, пока данные не будут переданы.
- Локальные уровни доступа работают только когда серверы Adapty недоступны. В остальных случаях SDK использует кешированные данные.
- Локальные уровни доступа не работают для расходуемых покупок, за исключением случаев, когда расходуемому продукту в дашборде Adapty назначен тип подписки (ежемесячная, ежегодная, еженедельная и т. д.).
---
# File: choose-meaningful-placements
---
---
title: "Выбирайте значимые плейсменты"
description: "Оптимизируйте плейсменты флоу и пейволов в Adapty для повышения вовлечённости пользователей и увеличения дохода."
---
При [создании плейсментов](create-placement) важно учитывать логику флоу вашего приложения и пользовательский опыт, который вы хотите создать. В большинстве приложений достаточно не более 5 [плейсментов](placements), чтобы при этом сохранить возможность проводить эксперименты. Вот пример того, как можно организовать плейсменты:
1. **Онбординг-флоу:** Это первое взаимодействие пользователей с вашим приложением. Отличный момент, чтобы показать ценность продукта — объедините здесь флоу, онбординг и пейвол-плейсменты. Более 80% подписок оформляется именно во время онбординга, поэтому важно делать акцент на самых прибыльных подписках. С Adapty вы легко настроите разные [флоу](adapty-flow-builder), [онбординги](onboardings) и [пейволы](paywalls) для разных аудиторий и запустите A/B-тесты, чтобы найти лучший вариант для своего приложения. Например, можно запустить A/B-тест для пользователей из США, показывая более дорогие подписки в 50% случаев.
2. **Настройки приложения:** Если пользователь не оформил подписку во время онбординга, создайте флоу или пейвол-плейсмент внутри приложения — в настройках или после выполнения какого-то целевого действия. Поскольку пользователи внутри приложения обдумывают подписку более взвешенно, продукты здесь могут быть немного дешевле, чем на этапе онбординга.
3. **Промо:** Если пользователь так и не оформил подписку после нескольких просмотров флоу или пейвола, возможно, цены для него слишком высоки или он в целом скептически относится к подпискам. В таком случае покажите ему специальное предложение с самой доступной подпиской или даже с продуктом с пожизненным доступом. Это поможет привлечь тех, кто чувствителен к цене или сомневается в необходимости подписки.
В большинстве приложений логика и плейсменты схожи — они следуют пути пользователя и ключевым точкам, в которых можно показывать флоу, пейволы, онбординги или A/B-тесты для роста конверсий и дохода. Вы можете настраивать их в каждом плейсменте, чтобы экспериментировать и оптимизировать стратегии монетизации.
---
# File: create-placement
---
---
title: "Создание плейсмента"
description: "Создавайте плейсменты в Adapty и управляйте ими для улучшения работы флоу и пейволов."
---
[Плейсмент](placements) — это конкретное место в мобильном приложении, где можно показать флоу, пейвол, онбординг или A/B-тест. Например, выбор подписки может появляться во флоу при запуске приложения, а расходуемый продукт (например, золотые монеты) — когда у пользователя заканчиваются монеты в игре.
В разных плейсментах или для разных сегментов пользователей можно показывать одни и те же или разные флоу, пейволы, онбординги или A/B-тесты — в Adapty такие сегменты называются «аудиториями».
Советы по выбору подходящих плейсментов читайте в разделе [Выбор значимых плейсментов](choose-meaningful-placements).
:::tip
Вы также можете создавать плейсменты программно с помощью [Developer CLI](developer-cli-reference#adapty-placements-create).
:::
:::info
Хотя процесс создания плейсментов похож для флоу, пейволов и онбордингов, нельзя создать один плейсмент, который обслуживает более одного типа — каждый тип плейсмента обрабатывает разные метрики.
:::
## Создание и настройка плейсмента \{#create-and-configure-a-placement\}
1. Перейдите в раздел **[Placements](https://app.adapty.io/placements)** главного меню Adapty. Выберите вкладку **Flows**, **Paywalls** или **Onboardings** в зависимости от типа плейсмента, который хотите создать.
2. Нажмите **Create placement**.
3. Введите **Placement name** — внутренний идентификатор в дашборде Adapty. При необходимости его можно изменить позже.
4. Введите **Placement ID** — этот идентификатор используется в SDK для вызова [флоу](adapty-flow-builder), [пейволов](paywalls), [онбордингов](onboardings) и [A/B-тестов](ab-tests) плейсмента. Изменить его позже не получится, так как он уникален для каждого плейсмента.
Затем назначьте плейсменту флоу, пейвол, онбординг или A/B-тест. Adapty поддерживает [аудитории](audience) — сегменты пользователей на основе [сегментов](segments) — так что вы можете показывать разный контент разным группам пользователей. Если таргетинг не нужен, аудитория *All users* по умолчанию охватывает всех.
:::note
Прежде чем продолжить, убедитесь, что вы создали флоу, пейвол, онбординг или A/B-тест, который хотите запустить, а также аудиторию, которую хотите указать.
:::
1. В окне **Placements/ Your placement** добавьте флоу, пейвол, онбординг или A/B-тест для отображения аудитории *All users* по умолчанию. Для этого нажмите кнопку **Run flow**, **Run paywall** или **Run A/B test** (название зависит от типа плейсмента), затем выберите нужный флоу, пейвол, онбординг или A/B-тест из выпадающего списка.
2. Если вы хотите использовать в плейсменте несколько аудиторий для создания персонализированного контента для разных групп пользователей, нажмите кнопку **Add audience** и выберите нужный сегмент пользователей из списка.
Экспортированный CSV-файл содержит следующую информацию о ваших плейсментах:
- ID плейсмента
- Название плейсмента
- Название аудитории
- Название сегмента
- Название кросс-плейсментного A/B-теста
- Название A/B-теста
- Название флоу, пейвола или онбординга (в зависимости от вкладки, из которой был выполнен экспорт)
:::note
Кросс-плейсментные A/B-тесты не поддерживаются для плейсментов с флоу, поэтому этот столбец будет пустым в экспортах флоу.
:::
---
# File: delete-placement
---
---
title: "Удаление плейсмента"
description: "Узнайте, как удалить плейсмент в Adapty, не затрагивая работу флоу или пейвола."
---
[Плейсмент](placements) — это конкретное место в вашем мобильном приложении, где может отображаться флоу, пейвол, онбординг или A/B-тест.
:::danger
Хотя у вас есть возможность удалить любой плейсмент, крайне важно не удалять плейсмент, который активно используется в вашем мобильном приложении. Удаление активного флоу или плейсмента пейвола приведёт к тому, что резервный пейвол будет показываться постоянно, если вы его [настроили](fallback-paywalls), и вы никогда не сможете заменить его динамическим флоу или пейволом в уже выпущенных версиях приложения.
:::
Чтобы удалить существующий плейсмент:
1. Перейдите в **[Placements](https://app.adapty.io/placements)** из главного меню Adapty. Переключитесь на вкладку **Flows**, **Paywalls** или **Onboardings** в зависимости от типа плейсмента, который нужно удалить.
2. Нажмите кнопку **3-dot** рядом с плейсментом и выберите **Delete**.
3. В открывшемся окне **Delete placement** введите название плейсмента, который вы собираетесь удалить.
4. Нажмите кнопку **Delete forever**, чтобы подтвердить удаление.
---
# File: add-audience-paywall-ab-test
---
---
title: "Добавление аудитории и флоу, пейвола или A/B-теста к плейсменту"
description: "Запускайте A/B-тесты для флоу и пейволов с разными сегментами аудитории в Adapty."
---
:::note
Прежде чем продолжить, убедитесь, что вы создали флоу, пейвол, онбординг или A/B-тест, который хотите запустить, а также аудиторию, которую хотите указать.
:::
1. В окне **Placements/ Your placement** добавьте флоу, пейвол, онбординг или A/B-тест для отображения аудитории *All users* по умолчанию. Для этого нажмите кнопку **Run flow**, **Run paywall** или **Run A/B test** (название зависит от типа плейсмента), затем выберите нужный флоу, пейвол, онбординг или A/B-тест из выпадающего списка.
2. Если вы хотите использовать в плейсменте несколько аудиторий для создания персонализированного контента для разных групп пользователей, нажмите кнопку **Add audience** и выберите нужный сегмент пользователей из списка.
В этом случае используется приоритет аудитории. Приоритет аудитории — это числовой порядок, где #1 — наивысший. Он определяет последовательность, в которой проверяются аудитории. Проще говоря, приоритет аудитории помогает Adapty решить, какую аудиторию применить первой при выборе пейвола, онбординга или A/B-теста для отображения. Если приоритет аудитории низкий, подходящие пользователи могут быть пропущены и направлены в другую аудиторию с более высоким приоритетом.
Кросс-плейсментные аудитории, то есть созданные для [кросс-плейсментных A/B-тестов](ab-tests#ab-test-types), всегда имеют приоритет над обычными аудиториями.
Аудитория «Все пользователи» всегда имеет наименьший приоритет, поскольку является резервной и включает всех, кто не попал ни в одну другую аудиторию.
Чтобы изменить приоритеты аудиторий в плейсменте:
1. При создании нового или редактировании существующего плейсмента нажмите **Edit priority**. Кнопка отображается только если в плейсмент добавлено не менее трёх аудиторий («Все пользователи» и ещё две). Если аудиторий меньше, порядок очевиден — аудитория «Все пользователи» идёт последней.
2. В открывшемся окне **Edit audience priorities** перетащите аудитории в нужном порядке.
3. Нажмите кнопку **Save**.
---
# File: placement-metrics
---
---
title: "Метрики плейсментов"
description: "Анализируйте метрики плейсментов в Adapty для улучшения эффективности пейволов."
---
С Adapty вы можете создавать и управлять несколькими плейсментами в приложении, каждый из которых связан с отдельными пейволами или A/B-тестами. Это позволяет таргетировать конкретные сегменты пользователей, экспериментировать с различными предложениями или моделями ценообразования и оптимизировать стратегию монетизации приложения.
Для сбора ценной информации о работе ваших плейсментов и вовлечённости пользователей Adapty отслеживает различные взаимодействия и транзакции, связанные с отображаемыми пейволами. Система аналитики фиксирует такие метрики, как просмотры, уникальные просмотры, покупки, триалы, возвраты, конверсию и выручку.
Собранные метрики непрерывно обновляются в реальном времени и доступны для анализа в удобном дашборде Adapty. Вы можете настраивать временной диапазон анализа, применять фильтры по различным параметрам и сравнивать метрики по плейсментам, сегментам пользователей или продуктам.
Метрики плейсментов доступны в списке плейсментов, где можно получить общее представление о работе всех ваших плейсментов. Этот обзорный вид предоставляет агрегированные метрики по каждому плейсменту, что позволяет сравнивать их эффективность и выявлять тенденции.
Для более детального анализа каждого плейсмента можно перейти к подробным метрикам плейсмента. На этой странице вы найдёте исчерпывающие метрики для выбранного плейсмента. Они дают глубокое понимание того, как работает конкретный плейсмент, и помогают оценить его эффективность и принимать решения на основе данных.
### Фильтрация метрик по дате установки \{#filter-metrics-by-install-date\}
Метрики пейволов, триалов и покупок можно группировать по двум разным датам:
- **Дата события** — когда был просмотрен пейвол, начался триал или совершена покупка.
- **Дата установки** — когда пользователь впервые открыл приложение.
Два режима могут показывать очень разные цифры для одного и того же периода. Чекбокс **Filter metrics by install date** определяет, какой из них использует дашборд:
- **Не отмечен (по умолчанию)**: метрики группируются по дате события.
- **Отмечен**: метрики группируются по дате установки.
**Пример.** Вы задаёте период с 1 по 30 апреля и смотрите на триалы.
- **Не отмечен**: показывает триалы, которые *начались* в апреле, независимо от того, когда эти пользователи установили приложение.
- **Отмечен**: показывает триалы от пользователей, которые *установили* приложение в апреле, независимо от того, когда у них начались триалы.
Используйте режим по дате установки, чтобы оценить эффективность привлечения пользователей для конкретной когорты. Используйте режим по дате события, чтобы измерить активность пейвола или онбординга за конкретный период.
### Управление метриками \{#metrics-controls\}
Система отображает метрики за выбранный период и организует их по параметру левого столбца с четырьмя уровнями вложенности.
#### Варианты отображения данных метрик \{#view-options-for-metrics-data\}
На странице метрик плейсмента доступны два варианта отображения данных метрик: по пейволам и по аудиториям.
В режиме группировки по пейволам метрики сгруппированы по плейсментам, связанным с пейволом. Это позволяет анализировать метрики в разрезе разных плейсментов.
В режиме группировки по аудиториям метрики сгруппированы по целевой аудитории пейвола. Это позволяет оценивать метрики для разных сегментов аудитории.
#### Временные диапазоны \{#time-ranges\}
Вы можете выбрать один из нескольких временных периодов для анализа данных метрик — дни, недели, месяцы или произвольный диапазон дат.
#### Доступные фильтры и группировка \{#available-filters-and-grouping\}
:::link
Основная статья: [Управление аналитикой](controls-filters-grouping-compare-proceeds)
:::
Adapty предлагает мощные инструменты для фильтрации и настройки анализа метрик под ваши задачи. На странице метрик доступны различные временные диапазоны, параметры группировки и варианты фильтрации.
- ✅ Фильтрация по: аудитории, пейволу, группе пейволов, плейсменту, стране, стору.
- ✅ Группировка по: сегменту, стору и продукту
#### График отдельной метрики \{#single-metrics-chart\}
Один из ключевых компонентов страницы метрик плейсмента — раздел с графиком, который наглядно отображает выбранные метрики и упрощает их анализ.
Раздел с графиком на странице метрик плейсментов включает горизонтальную столбчатую диаграмму, которая наглядно отображает значения выбранной метрики. Каждый столбец соответствует отдельному значению метрики и масштабируется пропорционально, что позволяет сразу оценить данные. Горизонтальная ось показывает анализируемый временной диапазон, а вертикальный столбец — числовые значения метрик. Суммарное значение всех метрик отображается рядом с графиком.
Кроме того, нажав на значок стрелки в правом верхнем углу раздела графика, можно развернуть вид и отобразить выбранные метрики на полной строке графика.
#### Сводка общих метрик \{#total-metrics-summary\}
Рядом с графиком отдельной метрики отображается раздел сводки по всем метрикам — он показывает накопленные значения выбранных метрик на конкретный момент времени. Отображаемую метрику можно изменить через выпадающее меню.
### Определения метрик \{#metrics-definitions\}
Раскройте потенциал метрик плейсментов с помощью наших подробных определений. От выручки до коэффициентов конверсии — получайте ценные инсайты, которые прокачают ваши стратегии монетизации и помогут приложению расти.
:::note
Adapty конвертирует другие валюты в USD по курсу [currencylayer.com](https://currencylayer.com/) (обновляется каждые 8 часов). Курс **фиксируется на момент транзакции** — последующие изменения не влияют на результат конвертации.
:::
#### Выручка \{#revenue\}
Эта метрика отображает общую сумму дохода в USD от покупок и продлений в рамках конкретных плейсментов. Обратите внимание: при расчёте дохода комиссия App Store или Google Play не учитывается — сумма рассчитывается до вычета каких-либо комиссий.
#### Proceeds \{#proceeds\}
Эта метрика отражает фактическую сумму в USD, которую владелец приложения получает от покупок и продлений в конкретных плейсментах после вычета комиссии Apple App Store или Google Play Store. Она показывает чистую выручку, которая напрямую влияет на доход приложения. Подробнее о том, как рассчитываются поступления, читайте в [документации](analytics-cohorts#revenue-vs-proceeds) Adapty.
#### ARPPU
ARPPU означает Average Revenue Per Paying User — средний доход на одного платящего пользователя в рамках конкретных плейсментов. Рассчитывается как общий доход, делённый на количество уникальных платящих пользователей. Например, если общий доход составляет $15 000, а платящих пользователей 1 000, то ARPPU равен $15.
#### ARPAS
ARPAS, или Average revenue per active subscriber (средний доход на одного активного подписчика), показывает средний доход, получаемый с одного активного подписчика в рамках конкретных плейсментов. Рассчитывается как отношение общего дохода к числу подписчиков, активировавших пробный период или подписку. Например, если общий доход составляет $5 000, а подписчиков 1 000, то ARPAS равен $5. Эта метрика помогает оценить средний потенциал монетизации в расчёте на одного подписчика.
#### ARPU \{#arpu\}
Только для плейсментов онбординга. ARPU — это средняя выручка на пользователя, просмотревшего онбординг. Рассчитывается как общая выручка, делённая на количество уникальных просмотров.
#### Уникальный CR до покупки \{#unique-cr-to-purchases\}
Уникальный коэффициент конверсии до покупки рассчитывается как отношение количества покупок в определённых плейсментах к количеству уникальных просмотров. Он отражает соотношение покупок к уникальному числу просмотров, позволяя оценить эффективность конвертации уникальных посетителей в конкретных плейсментах в платящих пользователей.
#### CR до покупки \{#cr-to-purchases\}
Конверсия в покупки рассчитывается путём деления количества покупок в конкретных плейсментах на общее количество просмотров пейволов. Она показывает, какой процент просмотров в конкретных плейсментах завершается покупкой, и позволяет оценить эффективность вашего пейвола с точки зрения конвертации пользователей в платящих клиентов.
#### Уникальный CR в триалы \{#unique-cr-to-trials\}
Уникальная конверсия в триалы рассчитывается как отношение числа запущенных триалов в конкретных плейсментах к числу уникальных просмотров. Она показывает, какой процент уникальных просмотров в конкретных плейсментах завершился активацией триала, и помогает оценить эффективность пейвола в части конверсии уникальных посетителей в пользователей триала.
#### Покупки \{#purchases\}
Покупки представляют собой совокупный итог различных транзакций, совершённых на пейволе в конкретных плейсментах. В эту метрику включены следующие транзакции (продления не учитываются):
- Новые покупки, совершённые непосредственно в конкретных плейсментах.
- Конверсии триалов, изначально активированных в конкретных плейсментах.
- Даунгрейды, апгрейды и кросс-грейды подписок, оформленных в конкретных плейсментах.
- Восстановления подписок в конкретных плейсментах — например, когда подписка возобновляется после истечения без автопродления.
Учитывая все эти типы транзакций, метрика покупок даёт полное представление об общей активности по привлечению пользователей и монетизации в конкретных плейсментах.
#### Триалы \{#trials\}
Метрика «Trials» отражает общее количество пробных периодов, активированных в конкретных плейсментах. Она показывает, сколько пользователей начали пробный период через ваш пейвол в этих плейсментах. Метрика помогает отслеживать эффективность пробного предложения и даёт представление о вовлечённости пользователей и конверсии из пробных периодов в платные подписки.
#### Trials canceled \{#trials-canceled\}
Метрика «отменённые триалы» показывает количество триалов в конкретных плейсментах, в которых была отключена функция автопродления. Это происходит, когда пользователи вручную отказываются от триала, давая понять, что не планируют продолжать подписку после окончания пробного периода. Отслеживание отменённых триалов даёт ценную информацию о поведении пользователей и позволяет понять, с какой частотой они отказываются от триала в конкретных плейсментах.
#### Возвраты \{#refunds\}
Метрика возвратов отражает количество возвращённых покупок и подписок в рамках конкретных плейсментов. Сюда входят транзакции, которые были отменены или возвращены по различным причинам: по запросу пользователя, из-за проблем с оплатой или по другим основаниям согласно применимой политике возвратов.
#### Процент возвратов \{#refund-rate\}
Процент возвратов рассчитывается как отношение количества возвратов в конкретных плейсментах к числу первичных покупок (продления не учитываются). Например, если было 5 возвратов и 1 000 первичных покупок, процент возвратов составит 0,5%.
#### Просмотры \{#views\}
Метрика просмотров показывает общее количество раз, когда пользователи видели пейвол в конкретных плейсментах. Каждое посещение пейвола считается отдельным просмотром. Отслеживание просмотров помогает понять уровень вовлечённости и активность пользователей на пейволе, даёт представление об их поведении и об эффективности размещения и дизайна пейвола в конкретных разделах приложения.
#### Уникальные просмотры \{#unique-views\}
Метрика уникальных просмотров отражает количество уникальных случаев, когда пользователи просматривали пейвол в конкретных плейсментах. В отличие от общего числа просмотров, где каждое посещение считается отдельным, уникальные просмотры учитывают каждого пользователя только один раз — вне зависимости от того, сколько раз он открывал пейвол в этих плейсментах. Отслеживание уникальных просмотров даёт более точное представление о вовлечённости пользователей и охвате пейвола в конкретных плейсментах, поскольку в фокусе — отдельные пользователи, а не общее число визитов.
#### Завершения и уникальные завершения \{#completions--unique-completions\}
Только для плейсментов с онбордингом. Завершения — это количество раз, когда пользователи проходят плейсмент с онбордингом от первого до последнего экрана. Если кто-то прошёл его дважды, это два **завершения**, но одно **уникальное завершение**.
#### Процент уникальных завершений \{#unique-completions-rate\}
Только для плейсментов с онбордингом. Количество уникальных завершений, делённое на количество уникальных просмотров. Эта метрика помогает понять, как пользователи взаимодействуют с плейсментом онбординга, и при необходимости внести изменения, если вы замечаете, что пользователи его игнорируют.
---
# File: create-paywall
---
---
title: "Создание пейвола"
description: "Узнайте, как создавать высококонверсионные пейволы с помощью Paywall Builder от Adapty."
---
[Пейвол](paywalls) — это конфигурация в Adapty, определяющая, какие продукты предлагать пользователям. В Adapty пейволы — единственный способ получать продукты в приложении.
Пейвол нужен вне зависимости от того, как вы его отображаете:
- [**Paywall Builder**](adapty-paywall-builder): Дизайн экрана в визуальном редакторе без кода. Adapty отрисовывает его и обрабатывает покупки.
- **Кастомный пейвол**: Реализуйте собственный UI и используйте конфигурацию пейвола для получения продуктов.
После создания назначьте пейвол [плейсменту](placements) — плейсменты определяют, какой пейвол видят пользователи. Продукты опубликованного пейвола зафиксированы, поэтому его метрики всегда отражают одну и ту же комбинацию, что позволяет сравнивать эффективность разных наборов продуктов и цен.
:::tip
Вы также можете создавать пейволы программно с помощью [Developer CLI](developer-cli-reference#adapty-paywalls-create).
:::
## Дальнейшие шаги \{#next-steps\}
После создания первого пейвола:
1. Добавьте его в [плейсмент](placements). Идентификаторы плейсментов — единственные захардкоженные сущности. Они используются для получения продуктов для продажи.
2. Дальнейшая работа с пейволом зависит от вашей реализации:
- Если вы хотите использовать [Adapty Paywall Builder](adapty-paywall-builder), оформите пейвол в визуальном редакторе без кода. Adapty отрисует пейвол и обработает логику покупки, а вам останется только отобразить его в коде приложения.
- Если вы используете кастомный пейвол, воспользуйтесь нашими гайдами по реализации встроенных покупок с Adapty для вашей платформы:
- [iOS](ios-implement-paywalls-manually)
- [Android](android-implement-paywalls-manually)
- [React Native](react-native-implement-paywalls-manually)
- [Flutter](flutter-implement-paywalls-manually)
- [Unity](unity-implement-paywalls-manually)
- [Kotlin Multiplatform](kmp-implement-paywalls-manually)
---
# File: customize-paywall-with-remote-config
---
---
title: "Дизайн пейвола с Remote Config"
description: "Настройте свой пейвол с помощью Remote Config в Adapty для более точного таргетинга."
---
:::important
Этот гайд описывает Remote Config для классических пейволов. Для Flow Builder см. [Настройка флоу с помощью Remote Config](customize-flow-with-remote-config).
:::
Remote Config пейвола — мощный инструмент, предоставляющий гибкие возможности настройки. Он позволяет использовать произвольные JSON-данные для точной конфигурации пейволов. С его помощью можно задавать такие параметры, как заголовки, изображения, шрифты, цвета и многое другое.
3. Перейдите на вкладку **Remote config**.
Remote Config имеет 2 режима просмотра:
- [Таблица](customize-paywall-with-remote-config#table-view-of-the-remote-config)
- [JSON](customize-paywall-with-remote-config#json-view-of-the-remote-config)
Оба режима — **Table** и **JSON** — содержат одинаковые элементы конфигурации. Разница лишь в удобстве: режим таблицы предоставляет контекстное меню, которое может пригодиться для исправления ошибок локализации.
Переключаться между режимами можно в любой момент, нажав на вкладку **Table** или **JSON**.
Какой бы вид настройки пейвола вы ни выбрали, позже вы сможете получить эти данные из SDK с помощью свойств `remoteConfig` или `remoteConfigString` объекта `AdaptyPaywall` и внести нужные изменения в пейвол. Вы также можете программно обновлять значения Remote Config через [серверный API](api-adapty/operations/updatePaywall), чтобы динамически изменять конфигурацию пейвола без ручного обновления в дашборде. Вот несколько примеров того, как можно использовать Remote Config.
### Табличное представление Remote Config \{#table-view-of-the-remote-config\}
Если вы редко работаете с кодом и вам нужно подправить отдельные значения JSON, воспользуйтесь режимом **Table** в Adapty.
Это копия вашего JSON в формате таблицы, которую удобно читать и понимать. Цветовая подсветка помогает различать типы данных.
Чтобы добавить ключ, нажмите кнопку **Add row**. Мы автоматически проверяем соответствие значений и типов и показываем предупреждение, если ваши изменения могут привести к невалидному JSON.
Дополнительные параметры строк особенно полезны при [локализации пейволов](add-remote-config-locale):
Теперь нужно [создать плейсмент](create-placement) и добавить в него пейвол. После этого вы сможете
4. Нажмите **Locales** и выберите языки, которые хотите поддержать. Сохраните изменения, чтобы добавить эти локали к пейволу.
Теперь вы можете переводить контент вручную, с помощью ИИ или экспортировать файл локализации для внешних переводчиков.
## Перевод пейволов с помощью ИИ \{#translate-paywalls-with-ai\}
Перевод с помощью ИИ — быстрый и эффективный способ локализовать пейвол.
Вы можете переводить значения типа **String** и **List**. По умолчанию все строки выбраны (выделены фиолетовым). Строки, которые уже переведены, отмечены зелёным и по умолчанию не включаются в новый перевод. Невыбранные и непереведённые строки отображаются серым.
1. Выберите строки для перевода. Рекомендуется снять галочки со строк, содержащих идентификаторы, URL и переменные, чтобы ИИ их не переводил.
2. Выберите языки для перевода.
3. Нажмите **AI Translate**, чтобы применить переводы. Выбранные строки будут переведены и добавлены к пейволу, переведённые строки станут зелёными.
## Экспорт файлов локализации для внешнего перевода \{#exporting-localization-files-for-external-translation\}
Хотя локализация с помощью ИИ становится всё популярнее, вы можете предпочесть более надёжный подход — профессиональных переводчиков или проверенное переводческое агентство. В таком случае вы можете экспортировать файлы локализации, передать их переводчикам, а затем импортировать готовые переводы обратно в Adapty.
Кнопка **Export** создаёт отдельные файлы `.json` для каждого языка, упакованные в один архив. Если нужен только один файл, его можно экспортировать напрямую из меню конкретного языка.
После получения переведённых файлов используйте кнопку **Import**, чтобы загрузить их все сразу или по отдельности. Adapty автоматически проверит файлы на соответствие правильному формату.
### Формат файла для импорта \{#import-file-format\}
Чтобы импорт прошёл успешно, файл должен соответствовать следующим требованиям:
- **Имя файла и расширение:**
Имя файла должно совпадать с представляемой локалью и иметь расширение `.json`. Проверить и скопировать название локали можно в дашборде Adapty. Если имя не распознано, импорт завершится ошибкой.
- **Валидный JSON:**
Файл должен быть валидным JSON. Если это не так, импорт завершится ошибкой.
## Ручная локализация \{#manual-localization\}
Иногда может потребоваться подправить переводы, добавить разные изображения для конкретных локалей или настроить Remote Config напрямую.
1. Выберите элемент, который хотите перевести, и введите новое значение. Можно обновить значения типа **String** и **List** или заменить изображения на более подходящие для данной локали.
2. Воспользуйтесь контекстным меню в английской локали для эффективного решения проблем с локализацией:
- **Copy this value to all locales**: перезаписывает все изменения, внесённые в не-английских локалях для выбранной строки, заменяя их значением из английской локали.
- **Revert all row changes to original values**: отменяет все изменения, внесённые в текущей сессии, и восстанавливает значения до последнего сохранённого состояния.
После добавления локалей к пейволу убедитесь, что коды локалей корректно реализованы в коде приложения. См.
3. ⚠️ Если вы выбрали Stripe, убедитесь, что используете ключи из окружения **Test Mode**, несмотря на то что в интерфейсе написано **Sandbox**. Иначе веб-пейвол не будет работать. **Sandbox** в Stripe пока не поддерживается.
### Настройка верификации домена для Apple Pay \{#set-up-apple-pay-domain-verification\}
В разделе **Settings > Domains** выберите основного платёжного провайдера для верификации домена. Затем подтвердите домены своего пейвола у соответствующего провайдера:
**Stripe**:
1. Перейдите в [настройки доменов способов оплаты](https://dashboard.stripe.com/settings/payment_method_domains) и нажмите **Add a new domain**.
2. Добавьте `app.funnelfox.com` и ваш личный субдомен пейвола (он выглядит как `paywalls-....fnlfx.com`). Чтобы найти субдомен, перейдите в **Settings > Domains** и скопируйте значение **Hosted subdomain**.
**Paddle**:
1. В консоли Paddle перейдите в **Checkout > Website approval** и нажмите **Add a new domain**.
2. Добавьте `app.funnelfox.com` и ваш личный субдомен пейвола (он выглядит как `paywalls-....fnlfx.com`). Чтобы найти субдомен, перейдите в **Settings > Domains** и скопируйте значение **Hosted subdomain**.
Процесс проверки в Paddle выполняется вручную, поэтому нужно подождать, пока домены не перейдут из статуса `Pending` в `Approved`.
**FunnelFox Billing**:
Следуйте [инструкциям по интеграции FunnelFox Billing](https://funnelfox.com/docs/billing/integration-billing-funnelfox).
**SolidGate**:
1. В вашем дашборде Solidgate перейдите в **Developers > Apple Pay Domains**.
2. Нажмите **+ Add new domain** и вставьте домен вашего проекта (из **Settings > Domains** в FunnelFox). При необходимости добавьте также ваш кастомный домен.
3. Чтобы использовать Apple Pay в режиме предварительного просмотра, также добавьте `http://app.funnelfox.com/`.
## Создание и настройка веб-пейвола \{#create-and-configure-a-web-paywall\}
1. На странице со списком веб-пейволов нажмите **Create a paywall**.
2. Введите название пейвола и нажмите **Create**.
3. Вы будете перенаправлены на базовый шаблон с двумя вариантами подписки и кнопкой покупки через Apple Pay.
На первом экране отображается список планов подписки. Второй и третий экраны — это экраны оформления заказа. Каждый экран соответствует одному из предлагаемых вами планов. Если у вас только один план, удалите лишний экран. Если планов больше, нужно продублировать экраны оформления заказа.
Последний экран, который видит пользователь после успешной покупки, — это место, где нужно чётко указать, что он может вернуться в ваше приложение.
4. Настройте список планов: добавьте или удалите планы и цены. Все цены и планы на экране не добавляются автоматически, поэтому их нужно настраивать вручную.
5. Добавьте или настройте экран оформления заказа для каждого плана. Рекомендуем добавлять итоговую сумму на каждый экран оформления, чтобы пользователи видели стоимость до нажатия кнопки покупки.
6. На экранах оформления заказа уже есть кнопка Apple Pay. Чтобы она работала, настройте на каждом экране следующее:
1. **Product type**: выберите, хотите ли вы добавить пробный период или скидку.
2. **Trial period**: укажите длительность пробного периода.
3. **Product**: выберите продукт из вашего платёжного провайдера.
:::important
Убедитесь, что продукт добавлен в Adapty. Иначе результат покупки будет установлен по умолчанию.
:::
4. **Subscription discount**: при необходимости выберите купон из вашего платёжного провайдера.
7. Теперь нужно связать планы с экранами оформления заказа. На экране выбора плана нажмите кнопку **Continue** и выберите целевой экран для каждого плана.
Когда пейвол будет готов, нужно получить его ссылку для активации в Adapty. Способ получения ссылки зависит от того, тестируете вы его или запускаете в продакшн:
1. **Для тестирования в песочнице**: нажмите **Preview** в правом верхнем углу и скопируйте ссылку.
2. **Для продакшна**: нажмите **Publish** в правом верхнем углу. Нажмите **Home** и скопируйте ссылку из столбца **URL**.
Готово! Используйте эту ссылку, чтобы [продолжить настройку](web-paywall#step-2-trigger-the-paywall).
---
# File: fallback-paywalls
---
---
title: "Резервные пейволы"
description: "Используйте резервные пейволы для обеспечения бесперебойного пользовательского опыта в Adapty."
---
Чтобы обеспечить бесперебойный пользовательский опыт, важно настроить **резервные версии** ваших [пейволов](paywalls) и [онбордингов](onboardings).
Когда приложение загружает пейвол, SDK Adapty запрашивает данные конфигурации с наших серверов. Но что произойдёт, если устройство не может подключиться к Adapty из-за проблем с сетью или сбоя серверов?
* Если пользователь уже открывал пейвол ранее и устройство кешировало его данные, приложение загружает данные пейвола **из кеша**.
* Если устройство не кешировало пейвол, приложение ищет локально сохранённый файл конфигурации. Это позволяет отобразить пейвол без ошибки.
Adapty автоматически генерирует резервные файлы конфигурации, которые вы можете скачать и использовать. Каждый файл содержит платформозависимые конфигурации для *всех* ваших плейсментов.
## С чего начать \{#get-started\}
1. [Скачайте резервный файл конфигурации](/local-fallback-paywalls) из Adapty.
2. Настройте резервные пейволы с помощью SDK Adapty:
* [iOS](ios-use-fallback-paywalls)
* [Android](android-use-fallback-paywalls)
* [React Native](react-native-use-fallback-paywalls)
* [Flutter](flutter-use-fallback-paywalls)
* [Unity](unity-use-fallback-paywalls)
* [Kotlin Multiplatform](kmp-use-fallback-paywalls)
* [Capacitor](capacitor-use-fallback-paywalls)
## Ограничения \{#limitations\}
Резервные пейволы хранятся локально и имеют фиксированную конфигурацию, поэтому им недоступны динамические возможности обычных пейволов Adapty.
* Резервные пейволы не поддерживают [локализацию](paywall-localization). При генерации файла конфигурации Adapty использует локаль по умолчанию — `en`.
* Для каждого плейсмента может быть только один резервный пейвол. Если в вашей настройке предусмотрены разные конфигурации пейволов для разных [аудиторий](audience), Adapty использует конфигурацию, предназначенную для «Всех пользователей».
* Резервные пейволы не поддерживают [A/B-тесты](ab-tests). Если пейвол участвует в A/B-тесте, в резервный файл конфигурации будет включён вариант с наибольшим весом.
* Резервными пейволами нельзя [управлять удалённо](customize-paywall-with-remote-config). Для обновления файла конфигурации необходимо выпустить новую версию приложения в App Store / Google Play.
---
# File: local-fallback-paywalls
---
---
title: "Скачать резервные пейволы"
description: "Используйте локальные резервные пейволы в Adapty, чтобы обеспечить бесперебойный флоу подписок."
---
Adapty автоматически генерирует JSON-файлы конфигурации для ваших [резервных пейволов](/fallback-paywalls) — по одному на каждую платформу. Эти файлы также содержат резервные данные для онбордингов.
Если в одном плейсменте несколько пейволов или онбордингов, в резервной версии будет включён вариант с наибольшим весом или наиболее широкой аудиторией. Adapty обновляет эти файлы при каждом изменении пейволов или онбордингов.
Чтобы скачать файлы резервных конфигураций, выполните следующие шаги:
1. Откройте страницу **[Placements](https://app.adapty.io/placements)**.
2. Нажмите кнопку **Fallbacks**.
3. Выберите целевую платформу (*iOS* или *Android*) из выпадающего списка.
4. Выберите версию SDK, чтобы начать загрузку.
## После загрузки \{#after-the-download\}
Следуйте руководству по настройке для вашей платформы:
* [iOS](ios-use-fallback-paywalls)
* [Android](android-use-fallback-paywalls)
* [React Native](react-native-use-fallback-paywalls)
* [Flutter](flutter-use-fallback-paywalls)
* [Unity](unity-use-fallback-paywalls)
* [Kotlin Multiplatform](kmp-use-fallback-paywalls)
* [Capacitor](capacitor-use-fallback-paywalls)
---
# File: paywall-metrics
---
---
title: "Метрики пейвола"
description: "Отслеживайте и анализируйте метрики производительности пейволов для повышения дохода от подписок."
---
Adapty собирает ряд метрик, которые помогают лучше оценивать эффективность пейволов. Все метрики обновляются в реальном времени, за исключением просмотров — они обновляются раз в несколько минут. Все метрики, кроме просмотров, привязаны к продукту в рамках пейвола. В этом документе описаны доступные метрики, их определения и способы расчёта.
Метрики пейволов доступны в списке пейволов — здесь вы сразу видите общую картину эффективности всех пейволов. Сводное представление показывает агрегированные метрики по каждому пейволу, что позволяет оценить их результативность и найти точки роста.
Для детального анализа отдельного пейвола перейдите к метрикам конкретного пейвола. Здесь вы найдёте подробные метрики по выбранному пейволу и получите более глубокое понимание его работы.
### Фильтрация метрик по дате установки \{#filter-metrics-by-install-date\}
Метрики пейволов, триалов и покупок можно группировать по двум разным датам:
- **Дата события** — когда был просмотрен пейвол, начался триал или совершена покупка.
- **Дата установки** — когда пользователь впервые открыл приложение.
Два режима могут показывать очень разные цифры для одного и того же периода. Чекбокс **Filter metrics by install date** определяет, какой из них использует дашборд:
- **Не отмечен (по умолчанию)**: метрики группируются по дате события.
- **Отмечен**: метрики группируются по дате установки.
**Пример.** Вы задаёте период с 1 по 30 апреля и смотрите на триалы.
- **Не отмечен**: показывает триалы, которые *начались* в апреле, независимо от того, когда эти пользователи установили приложение.
- **Отмечен**: показывает триалы от пользователей, которые *установили* приложение в апреле, независимо от того, когда у них начались триалы.
Используйте режим по дате установки, чтобы оценить эффективность привлечения пользователей для конкретной когорты. Используйте режим по дате события, чтобы измерить активность пейвола или онбординга за конкретный период.
### Управление метриками \{#metrics-controls\}
Система отображает метрики за выбранный период и группирует их по параметру левой колонки с тремя уровнями вложенности.
Для активного пейвола метрики охватывают период с даты запуска до текущей даты. Для неактивных пейволов — весь период с даты запуска до конца выбранного временного диапазона. Черновики и архивные пейволы включены в таблицу метрик, но если данных по ним нет, они отображаются без метрик.
#### Варианты отображения данных метрик \{#view-options-for-metrics-data\}
На странице пейвола доступны два варианта отображения данных метрик: по плейсментам и по аудиториям.
В режиме отображения по плейсментам метрики группируются по плейсментам, связанным с пейволом. Это позволяет анализировать метрики в разрезе разных плейсментов.
В режиме просмотра по аудитории метрики сгруппированы по целевой аудитории пейвола. Пользователи могут оценить метрики, характерные для разных сегментов аудитории. Выбрать нужный режим можно через выпадающий список в верхней части страницы с детальной информацией о пейволе.
#### Временные диапазоны \{#time-ranges\}
Вы можете выбрать один из нескольких временных периодов для анализа данных метрик: конкретные дни, недели, месяцы или произвольный диапазон дат.
#### Доступные фильтры и группировка \{#available-filters-and-grouping\}
:::link
Основная статья: [Управление аналитикой](controls-filters-grouping-compare-proceeds)
:::
Adapty предоставляет мощные инструменты для фильтрации и настройки анализа метрик под ваши задачи. На странице метрик доступны различные временные диапазоны, параметры группировки и возможности фильтрации.
- Фильтрация по: аудитории, стране, пейволу, состоянию пейвола, группе пейволов, плейсменту, стране, стору, продукту и стору продукта.
- Группировка по: продукту и стору.
#### График отдельной метрики \{#single-metrics-chart\}
Один из ключевых компонентов страницы метрик пейвола — раздел с графиком, который наглядно отображает выбранные метрики и упрощает анализ.
Раздел графика на странице метрик пейвола содержит горизонтальную столбчатую диаграмму, наглядно отображающую выбранные значения метрик. Каждый столбец соответствует значению метрики и пропорционален ему по размеру, что позволяет легко воспринимать данные с первого взгляда. Горизонтальная линия показывает анализируемый временной период, а вертикальный столбец отображает числовые значения метрик. Суммарное значение всех метрик выводится рядом с графиком.
Кроме того, нажав на иконку стрелки в правом верхнем углу раздела с графиком, можно развернуть его на всю ширину и просмотреть выбранные метрики.
#### Сводка общих метрик \{#total-metrics-summary\}
Рядом с графиком отдельной метрики отображается раздел со сводкой общих метрик — он показывает накопленные значения выбранных метрик на конкретный момент времени. Отображаемую метрику можно изменить через выпадающее меню.
### Определения метрик \{#metrics-definitions\}
:::note
Adapty конвертирует другие валюты в USD по курсу [currencylayer.com](https://currencylayer.com/) (обновляется каждые 8 часов). Курс **фиксируется на момент транзакции** — последующие изменения не влияют на результат конвертации.
:::
#### Выручка \{#revenue\}
Эта метрика отражает общую сумму денег в USD, полученную от покупок и продлений. Обратите внимание, что при расчёте выручки комиссия App Store / Play Store не вычитается — сумма указывается до удержания каких-либо сборов.
#### Поступления \{#proceeds\}
Эта метрика отражает фактическую сумму в USD, которую получает владелец приложения от покупок и продлений после вычета применимой комиссии App Store / Play Store.
:::important
Уведомите Adapty, если ваше приложение участвует в программе сниженной комиссии. Для корректных расчётов укажите статус участия в программах [Small Business Program](app-store-small-business-program) и [Reduced Service Fee](google-reduced-service-fee) в [настройках приложения](general).
:::
Отражает чистый доход, который напрямую формирует выручку приложения. Подробнее о расчёте proceeds читайте в [документации](analytics-cohorts#revenue-vs-proceeds) Adapty.
#### ARPPU \{#arppu\}
ARPPU — это средний доход на одного платящего пользователя. Рассчитывается как общий доход, делённый на количество уникальных платящих пользователей. $15 000 доход / 1000 платящих пользователей = $15 ARPPU.
#### ARPAS \{#arpas\}
Средний доход на активного подписчика (ARPAS) показывает, сколько в среднем приносит каждый активный подписчик. Рассчитывается как общий доход, делённый на количество подписчиков, которые активировали пробный период или подписку. Например, если общий доход составляет $5 000, а подписчиков 1 000, то ARPAS равен $5. Эта метрика помогает оценить средний потенциал монетизации на одного подписчика.
#### Уникальный коэффициент конверсии (CR) в покупки \{#unique-conversion-rate-cr-to-purchases\}
Уникальный коэффициент конверсии в покупки рассчитывается путём деления числа покупок на количество уникальных просмотров. Например, если было совершено 10 покупок при 100 уникальных просмотрах, уникальный CR в покупки составит 10%. Эта метрика отражает соотношение покупок к уникальному числу просмотров и показывает, насколько эффективно уникальные посетители конвертируются в платящих пользователей.
#### CR в покупки \{#cr-to-purchases\}
Конверсия в покупки рассчитывается как отношение числа покупок к общему числу просмотров. Например, если было 10 покупок и 100 просмотров, конверсия в покупки составит 10%. Эта метрика показывает, какой процент просмотров заканчивается покупкой, и даёт представление об эффективности вашего пейвола в превращении пользователей в платящих клиентов.
#### Уникальная конверсия в триалы \{#unique-cr-to-trials\}
Уникальная конверсия в триалы рассчитывается как отношение количества начатых триалов к числу уникальных просмотров. Например, если было начато 30 триалов при 100 уникальных просмотрах, уникальная конверсия в триалы составит 30%. Эта метрика показывает, какой процент уникальных просмотров приводит к активации триалов, и помогает оценить эффективность пейвола в плане привлечения уникальных посетителей к пробному периоду.
#### Покупки \{#purchases\}
Purchases — это совокупное количество различных транзакций, совершённых на пейволе. В эту метрику входят следующие транзакции (продления не учитываются):
- Новые покупки, совершённые непосредственно на пейволе.
- Конвертации триалов, изначально активированных на пейволе.
- Даунгрейды, апгрейды и кросс-грейды подписок, выполненные на пейволе.
- Восстановления подписок на пейволе — например, когда подписка возобновляется после истечения срока без автопродления.
Принимая во внимание все типы транзакций, метрика покупок даёт исчерпывающее представление об общей активности по привлечению пользователей и монетизации через ваш пейвол.
#### Пробные периоды \{#trials\}
Метрика пробных периодов отражает общее количество активированных триалов. Она показывает, сколько пользователей запустили пробный период через ваш пейвол. Метрика помогает отслеживать эффективность предложения пробного периода и даёт представление о вовлечённости пользователей и их конверсии из триала в платную подписку.
#### Отменённые пробные периоды \{#trials-canceled\}
Метрика «отменённые триалы» отражает количество пробных периодов, в которых пользователь отключил автопродление. Это происходит, когда пользователь вручную отписывается от триала — то есть решает не продолжать подписку после его окончания. Отслеживание отменённых триалов даёт ценную информацию о поведении пользователей и позволяет понять, как часто они отказываются от пробного периода.
#### Возвраты \{#refunds\}
Метрика возвратов отражает количество возвращённых покупок и подписок. Сюда входят транзакции, отменённые или возвращённые по различным причинам: по запросу пользователя, из-за проблем с оплатой или в соответствии с применимой политикой возврата.
#### Процент возвратов \{#refund-rate\}
Процент возвратов рассчитывается как отношение числа возвратов к числу первичных покупок (продления не учитываются). Например, если было 5 возвратов и 1000 первичных покупок, процент возвратов составит 0,5%.
#### Просмотры \{#views\}
Метрика просмотров показывает общее количество раз, когда пользователи открывали пейвол. Каждое посещение пейвола засчитывается как отдельный просмотр. Например, если пользователь открыл пейвол дважды, это будет записано как два просмотра. Отслеживание просмотров помогает понять уровень вовлечённости пользователей и их взаимодействие с пейволом, а также оценить эффективность плейсмента и дизайна.
#### Уникальные просмотры \{#unique-views\}
Метрика уникальных просмотров отражает количество уникальных случаев, когда пользователи просматривали пейвол. В отличие от общего числа просмотров, где каждый визит считается отдельно, уникальные просмотры учитывают посещение пейвола каждым пользователем только один раз — сколько бы раз он ни заходил. Например, если пользователь посетил пейвол дважды, это будет засчитано как один уникальный просмотр. Отслеживание уникальных просмотров даёт более точное представление о вовлечённости пользователей и охвате пейвола, поскольку акцент делается на отдельных людях, а не на общем количестве визитов.
:::warning
Обязательно отправляйте данные о просмотрах пейвола в Adapty с помощью метода `.logShowFlow()` (iOS SDK v4+) / `.logShowPaywall()`. Иначе просмотры пейвола не будут учитываться в метриках, и конверсии окажутся недостоверными.
:::
---
# File: migrate-paywalls
---
---
title: "Миграция пейволов между приложениями"
description: "Узнайте, как мигрировать пейволы из других приложений в Adapty."
---
В Adapty не нужно создавать новый пейвол с нуля для каждого приложения. Если вы управляете несколькими приложениями, можно перенести конфигурацию Paywall Builder из одного приложения в другое — для любого пейвола, созданного с помощью билдера.
При миграции копируются все визуальные настройки:
- Настройки макета пейвола и всех его элементов
- Медиафайлы
- Локализация
Миграция применяется только к конфигурации билдера и не копирует продукты или Remote Config.
:::note
Если вы мигрируете конфигурацию Paywall Builder с кастомными шрифтами, проверьте их отображение на устройстве — они могут отображаться некорректно.
:::
## Миграция пейвола \{#migrate-paywall\}
:::important
Мигрировать можно только пейволы, созданные в **новом** Paywall Builder Adapty. Чтобы мигрировать пейволы из **старого** билдера, сначала необходимо перенести их в новый Paywall Builder.
:::
Чтобы мигрировать конфигурацию Paywall Builder:
1. **Для нового пейвола**: начните [создание пейвола](create-paywall) и добавьте продукты. Затем нажмите **Build no-code paywall**, чтобы открыть библиотеку шаблонов.
**Для существующего пейвола**: перейдите в раздел **Layout settings** на вкладке **Builder & Generator** и нажмите **Change template**.
2. Нажмите **Choose paywall** в блоке **Copy a design from your apps** при редактировании шаблона пейвола.
3. Выберите приложение и пейвол, конфигурацию которого хотите скопировать.
4. Нажмите **Copy Selected Paywall**.
После миграции вы можете вносить любые правки — они не затронут исходный пейвол.
---
# File: duplicate-paywalls
---
---
title: "Дублирование пейвола"
description: "Узнайте, как управлять дублированными пейволами и оптимизировать их эффективность в Adapty."
---
Если вам нужно внести небольшие изменения в существующий пейвол в Adapty — особенно когда он уже используется в вашем мобильном приложении и вы не хотите нарушить аналитику — просто продублируйте его. Дубликаты можно использовать для замены оригинальных пейволов в некоторых или во всех плейсментах по мере необходимости.
При дублировании создаётся копия пейвола со всеми его настройками: названием, продуктами и акциями. К названию нового пейвола добавляется слово «Copy», чтобы его можно было легко отличить от оригинала.
Чтобы продублировать пейвол в дашборде Adapty:
1. Откройте раздел [**Paywalls**](https://app.adapty.io/paywalls) в главном меню Adapty. На странице списка пейволов отображаются все пейволы вашего аккаунта.
2. Нажмите кнопку **3-dot** рядом с нужным пейволом и выберите **Duplicate**.
3. Настройте новый пейвол и нажмите кнопку **Save**.
4. Adapty предложит заменить оригинальные пейволы их дубликатами в плейсментах, если оригинальный пейвол уже используется в каком-либо плейсменте. Если вы выберете **Create and replace original**, новые пейволы сразу перейдут в статус **Live**. В противном случае они будут созданы как новые пейволы в статусе **Draft**, и вы сможете добавить их в плейсменты позже.
---
# File: archive-paywalls
---
---
title: "Архивирование пейвола"
description: "Узнайте, как архивировать устаревшие пейволы в Adapty без потери данных."
---
По мере работы с Adapty и настройки пейволов у вас может накопиться немало пейволов, которые больше не вписываются в текущую стратегию или кампании. Эти неиспользуемые пейволы со статусом `Inactive` загромождают рабочее пространство и затрудняют поиск нужных. Чтобы решить эту проблему, Adapty предлагает возможность архивировать ненужные пейволы.
Архивирование позволяет безопасно хранить их без окончательного удаления — при необходимости к ним всегда можно вернуться. Кроме того, архивные пейволы можно скрыть из стандартного представления, освободив рабочее пространство и упростив интерфейс. В этом гайде мы покажем, как эффективно архивировать пейволы в Adapty, чтобы вы могли управлять ими удобнее.
Важное уточнение: пейволы, которые в данный момент активны хотя бы в одном плейсменте, архивировать нельзя. Если вы хотите заархивировать такой пейвол, сначала удалите его из всех плейсментов.
:::note
Нельзя заархивировать пейвол, если он используется в неархивированном A/B-тесте. Это сделано для того, чтобы пользователь мог просматривать детальные метрики завершённого A/B-теста, а связанный пейвол оставался частью этих данных.
:::
**Чтобы заархивировать пейвол:**
1. Откройте раздел [**Paywalls**](https://app.adapty.io/paywalls) в главном меню Adapty.
2. Нажмите кнопку **3-dot** рядом с нужным пейволом и выберите **Archive**.
3. В открывшемся окне **Archive paywall** введите название пейвола, который хотите заархивировать, и нажмите кнопку **Archive**.
---
# File: restore-paywall
---
---
title: "Восстановление пейвола из архива"
description: "Восстанавливайте пейволы в Adapty, чтобы обеспечить бесперебойный доступ пользователей к подпискам."
---
Возможность архивировать пейволы значительно упрощает управление ими: вы можете скрыть ненужные пейволы и не захламлять рабочее пространство. А опция восстановления из архива даёт дополнительную гибкость — вы всегда можете вернуть пейвол в работу, если он снова окажется полезным.
Архивные пейволы могут быть скрыты в стандартном отображении. Чтобы их увидеть, выберите **Archived** в фильтре **State**.
**Чтобы вернуть пейвол из архива:**
1. Откройте раздел [**Paywalls**](https://app.adapty.io/paywalls) в главном меню Adapty.
2. Убедитесь, что архивные пейволы отображаются в списке. Если нет, обновите фильтр справа.
3. Нажмите кнопку **3-dot** рядом с архивным пейволом и выберите **Back to active**.
---
# File: profiles-crm
---
---
title: "Профили/CRM"
description: "Управляйте профилями пользователей и данными CRM в Adapty для улучшения сегментации аудитории."
---
Профили — это CRM для ваших пользователей. С помощью профилей вы можете:
1. Находите конкретных пользователей по ID профиля, customer user ID, email или ID транзакции.
2. Просматривайте временную шкалу событий пользователя, включая проблемы с оплатой, льготные периоды и другие [события](events).
3. Анализируйте свойства пользователя: статус подписки, общий доход/выручку и многое другое.
4. Выдавайте пользователю подписку.
:::note
События из ленты событий поступают на дашборд с задержкой. Новые профили и изменения атрибутов могут отображаться не сразу.
:::
:::link
Чтобы узнать, как Adapty создаёт и связывает профили пользователей, см. [Как работают профили](how-profiles-work).
:::
## Поиск пользователей \{#finding-users\}
В списке профилей можно найти конкретного пользователя по:
- **Profile ID**: внутренний идентификатор пользователя в Adapty (также называется Adapty ID).
- **Customer user ID**: идентификатор пользователя в вашем приложении, если вы его задали.
- **Email**: электронная почта пользователя, если передана как кастомный атрибут.
- **Transaction ID**: идентификатор транзакции стора из покупки.
Нажмите на любую строку, чтобы открыть полный профиль пользователя.
## Состояние подписки \{#subscription-state\}
В списке профилей вы можете фильтровать и сортировать пользователей по состоянию подписки. Доступные значения состояния:
| **Состояние** пользователя | Описание |
| :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Subscribed | У пользователя активная подписка с включённым автопродлением. |
| Auto-renew off | Пользователь отключил автопродление, но сохраняет доступ к премиум-функциям до конца оплаченного периода. |
| Subscription cancelled | Пользователь отменил подписку, и она полностью завершилась. |
| Billing issue | Пользователя не удалось списать средства из-за проблем с оплатой — после истечения подписки или пробного периода. |
| Grace period | Пользователь находится в льготном периоде из-за проблем с оплатой, возникших при попытке списать средства после истечения подписки или пробного периода. |
| Active trial | У пользователя активная подписка, которая сейчас находится в пробном периоде. |
| Trial cancelled | Пользователь отменил пробный период и не имеет активной подписки. |
| Never subscribed | Пользователь никогда не оформлял подписку и не начинал пробный период — остаётся пользователем бесплатного тарифа. |
## Атрибуты пользователя \{#user-attributes\}
Вы можете передавать дополнительные свойства пользователя в Adapty через SDK.
По умолчанию Adapty устанавливает:
| Свойство | Описание |
| ---------------- | ------------------------------------------------------------ |
| Customer user ID | Идентификатор вашего конечного пользователя в вашей системе. |
| Adapty ID | Внутренний идентификатор Adapty для вашего конечного пользователя, называемый Profile ID. |
| IDFA | Идентификатор для рекламодателей, присваиваемый Apple устройству пользователя. Требует разрешения App Tracking Transparency (ATT) на iOS 14+. Недоступен на Android. |
| Country | Страна вашего конечного пользователя. |
| OS | Операционная система конечного пользователя. |
| Device | Название модели устройства, отображаемое пользователю. |
| Install date | Дата первой записи пользователя в Adapty:
## Предоставление подписки \{#granting-a-subscription\}
В профиле можно продлить активную подписку или предоставить пользователю пожизненный доступ к уровню доступа — без необходимости совершать покупку.
Это особенно удобно в следующих случаях:
- Компенсация пользователю после проблем с оплатой или обращения в поддержку.
- Проведение ручных акций или бета-программ.
- Тестирование флоу подписок без реальной покупки.
Чтобы предоставить доступ, откройте профиль пользователя, перейдите в раздел **Access levels** и нажмите **Edit**. Установите дату истечения доступа и сохраните. Дата должна быть в будущем и не может быть уменьшена после установки. Изменение даты для активных подписок не влияет на текущие платежи.
:::note
Предоставление доступа не создаёт события покупки в App Store или Google Play. Лента событий пользователя и аналитика будут отличаться от реального флоу покупки.
:::
Также можно предоставить доступ программно с помощью метода API [Grant access level](api-adapty/operations/grantAccessLevel).
## Совместное использование платного доступа между аккаунтами пользователей \{#sharing-paid-access-between-user-accounts\}
:::link
Основная статья: [Совместное использование платного доступа между аккаунтами пользователей](sharing-paid-access-between-user-accounts)
:::
### История совместного использования уровней доступа \{#access-sharing-history\}
Когда уровни доступа передаются или используются совместно, в профиле пользователя отображается ссылка на связанный профиль — тот, который поделился доступом, или тот, который его получил. Чтобы открыть связанный профиль, в **Profile** пользователя нажмите на ссылку рядом с уровнем доступа.
:::note
Балансы виртуальной валюты не распределяются и не передаются между профилями, как уровни доступа. Каждый баланс привязан к одному профилю — подробнее см. [Балансы, профили и устройства](virtual-currency-balance#balances-profiles-and-devices).
:::
## Следующие шаги \{#next-steps\}
- Чтобы понять, как Adapty создаёт и связывает профили, см. [Как работают профили](how-profiles-work).
- Чтобы настроить политику общего доступа, см. [Общий доступ к платным функциям между аккаунтами](sharing-paid-access-between-user-accounts).
- Чтобы выдать доступ программно, см. метод API [Grant access level](api-adapty/operations/grantAccessLevel).
---
# File: how-profiles-work
---
---
title: "Как работают профили"
description: "Узнайте, как Adapty создаёт, отслеживает и связывает профили пользователей — включая анонимные профили, идентифицированных пользователей и отношения родительский/наследующий профиль."
---
Каждый пользователь вашего приложения получает профиль Adapty, в котором отслеживаются его покупки, события и состояние подписки. Понимание того, как профили создаются и связываются, поможет вам избежать ошибок интеграции, фрагментации данных и правильно интерпретировать данные в разделе [Профили](profiles-crm).
## Создание профиля \{#profile-creation\}
Adapty автоматически создаёт профиль при первом запуске приложения пользователем.
**Без Customer User ID** профиль анонимный. Новый анонимный профиль создаётся каждый раз, когда:
- Пользователь переустанавливает приложение
- Пользователь выходит из вашего приложения (когда приложение вызывает `Adapty.logout()`)
Покупки привязываются к установке приложения, а не к постоянной идентификации пользователя.
**С Customer User ID** профиль сохраняется между переустановками и на разных устройствах. Customer User ID позволяет:
1. Отслеживать пользователя при переустановке приложения и на нескольких устройствах.
2. Находить пользователей по их customer user ID в разделе [**Profiles**](profiles-crm).
3. Использовать customer user ID в [серверном API](getting-started-with-server-side-api).
4. Adapty передаёт customer user ID во все интеграции.
Поведение профиля с customer user ID зависит от того, когда вы его устанавливаете:
- **При активации SDK**: Adapty использует существующий профиль с этим customer user ID (для вернувшихся пользователей) или создаёт новый профиль (для новых пользователей).
- **После активации SDK**: Adapty создаёт анонимный профиль при активации. Когда вы впоследствии идентифицируете пользователя, Adapty привязывает customer user ID к анонимному профилю (для новых пользователей) или переключается на существующий профиль с этим ID (для вернувшихся пользователей).
**Какой подход выбрать:**
- **Customer user ID доступен при запуске приложения** (например, сохранён из предыдущей сессии) — передайте его в `activate()` при инициализации SDK.
- **Пользователи входят в систему после запуска приложения** — вызовите `identify()` после аутентификации. Adapty привяжет ID к текущему профилю (если ID новый) или переключится на существующий профиль (если ID уже есть).
- **Пользователи могут совершать покупки до входа в систему** — вызовите `identify()` после входа. Если customer user ID уже существует в Adapty, получите профиль после этого, чтобы синхронизировать текущий уровень доступа.
Подробнее о реализации — в гайде SDK по [идентификации пользователей](identifying-users).
:::note
Если вернувшийся пользователь ранее использовал приложение без customer user ID, анонимные профили не объединяются автоматически при идентификации во время активации SDK. Чтобы сохранить полную историю для таких пользователей, вызывайте `identify()` после входа в систему.
:::
## Родительские и дочерние профили \{#parent-and-inheritor-profiles\}
Когда одна и та же подписка в сторе привязана к нескольким профилям Adapty, Adapty выстраивает из них цепочку: один **родительский** профиль и один или несколько **дочерних** профилей, которые получают доступ от той же покупки.
Это происходит в следующих случаях:
- [Совместный доступ к платным возможностям между аккаунтами](sharing-paid-access-between-user-accounts) включён, и пользователь входит на устройстве, где покупка была совершена из другого профиля.
- Пользователь переустанавливает приложение без `customer_user_id`, и новый профиль подхватывает покупку из предыдущей установки.
- Разные идентифицированные пользователи восстанавливают покупки на одном устройстве.
- Приложение переходит между Apple Team ID, и новое приложение подхватывает покупки, сделанные в рамках старого Team ID.
**Как выбирается родительский профиль.**
Родительский профиль — это **первый профиль, зафиксировавший покупку**, который определяется порядком поступления чеков покупок в Adapty, а не порядком создания профилей. Например: вы установили приложение и ничего не купили, затем переустановили и оформили подписку. Второй профиль становится родительским, поскольку именно он совершил покупку. Первый профиль становится наследником и получает доступ через общий доступ.
**Как распределяются события:**
- **Транзакционные события** (покупки, продления, отмены, проблемы с оплатой, льготные периоды, возвраты): отображаются только в **родительском профиле**, совершившем покупку. Все продления и обновления подписки продолжают отображаться в этом профиле.
- **События `access_level_updated`**: отображаются **в обоих профилях — родительском и профиле-наследнике** — при каждом изменении состояния уровня доступа. Это позволяет всем связанным профилям быть в курсе актуального статуса доступа.
В родительском профиле отображается полная история транзакций. Дочерние профили показывают только обновления уровня доступа и ссылку на родительский профиль в разделе **Access level**.
**Отслеживание одной и той же подписки в нескольких профилях.**
У каждого унаследованного профиля есть свой `profile_id`, поэтому `profile_id` не является стабильным идентификатором в цепочке. Чтобы идентифицировать одну и ту же подписку в нескольких профилях — например, при сверке событий вебхука или сопоставлении профилей дашборда с одним базовым пользователем — используйте идентификатор на стороне стора.
| Поле | Применение |
| --- | --- |
| `store_original_transaction_id` | Идентификация цепочки подписки в разных профилях. Уникально для каждой подписки Apple. |
| `profiles_sharing_access_level` (поле вебхука) | Все профили, которым в данный момент предоставлен уровень доступа по подписке, если включено совместное использование. |
| `profile_id` | **Не** подходит для отслеживания между профилями — у каждого наследника свой. |
## Транзакции без профилей \{#transactions-without-profiles\}
Некоторые транзакции в Adapty не привязаны ни к одному профилю — они отображаются в аналитике и экспортах, но не попадают в список профилей. Это происходит, когда **серверные (S2S) уведомления стора** приходят от пользователей, чьи аккаунты никогда не подключались к вашему приложению через SDK Adapty. Известные источники:
- S2S-уведомления App Store (включая события возврата средств)
- S2S-уведомления Google Play
- Вебхук-события Stripe и Paddle
Эти транзакции:
- **Отображаются в аналитических графиках** (учитываются в общих метриках)
- **Отображаются в экспортах** (S3, GCS, BigQuery) с `profile_id`, равным `null`
- **Не отображаются в списке профилей** — привязать их не к чему
Если в аналитике или экспортах событий больше, чем вы можете найти в интерфейсе профилей, разница, скорее всего, объясняется именно такими транзакциями без профиля. Чтобы найти их в экспорте, отфильтруйте строки, где `profile_id IS NULL`.
## Общий доступ к платному контенту между аккаунтами пользователей \{#sharing-paid-access-between-user-accounts\}
:::link
Основная статья: [Общий доступ к платному контенту между аккаунтами пользователей](sharing-paid-access-between-user-accounts)
:::
Чтобы задать политику общего доступа к уровням доступа, на странице настроек [**General**](general) выберите подходящий вариант. Для [среды песочницы](test-purchases-in-sandbox) можно задать отдельную политику.
**Включено (по умолчанию)**
Идентифицированные пользователи (те, у кого задан [Customer User ID](identifying-users#set-customer-user-id-on-configuration)) могут совместно использовать один и тот же [уровень доступа](access-level), предоставленный Adapty, если их устройство привязано к одному Apple/Google ID. Это удобно, когда пользователь переустанавливает приложение и входит с другим email — он всё равно сохранит доступ к своей предыдущей покупке. При этой опции несколько идентифицированных пользователей могут совместно использовать один уровень доступа.
Несмотря на то что уровень доступа является общим, все прошлые и будущие транзакции фиксируются как события в исходном Customer User ID — для обеспечения корректной аналитики и сохранения полной истории транзакций: пробных периодов, покупок подписок, продлений и прочего, привязанных к одному профилю.
**Передача доступа новому пользователю**
Идентифицированные пользователи сохраняют доступ к [уровню доступа](access-level), предоставленному Adapty, даже если они входят с другим [Customer User ID](identifying-users#set-customer-user-id-on-configuration) или переустанавливают приложение — при условии, что устройство привязано к одному Apple/Google ID.
В отличие от предыдущей опции, Adapty передаёт покупку между идентифицированными пользователями. Это гарантирует доступность купленного контента, однако одновременно доступ может быть только у одного пользователя. Например, если UserA оформляет подписку, а UserB входит на том же устройстве и восстанавливает транзакции, UserB получит доступ к подписке, а у UserA он будет отозван.
Если один из пользователей (новый или прежний) не идентифицирован, уровень доступа всё равно будет общим между этими профилями в Adapty.
Несмотря на передачу уровня доступа, все прошлые и будущие транзакции фиксируются как события в исходном Customer User ID — для обеспечения корректной аналитики и сохранения полной истории транзакций: пробных периодов, покупок подписок, продлений и прочего, привязанных к одному профилю.
После переключения на **Transfer access to new user** уровни доступа не будут немедленно переданы между профилями. Процесс передачи для каждого конкретного уровня доступа запускается только при получении Adapty события от стора — например, при продлении подписки, восстановлении или при валидации транзакции.
**Отключено**
Первый идентифицированный профиль пользователя, получивший уровень доступа, сохранит его навсегда. Это оптимальный вариант, если бизнес-логика вашего приложения требует привязки покупок к единственному Customer User ID.
Обратите внимание, что уровни доступа по-прежнему остаются общими между анонимными пользователями.
Вы можете «отвязать» покупку, [удалив профиль пользователя-владельца](https://adapty.io/docs/ru/api-adapty/operations/deleteProfile). После удаления уровень доступа становится доступным первому профилю, который его запросит — анонимному или идентифицированному.
Отключение совместного использования распространяется только на новых пользователей. Подписки, уже разделённые между пользователями, продолжат оставаться общими даже после отключения этой опции.
:::warning
Apple и Google требуют, чтобы встроенные покупки были доступны для совместного использования или передачи между пользователями, поскольку они привязывают покупку к Apple/Google ID. Без совместного использования восстановление покупок после повторной установки может не работать.
Отключение совместного использования может лишить пользователей возможности восстановить доступ после входа в аккаунт.
Рекомендуем отключать совместное использование только в том случае, если пользователи **обязаны войти в аккаунт** до совершения покупки. В противном случае идентифицированный пользователь может оформить подписку, войти в другой аккаунт и навсегда потерять к ней доступ.
:::
### Какой вариант выбрать? \{#which-setting-should-i-choose\}
| Моё приложение... | Вариант |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| Не имеет системы входа и использует только анонимные идентификаторы профилей Adapty. | Используйте вариант по умолчанию — уровни доступа всегда являются общими между анонимными идентификаторами профилей для всех трёх вариантов. |
| Имеет необязательную систему входа и позволяет совершать покупки до создания аккаунта. | Выберите **Transfer access to new user**, чтобы пользователи, совершившие покупку без аккаунта, могли впоследствии восстановить свои транзакции. |
| Требует создания аккаунта перед покупкой, но допускает привязку покупок к нескольким Customer User ID. | Выберите **Transfer access to new user**, чтобы одновременно доступ был только у одного Customer User ID, при этом пользователи могли входить с другим Customer User ID без потери оплаченного доступа. |
| Требует создания аккаунта перед покупкой и жёстко привязывает покупки к единственному Customer User ID. | Выберите **Disabled**, чтобы транзакции никогда не передавались между аккаунтами. |
## Временны́е метки событий с датами в будущем (Apple/iOS) \{#event-timestamps-with-future-dates-appleios\}
Это поведение характерно только для Apple App Store. Система уведомлений Google Play не отправляет события заранее.
Временны́е метки событий в профилях и интеграциях могут показывать даты в будущем, потому что Apple отправляет события о продлении подписки заранее.
- **Почему это происходит**: Apple делает это, чтобы подписки автоматически обновлялись до истечения срока, не прерывая сервис для пользователей. Подробнее — на форуме разработчиков Apple: [Server Notifications for Subscriptions](https://developer.apple.com/forums/tags/app-store-server-notifications).
- **Затронутые типы событий**: Как правило, это касается продлений подписок и конверсий из пробного периода в платный. У таких событий могут быть будущие временные метки, поскольку Apple уведомляет системы заранее.
- **Другие типы событий**: Дополнительные встроенные покупки и изменения тарифного плана подписки записываются с фактическими временными метками, так как эти события невозможно предсказать заранее.
- **Влияние на Analytics и Event Feed**: Такие события появятся в **Analytics** и **Event Feed** только после того, как наступит их временная метка. События с будущими временными метками не отображаются ни в одном из этих разделов.
- **Влияние на интеграции**: Adapty отправляет события в интеграции сразу после их получения. Если у события будущая временная метка, Adapty передаёт его в вашу интеграцию с этой временной меткой без изменений.
## Дальнейшие шаги \{#next-steps\}
- Чтобы использовать дашборд Profiles для поиска и управления пользователями, см. [Profiles](profiles-crm).
- Чтобы настроить идентификацию пользователей в вашем приложении, см. гайд SDK по [идентификации пользователей](identifying-users).
- Чтобы настроить политику общего доступа, см. [Общий доступ к платному контенту между аккаунтами пользователей](sharing-paid-access-between-user-accounts).
---
# File: sharing-paid-access-between-user-accounts
---
---
title: "Общий доступ к платным функциям между аккаунтами"
description: "Общий доступ к платным функциям между разными аккаунтами пользователей для тех, кто использует несколько устройств или несколько профилей в приложении"
---
Когда пользователь совершает покупку, Adapty присваивает новый [уровень доступа](access-level) его активному [профилю](identifying-users). Этот уровень доступа разрешает покупателю доступ к платному контенту.
Профиль покупателя может непреднамеренно измениться, если он переустановит приложение или войдёт в новый аккаунт внутри приложения. Чтобы обеспечить бесперебойный доступ, Adapty автоматически передаёт уровень доступа пользователя между исходным профилем и последующими.
Такой подход подходит для большинства приложений. Но если ваша бизнес-логика требует иного, вы можете выбрать более ограниченную политику совместного использования платного доступа.
Откройте страницу [General Settings](https://app.adapty.io/settings/general), чтобы задать политику совместного использования уровней доступа. Для удобства тестирования можно изменить этот параметр [только для среды песочницы](#sharing-paid-access-on-sandbox).
## Включено (по умолчанию) \{#enabled-default\}
Эта настройка лучше всего подходит для приложений **без собственной аутентификации**. После покупки все профили, связанные с одним аккаунтом стора, автоматически *наследуют* уровень доступа.
* Если пользователь входит в ваше приложение с новыми учётными данными, он сохраняет доступ к платному контенту.
* Если пользователь переустанавливает приложение после сброса настроек до заводских, он сохраняет доступ к платному контенту.
* Если пользователь устанавливает приложение на других устройствах с тем же аккаунтом стора, покупка становится доступна на всех устройствах — даже если у каждого экземпляра приложения есть свой профиль покупателя.
## Перенос доступа на нового пользователя \{#transfer-access-to-new-user\}
Эта настройка лучше всего подходит для приложений, которые допускают покупки **с авторизацией и без**, или хотят ввести политику **«одно устройство на одного пользователя»**.
Adapty ограничивает доступ к покупке одним customer ID одновременно. Владелец устройства может переустанавливать приложение, входить и выходить из аккаунта, но не может получить доступ к одному и тому же продукту более чем с одного customer ID одновременно.
При включённом параметре анонимные профили (например, профиль, становящийся активным после выхода пользователя из системы) всегда наследуют уровень доступа последнего активного customer ID. Это необходимо, чтобы предотвратить потерю доступа в дальнейшем.
:::warning
Если вы отключите настройку по умолчанию и включите **Transfer access to new user**, Adapty не обновит немедленно уровни доступа существующих профилей пользователей.
Переключение происходит, когда пользователь инициирует новое событие стора: например, продлевает подписку или восстанавливает покупки.
:::
:::important
Adapty отзывает старый профиль только тогда, когда у нового профиля есть [Customer User ID](identifying-users#set-customer-user-id-on-configuration) в момент, когда SDK распространяет транзакцию. Если `restorePurchases` выполняется на анонимном профиле, и старый Customer User ID, и новый анонимный профиль получают уровень доступа. Старый профиль отзывается позже, когда вы идентифицируете анонимный профиль.
Чтобы избежать этого, вызывайте методы SDK по порядку: `activate` → `identify` → `restorePurchases`.
:::
## Отключение общего доступа к платным функциям \{#disable-paid-access-sharing\}
Этот параметр **подходит только** для приложений с **обязательной аутентификацией** или собственной реализацией управления доступом. В остальных случаях пользователи могут потерять доступ к своим покупкам, и ваше приложение рискует **не пройти обязательную проверку стора**.
Если вы отключите совместный доступ к оплаченному контенту, Adapty привяжет продукт к активному [идентификатору пользователя](identifying-users#set-customer-user-id-on-configuration) на момент покупки и не будет предоставлять уровень доступа другим профилям. Это обеспечивает строгое распределение продукта по принципу «один к одному».
:::warning
Если вы отключите совместный доступ к оплаченному контенту, идентификаторы пользователей перестанут наследовать оплаченный доступ. Если идентификатор ранее уже унаследовал оплаченный доступ, отозвать его автоматически невозможно.
:::
:::important
В экстренных случаях вам может потребоваться [удалить профиль пользователя](api-adapty/operations/deleteProfile), чтобы следующий доступный профиль (идентифицированный или анонимный) мог получить его уровень доступа.
:::
## Практический справочник \{#practical-reference\}
После выбора режима контракты ниже описывают, чего ожидать: какие профили получают доступ, когда старый профиль его теряет и какие события вебхуков срабатывают.
| Режим | Несколько профилей делят одну покупку? | Старый профиль отзывается при передаче? | Когда отзывается старый профиль | Webhook-события, когда второй профиль претендует на подписку |
| --- | --- | --- | --- | --- |
| **Включён (по умолчанию)** | Да — каждый профиль, восстановивший покупку или выполнивший вход, наследует доступ | Никогда | Н/Д | `access_level_updated` (`is_active=true`) для каждого нового профиля, унаследовавшего доступ |
| **Передача доступа новому пользователю** | Нет — эксклюзивный, но переносимый между профилями | Да | Сразу после того, как новое идентифицированное устройство передаёт транзакцию (`restorePurchases`, идентификация или следующее событие на стороне стора) | Новый профиль: `access_level_updated` (`is_active=true`). Старый профиль: `access_level_updated` (`is_active=false`) |
| **Отключён** | Нет — один Customer User ID на покупку, навсегда | Н/Д — доступ не передаётся никогда | Н/Д | Ни одного для второго профиля. SDK не показывает для него никакого доступа |
## Совместный доступ к оплаченному контенту в песочнице \{#sharing-paid-access-on-sandbox\}
Вы можете задать политику совместного доступа к оплаченному контенту отдельно для среды песочницы. При тестировании покупок в песочнице ожидайте следующего поведения:
* Apple хранит информацию о прошлых покупках в истории покупок аккаунта. SDK Adapty тоже может получить к ней доступ.
* Если вы переустановите приложение, и Adapty обнаружит, что продукт уже был куплен, активный профиль унаследует уровень доступа.
* Если Apple обнаруживает существующую покупку продукта, повторная покупка того же продукта будет невозможна, даже если у активного профиля нет нужного уровня доступа.
Это поведение возникает **независимо от настройки общего доступа к платным функциям**. Если приложение не показывает пейвол, купить продукт невозможно. Единственное решение — **очистить историю покупок аккаунта**. Подробные инструкции см. в [гайде по тестированию в песочнице](test-purchases-in-sandbox).
:::warning
Подписки в песочнице Apple автоматически продлеваются каждые несколько минут. Такие частые продления могут менять профиль, который Adapty считает [родительским](how-profiles-work#parent-and-inheritor-profiles) — паттерн цепочки, который в продакшене воспроизводится крайне редко. Тестируйте в том же режиме, который используете в продакшене, и проверяйте поведение на реальном Apple ID, прежде чем делать выводы по данным из песочницы.
:::
## Совместный доступ в аналитике \{#paid-access-sharing-in-analytics\}
* Adapty фиксирует транзакции по мере их поступления. Одна транзакция может быть связана с несколькими профилями, но учитывается только один раз.
* Если два или более профиля используют один уровень доступа, покупка атрибутируется [родительскому профилю](how-profiles-work#parent-and-inheritor-profiles).
* Наследование уровня доступа не влияет на статистику установок. Чтобы задать способ подсчёта установок в Adapty, выберите один из двух доступных [вариантов определения установок](installs#calculation) на странице настроек.
---
# File: segments
---
---
title: "Сегменты"
description: "Создавайте сегменты пользователей и управляйте ими для более точного таргетинга в Adapty."
---
**Сегмент** — это набор фильтров, который группирует пользователей с общими свойствами. Используйте сегменты для более точного таргетинга пейволов и A/B-тестов.
:::note
События из ленты событий поступают на дашборд с задержкой. Новые профили и изменения атрибутов могут отображаться не сразу.
:::
После того как вы создадите сегмент, вы можете [использовать его как **аудиторию** в плейсментах и A/B-тестах](audience), чтобы управлять тем, какой пейвол видят пользователи (один или несколько). Примеры:
- Показывать стандартный пейвол тем, кто ещё не подписался, и предлагать скидку пользователям, которые ранее отменили подписку или пробный период.
- Показывать разные пейволы пользователям из разных стран.
- Настраивать таргетинг на основе данных атрибуции Apple Search Ads.
- Гарантировать, что пользователи на старых версиях приложения продолжают видеть прежний пейвол, а на новых — обновлённый.
- [В Analytics](controls-filters-grouping-compare-proceeds#filter-and-group-data), фильтровать по сегментам, чтобы смотреть показатели для конкретных групп пользователей. Группировать по сегменту, чтобы сравнивать результаты или вклад в рамках **All users**.
## Создание \{#creation\}
Чтобы создать сегмент, введите название и выберите атрибуты, которые задают его фильтры. Если выбрано несколько атрибутов, пользователь должен соответствовать всем условиям одновременно. Adapty применяет логику AND между атрибутами.
## Доступные атрибуты \{#available-attributes\}
:::note
Многие атрибуты пользователя устанавливаются автоматически (например, **Country** или **Calculated total revenue USD**), однако **Age**, **App user ID**, данные **Attribution**, **Gender** и **Custom attributes** автоматически не определяются. Чтобы использовать их для сегментации, необходимо [задать атрибуты пользователя](setting-user-attributes) или [передать данные атрибуции](attribution-integration).
:::
:::tip
Для атрибутов на основе дат доступна фильтрация по:
- **Фиксированная дата**: выберите конкретные даты в календаре (например, покажите специальное предложение пользователям, установившим приложение в период с Чёрной пятницы по Киберпонедельник)
- **Относительный диапазон**: задайте динамические временные окна, например «Последние 7 дней» или «Последние 3 месяца» (например, верните пользователей, которых не было 30+ дней, или нацельтесь на недавние установки)
Относительные диапазоны обновляются автоматически — это идеальный вариант для постоянных кампаний. Фиксированные даты лучше подходят для акций с ограниченным сроком.
:::
| Атрибут | Фильтр по |
|---------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Age** | Возраст пользователя. Обратите внимание: возраст рассчитывается в момент первого получения данных Adapty и в дальнейшем не обновляется. |
| **App User ID** | Идентификатор пользователя в вашем приложении ([customer_user_id](profiles-crm#user-attributes)). Можно фильтровать по наличию или отсутствию значения — например, чтобы показывать пейвол только пользователям, которые не вошли в аккаунт. |
| **App version (current)** | Текущая версия приложения, установленного на устройстве пользователя, с которого Adapty последний раз получал данные о событиях — **обновляется при каждом обновлении приложения**, поэтому всегда отражает актуальную версию. Используйте этот атрибут, когда нужно охватить всех, кто сейчас работает с конкретной версией, включая тех, кто обновился до неё с более ранней. При создании сегмента нажмите на значок карандаша рядом с **App version** и добавьте новую версию, чтобы сразу использовать её.
| Поле | Описание |
| ------ |--------------------------------------------------------------------------------------------------------------------------------------|
| **Name** | Название пользовательского атрибута, отображаемое только в дашборде Adapty. |
| **Key** | Уникальный идентификатор атрибута. Должен совпадать с ключом, используемым в SDK. |
| **Type** | Выберите один из вариантов:
## Дублирование сегментов \{#duplicate-segments\}
Если вам нужен сегмент, похожий на уже существующий, продублируйте его вместо того, чтобы создавать с нуля. Это экономит время командам, которые запускают несколько кампаний или A/B-тестов с пересекающимися группами пользователей.
При дублировании сегмента создаётся его копия со всеми фильтрами и описанием. К названию нового сегмента добавляется «(copy)», чтобы вы могли отличить его от оригинала. Новый сегмент независим от исходного: изменения в одном не влияют на другой.
Чтобы продублировать сегмент в дашборде Adapty:
1. Откройте раздел **Profiles & Segments** в главном меню Adapty и перейдите на вкладку [**Segments**](https://app.adapty.io/segments).
2. Нажмите кнопку **3-dot** рядом с нужным сегментом и выберите **Duplicate**.
3. Откройте новый сегмент и настройте фильтры по необходимости.
## Удаление сегментов \{#delete-segments\}
Если сегмент больше не нужен, его можно удалить без возможности восстановления.
Adapty заблокирует удаление, если сегмент используется как аудитория в одном из следующих объектов:
- **Плейсмент**: хотя бы один неудалённый плейсмент использует этот сегмент в качестве аудитории.
- **A/B-тест (активный или завершённый)**: хотя бы один неудалённый A/B-тест использует этот сегмент в качестве аудитории.
При удалении сегмента Adapty считает активными как **Live**, так и **Completed** A/B-тесты. Завершённый тест по-прежнему использует аудиторию для показа пейвола или онбординга после окончания теста подходящим пользователям, а исторические метрики теста привязаны к этому сегменту. Сегмент освобождается только при удалении самого A/B-теста.
:::warning
Удаление сегмента необратимо. Восстановить его не получится.
:::
Чтобы удалить сегмент в дашборде Adapty:
1. Перейдите в раздел **Profiles & Segments** главного меню Adapty и откройте вкладку [**Segments**](https://app.adapty.io/segments).
2. Нажмите кнопку **3-dot** рядом с сегментом и выберите **Delete**.
3. Введите название сегмента в поле подтверждения, затем нажмите **Delete forever**.
:::info
Если сегмент используется, в диалоге отобразится список плейсментов и A/B-тестов, которые на него ссылаются.
Чтобы разблокировать удаление, откройте каждый плейсмент или A/B-тест из списка и либо удалите сегмент из его аудитории, либо удалите сам плейсмент или A/B-тест. Как только ничто не будет ссылаться на сегмент, вы сможете его удалить.
:::
---
# File: event-feed
---
---
title: "Лента событий"
description: "Отслеживайте и анализируйте активность пользователей с помощью ленты событий Adapty."
---
Лента событий позволяет наглядно отслеживать [события](events), генерируемые Adapty, и проверять статус их экспорта в сторонние интеграции, включая вебхук.
:::warning
Лента событий не отображает:
- **Транзакции server-side API v1**: созданные через [server-side API (версия 1)](server-side-api-specs-legacy#requests). Используйте [server-side API (версия 2)](api-adapty/operations/setTransaction), чтобы они отображались.
- **События без профиля**: транзакции, поступившие до того, как SDK идентифицировал пользователя, — например, уведомления от серверов сторов. Чтобы включить их в экспорт, активируйте **Include events without profile** в настройках интеграции [S3](s3-exports) или [Google Cloud Storage](google-cloud-storage).
:::
:::note Статус отправки для AppsFlyer, Facebook Ads и Branch может отображаться некорректно, так как эти сервисы не всегда возвращают ошибки при их возникновении. ::: Чтобы открыть профиль пользователя, инициировавшего транзакцию, нажмите кнопку **View Profile** в деталях события. --- # File: ab-tests --- --- title: "A/B-тест" description: "Оптимизируйте ценообразование подписок с помощью A/B-тестов в Adapty для повышения конверсии." --- :::tip Вы можете получить готовый план A/B-теста без самостоятельного исследования. [AI Growth Advisor](autopilot) проверяет ваш пейвол, анализирует конкурентов и формирует рекомендации на основе обезличенных данных более чем 20 000 приложений с подписками, отслеживаемых Adapty. ::: Увеличьте доход приложения с помощью A/B-тестов в Adapty. Сравнивайте разные флоу, пейволы и онбординги, чтобы найти лучший вариант конверсии — без изменений в коде. Например, можно тестировать: - Цены на подписки - Дизайн, текст и макет пейвола - Пробные периоды и длительность подписок - Дизайн онбордингов ## Предварительные требования \{#prerequisites\} Перед настройкой A/B-теста убедитесь, что у вас есть: - **Плейсменты**: Один или несколько [плейсментов](placements), где отображается флоу, пейвол или онбординг. - **Для флоу**: Минимум два [флоу](adapty-flow-builder). - **Для пейволов**: Минимум два [пейвола](paywalls). - **Для онбордингов**: Минимум два [онбординга](onboardings). :::warning Если вы не используете [Adapty Flow builder](adapty-flow-builder) или [Adapty Paywall builder](adapty-paywall-builder), [отправляйте события просмотра пейвола в Adapty](present-remote-config-paywalls#track-paywall-view-events) с помощью `.logShowFlow()` (iOS SDK v4+) / `.logShowPaywall()`. Без этого метода Adapty не сможет подсчитать просмотры пейвола в тесте, и статистика конверсий будет неточной. ::: ## Типы A/B-тестов \{#ab-test-types\} Adapty поддерживает два основных типа A/B-тестов: - **Regular**: Запускается на одном плейсменте (флоу, пейвол или онбординг). - **Crossplacement**: Запускается сразу на нескольких плейсментах пейволов и показывает пользователю одинаковый вариант во всех из них. На данный момент доступен только для пейволов. Подробное сравнение типов, сценариев использования и правил приоритетов см. в разделе [Типы A/B-тестов](ab-test-types). ## Дальнейшие шаги \{#next-steps\} - [AI Growth Advisor](autopilot) — Проанализируйте свой пейвол, получите рыночные инсайты и сформируйте план A/B-теста - [Типы A/B-тестов](ab-test-types) — Узнайте о типах тестов и когда применять каждый из них - [Создание, запуск и остановка A/B-теста](run_stop_ab_tests) — Настройте и запустите свой первый тест - [Результаты и метрики A/B-теста](results-and-metrics) — Разберитесь в данных A/B-теста и выберите победителя --- # File: ab-test-types --- --- title: "Типы A/B-тестов" description: "Узнайте о типах A/B-тестов в Adapty." --- Adapty предлагает два типа A/B-тестов, каждый из которых подходит для разных сценариев тестирования: - **Обычный A/B-тест:** A/B-тест, созданный для одного [флоу](adapty-flow-builder)/[пейвола](paywalls)/[онбординга](onboardings) плейсмента. - **Кросс-плейсментный A/B-тест:** A/B-тест, созданный для нескольких плейсментов пейволов в вашем приложении. После того как A/B-тест назначает
## Ключевые различия \{#key-differences\}
| Функция | Обычный A/B-тест | Кросс-плейсментный A/B-тест |
| ------------------------------- |--------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
| **Что тестируется** | Один флоу/пейвол/онбординг | Набор пейволов, принадлежащих одному варианту |
| **Согласованность варианта** | Вариант определяется отдельно для каждого плейсмента | Один и тот же вариант используется во всех плейсментах пейволов |
| **Таргетинг по аудитории** | Задаётся для каждого плейсмента флоу/пейвола/онбординга | Общий для всех плейсментов пейволов |
| **Аналитика** | Анализируется один плейсмент флоу/пейвола/онбординга | Анализируется всё приложение по тем плейсментам, которые входят в тест |
| **Распределение веса вариантов** | Для каждого флоу/пейвола/онбординга | Для набора пейволов |
| **Пользователи** | Для всех пользователей | Только новые пользователи (те, кто ещё не видел пейвол Adapty) |
| **Версия SDK Adapty** | Для флоу: v4.0.0+. Для пейволов: любая. Для онбордингов: v3.8.0+ (iOS, Android, React Native, Flutter), v3.14.0+ (Unity), v3.15.0+ (KMP, Capacitor) | 3.5.0+ |
| **Лучше всего подходит для** | Тестирования независимых изменений в одном плейсменте флоу/пейвола/онбординга без учёта общей экономики приложения | Оценки общих стратегий монетизации в масштабах всего приложения |
## Логика выбора A/B-теста \{#ab-test-selection-logic\}
**Межплейсментные A/B-тесты имеют приоритет над обычными A/B-тестами.** Однако межплейсментные тесты показываются только **новым пользователям** — тем, кто ещё не видел ни одного пейвола Adapty (метод SDK `getPaywall` для них ни разу не вызывался). Это обеспечивает согласованность результатов между плейсментами.
На следующей схеме показана логика, которую Adapty использует для выбора A/B-теста для плейсмента:
На странице **A/B Tests** тесты пейволов, онбордингов, флоу и кросс-плейсментные тесты отображаются на отдельных вкладках.
## Ограничения кросс-плейсментных A/B-тестов \{#crossplacement-ab-test-limitations\}
:::warning
Кросс-плейсментные A/B-тесты не могут включать плейсменты с флоу или онбордингом.
:::
Кросс-плейсментные A/B-тесты гарантируют, что каждый пользователь видит один и тот же вариант во всех плейсментах теста. Это создаёт следующие ограничения:
* Участвовать могут только новые пользователи. Новый пользователь — тот, кто ещё не видел ни одного пейвола Adapty и чьё приложение ни разу не вызывало `getPaywall`. Для остальных пользователей Adapty не может гарантировать согласованную цепочку пейволов.
* Первый плейсмент, с которым сталкивается пользователь, определяет, какой пейвол покажет Adapty. Изменить назначение пользователя или записать одного и того же пользователя в более чем один кросс-плейсментный A/B-тест нельзя.
:::warning
Как только пользователь получает кросс-плейсментный пейвол, он видит его в течение 90 дней — даже после остановки теста. Чтобы изменить этот срок, в настройках **General** измените значение **[Cross-placement variation stickiness](general#9-cross-placement-variation-stickiness)**.
:::
## Приоритет Crossplacement A/B-тестов \{#crossplacement-ab-test-priority\}
* Crossplacement A/B-тесты всегда имеют приоритет над обычными A/B-тестами и A/B-тестами онбордингов. Если новый пользователь подходит одновременно для Crossplacement-теста и обычного теста на одном плейсменте, будет показан Crossplacement-тест.
* Когда несколько Crossplacement A/B-тестов с одной и той же аудиторией используют один плейсмент, Adapty автоматически расставляет приоритеты по порядку добавления тестов. Первый добавленный тест получает наивысший приоритет. Изменить его вручную нельзя.
* Тесты, нацеленные на меньшие сегменты аудитории, автоматически получают приоритет над тестами, которые нацелены на сегмент «Все пользователи».
:::note
В Analytics кросс-плейсментный A/B-тест отображается как несколько дочерних тестов — по одному на каждый плейсмент. Дочерние тесты именуются по шаблону `
2. В правом верхнем углу нажмите **Create A/B test**.
3. В окне **Create the A/B test** введите **Test name**. Это обязательное поле. Выберите название, которое чётко описывает суть теста, чтобы легко найти его при просмотре результатов.
4. Заполните поле **Test goal** — опишите, чего хотите достичь (например, увеличить число подписок или снизить отток).
5. Нажмите **Select placement** и выберите плейсмент с флоу, пейволом или онбордингом.
6. Настройте содержимое теста в таблице **Variants**. Каждая строка — это вариант, каждый столбец — плейсмент. В каждой ячейке добавьте пейвол.
По умолчанию таблица содержит 2 варианта и 1 плейсмент. Можно добавить до 20 вариантов. После добавления второго плейсмента тест становится кросс-плейсментным A/B-тестом. Обратите внимание: кросс-плейсментные A/B-тесты доступны только для пейволов.
7. Сохраните тест. У вас есть два варианта:
1. **Save as draft**: тест не запустится сразу. Вы сможете запустить его позже из списка плейсментов или A/B-тестов. Используйте этот вариант, чтобы проверить настройки перед запуском.
2. **Run A/B test**: запускает тест немедленно. Тест становится активным сразу после нажатия этой кнопки.
После сохранения в черновик перейдите к разделу [Запуск A/B-теста](#run-an-ab-test).
## Редактирование A/B-теста \{#edit-an-ab-test\}
Редактировать можно только те A/B-тесты, которые сохранены как черновики. После запуска теста изменить его нельзя. Чтобы обновить активный тест, воспользуйтесь опцией **Modify** — она создаёт дубликат с тем же именем, в котором можно внести правки. Adapty остановит исходный тест, и оба — исходный и изменённый — будут отображаться в аналитике отдельно.
## Запустите A/B-тест \{#run-an-ab-test\}
Запустить A/B-тест в Adapty — значит назначить его на плейсмент, чтобы он начал показывать пейволы и онбординги пользователям.
1. Откройте раздел [A/B-тесты](ab-tests) из главного меню Adapty.
2. Убедитесь, что просматриваете нужный список — A/B-тесты **Paywall**, **Flow**, **Onboardings** и **Crossplacement** отображаются на отдельных вкладках, между которыми можно переключаться.
3. Перейдите на вкладку **Drafts**. Запустить можно только черновые тесты.
4. Рядом с нужным тестом нажмите **Run A/B test**.
5. Откроется окно **Edit A/B test**. Проверьте настройки и при необходимости внесите изменения. Если плейсмент или аудитория не указаны, добавьте их сейчас.
6. После проверки настроек нажмите **Run A/B test**, чтобы запустить тест.
После запуска теста вы можете отслеживать его ход и просматривать данные о результатах на странице [Результаты и метрики A/B-теста](results-and-metrics).
## Остановить A/B-тест \{#stop-an-ab-test\}
Когда вы останавливаете A/B-тест, он завершается и становятся доступны его результаты. Также нужно решить, что показывать пользователям в затронутых плейсментах после окончания теста.
1. Откройте раздел [A/B tests](https://app.adapty.io/ab-tests) и перейдите на вкладку **Live**.
2. Рядом с нужным тестом нажмите меню с тремя точками и выберите **Stop A/B test**.
3. В окне **Stop the A/B test** выберите, что должно произойти после завершения теста. Доступны три варианта:
| Опция | Описание |
|----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Показать один из тестируемых пейволов/онбордингов | Выберите победивший пейвол или онбординг на основе результатов теста: выручка, вероятность быть лучшим (**P2BB**) и выручка на 1K пользователей. Этот пейвол или онбординг будет показываться для выбранного плейсмента и аудитории. |
| Выбрать пейволы/онбординги, не участвующие в A/B-тесте | Выберите любой пейвол или онбординг, который не является частью текущего A/B-теста. Используйте этот вариант, если ни один из тестируемых вариантов не достиг ваших целей. |
| Не показывать конкретный пейвол/онбординг | Для выбранного плейсмента и аудитории после завершения A/B-теста конкретный пейвол или онбординг выбран не будет. Вместо этого будет показан следующий доступный пейвол или онбординг согласно приоритету аудитории. Это хороший выбор, если вы предпочитаете, чтобы текущая настройка сама определяла, какой пейвол или онбординг отображать, без ручного выбора. |
:::note
Остановка A/B-теста необратима — его нельзя перезапустить. Убедитесь, что собрали достаточно данных, прежде чем принять решение об остановке.
:::
4. Нажмите кнопку **Stop and complete this A/B test**.
После завершения A/B-тест перестаёт быть активным, и пейволы или онбординги из него больше не показываются новым пользователям.
Вы по-прежнему можете просматривать результаты и метрики A/B-теста на [странице метрик A/B-теста](results-and-metrics#metrics-controls), чтобы оценить эффективность для пользователей, участвовавших в тесте. Метрики могут продолжать обновляться по мере того, как новые события покупок или дохода атрибутируются этим пользователям.
---
# File: ab-test-no-paywall-variants
---
---
title: "Добавление вариантов A/B-теста без флоу или пейволов"
description: "Запустите A/B-тест, в котором один вариант пропускает флоу или пейвол, используя флаг в Remote Config для управления его отображением."
---
Вы можете измерить влияние флоу или пейвола, запустив A/B-тест с пустым вариантом. Один вариант показывает флоу или пейвол, другой не показывает ничего. Приложение читает флаг из Remote Config и решает, нужно ли что-то отображать.
## Как это работает \{#how-it-works\}
Настройка использует два флоу/пейвола в одном плейсменте:
- **Флоу/Пейвол A**: флоу или пейвол, который вы хотите протестировать, с `show_paywall` установленным в `true` в его Remote Config.
- **Флоу/Пейвол B**: пустой флоу или пейвол с `show_paywall` установленным в `false` в его Remote Config.
Когда SDK возвращает флоу или пейвол, ваше приложение считывает флаг `show_paywall`. Если флаг равен `true`, приложение отображает его. Если флаг равен `false`, приложение пропускает отображение, и пользователь продолжает работу, ничего не видя.
## 1. Добавьте флаг show_paywall в Remote Config \{#1-add-the-show_paywall-flag-in-remote-config\}
Вам понадобятся два флоу или два пейвола в одном плейсменте: Flow/Paywall A (тот, который хотите протестировать) и Flow/Paywall B (пустой). Добавьте поле `show_paywall` в каждый из них, чтобы приложение могло принять решение по одному и тому же ключу для обоих вариантов.
Чтобы добавить флаг в Flow/Paywall A:
1. Откройте раздел [**Flows**](https://app.adapty.io/flows)/[**Paywalls**](https://app.adapty.io/paywalls) в главном меню Adapty и выберите Flow/Paywall A.
2. Откройте раздел **Remote config**.
3. Создайте поле с именем `show_paywall` и значением `true`. В режиме **JSON** запись выглядит так:
```json showLineNumbers
{
"show_paywall": true
}
```
4. Сохраните изменения.
Повторите те же шаги для Flow/Paywall B, но задайте для `show_paywall` значение `false`.
Подробнее о Remote Config читайте в разделах [Настройка флоу с помощью Remote Config](customize-flow-with-remote-config) и [Дизайн пейвола с помощью Remote Config](customize-paywall-with-remote-config).
:::tip
Установка `show_paywall` в обоих вариантах делает путь выполнения кода одинаковым для обеих групп и упрощает добавление новых вариантов в будущем.
:::
## 2. Настройте A/B-тест \{#2-set-up-the-ab-test\}
1. [Создайте A/B-тест](run_stop_ab_tests) на плейсменте и добавьте оба флоу/пейвола как варианты.
2. Задайте веса вариантов, чтобы распределить трафик между пользователями, которые видят флоу/пейвол, и теми, кто не видит.
## 3. Проверьте флаг в приложении \{#check-the-flag-in-your-app\}
Прочитайте `show_paywall` из Remote Config, который возвращает SDK. Если флаг равен `false`, пропустите рендеринг и дайте пользователю продолжить.
:::note
Adapty конвертирует другие валюты в USD по курсу [currencylayer.com](https://currencylayer.com/) (обновляется каждые 8 часов). Курс **фиксируется на момент транзакции** — последующие изменения не влияют на результат конвертации.
:::
**Revenue**: Эта метрика показывает общую сумму денег в USD, полученных от покупок и продлений подписок, за вычетом возвратов средств пользователям. Она учитывает как первоначальную покупку, так и последующие продления подписки. Revenue помогает понять, как каждый вариант A/B-теста работает с финансовой точки зрения, и определить, какой из них приносит больше всего денег.
Узнайте больше о метриках [пейвола](paywall-metrics).
**Вероятность быть лучшим**: Adapty использует надёжную математическую методику для анализа результатов A/B-тестов и предоставляет метрику под названием «Вероятность быть лучшим». Эта метрика оценивает вероятность того, что конкретный вариант является наилучшим по долгосрочной выручке среди всех тестируемых вариантов. Метрика выражается в процентах от 1% до 100%. Подробнее о том, как Adapty рассчитывает эту метрику, читайте в [документации.](maths-behind-it) Наилучший вариант, определяемый по выручке на 1000 пользователей, выделяется зелёным цветом и автоматически выбирается по умолчанию.
**Доход на 1K пользователей**: метрика «Доход на 1K пользователей» вычисляет средний доход, генерируемый на 1 000 пользователей для каждого варианта A/B-теста. Она помогает оценить эффективность вариантов с точки зрения дохода вне зависимости от общего числа пользователей — сравнивать варианты на стандартизированной шкале и принимать взвешенные решения на основе показателей эффективности генерации дохода.
**Доверительные интервалы прогноза для дохода на 1K пользователей**: Метрика дохода на 1K пользователей включает доверительные интервалы прогноза. Они показывают диапазон, в который, по оценке статистического анализа на основе имеющихся данных, попадёт истинное значение дохода на 1 000 пользователей для данного варианта.
В контексте A/B-тестирования при анализе выручки, генерируемой разными вариантами, мы рассчитываем среднюю выручку на 1000 пользователей для каждого варианта. Поскольку выручка может варьироваться от пользователя к пользователю, интервалы прогноза наглядно показывают правдоподобный диапазон значений выручки на 1000 пользователей с учётом вариативности и неопределённости, присущих процессу прогнозирования.
Включая интервалы прогнозов в метрику дохода на 1000 пользователей, Adapty позволяет оценивать эффективность вариантов A/B-теста с учётом диапазона возможных результатов по выручке. Эта информация помогает принимать решения на основе данных и эффективно оптимизировать стратегию подписок — с учётом неопределённости в процессе прогнозирования и возможных значений дохода на 1000 пользователей.
Анализируя эти метрики в Adapty, вы получаете представление о финансовых показателях, статистической значимости и эффективности дохода вариантов A/B-теста — и можете принимать решения на основе данных, оптимизируя стратегию подписок.
## Метрики A/B-теста \{#ab-test-metrics\}
Adapty предоставляет полный набор метрик для эффективного измерения результатов A/B-теста на вариантах пейвола или онбординга. Метрики обновляются в реальном времени, за исключением просмотров — они обновляются периодически. Понимание этих метрик поможет вам оценить эффективность разных вариантов и принимать решения на основе данных для оптимизации стратегии пейвола или онбординга.
Метрики A/B-тестов доступны в списке A/B-тестов, где можно получить общее представление о результатах всех ваших A/B-тестов. В этом сводном представлении отображаются агрегированные метрики для каждого варианта теста, что позволяет сравнивать их эффективность и выявлять значимые различия. Для более детального анализа конкретного A/B-теста можно перейти к детальным метрикам A/B-теста. В этом разделе представлены подробные метрики, относящиеся к выбранному A/B-тесту, которые позволяют глубоко изучить результаты отдельных вариантов.
Все метрики, за исключением просмотров, относятся к продукту в рамках пейвола или онбординга.
## Элементы управления метриками \{#metrics-controls\}
Система отображает метрики на основе выбранного периода времени и организует их в соответствии с параметром левого столбца с тремя уровнями отступов.
### Фильтрация профилей по дате установки \{#profile-install-date-filtration\}
Флажок **Filter metrics by install date** позволяет фильтровать метрики по дате установки профиля вместо стандартных фильтров, которые используют дату пробного периода/покупки для транзакций или дату просмотра для пейволов и онбордингов. Выбрав этот флажок, вы можете сосредоточиться на оценке эффективности привлечения пользователей за конкретный период, привязав метрики к дате установки профиля. Эта опция полезна, когда нужно адаптировать анализ метрик под конкретные задачи.
### Временные диапазоны \{#time-ranges\}
Вы можете выбирать из ряда временных периодов для анализа данных метрик, что позволяет сосредоточиться на конкретных промежутках, таких как дни, недели, месяцы или произвольные диапазоны дат.
### Доступные фильтры и группировка \{#available-filters-and-grouping\}
:::link
Основная статья: [Инструменты управления аналитикой](controls-filters-grouping-compare-proceeds)
:::
Adapty предоставляет мощные инструменты для фильтрации и настройки анализа метрик под ваши задачи. На странице метрик доступны различные временные диапазоны, варианты группировки и возможности фильтрации.
- ✅ Фильтрация по: аудитории, атрибуции, стране, пейволу, состоянию пейвола, группе пейволов, онбордингу, плейсменту, стране, стору, продукту и стору продукта.
- ✅ Группировка по: продукту и стору.
:::note
Когда вы фильтруете по A/B-тесту, кросс-плейсментные A/B-тесты отображаются как отдельные дочерние тесты (например, `My test child-0`, `My test child-1`) — по одному на каждый плейсмент. Подробнее см. в разделе [Ограничения кросс-плейсментных A/B-тестов](ab-test-types#crossplacement-ab-test-limitations).
:::
## График отдельной метрики \{#single-metrics-chart\}
Один из ключевых элементов страницы метрик пейвола или онбординга — раздел с графиком, который наглядно отображает выбранные метрики и упрощает их анализ.
График на странице метрик A/B-теста содержит горизонтальную столбчатую диаграмму, которая визуально отображает значения выбранной метрики. Каждый столбец соответствует значению метрики и пропорционален ему по размеру — это позволяет мгновенно считывать данные. Горизонтальная линия показывает анализируемый временной промежуток, вертикальный столбец отображает числовые значения метрик. Суммарное значение всех метрик отображается рядом с графиком.
Кроме того, нажатие на значок стрелки в правом верхнем углу раздела графика разворачивает область просмотра, отображая выбранные метрики на полной линии графика.
## Сводка A/B-теста \{#ab-test-summary\}
Рядом с графиком отдельной метрики отображается раздел сводки деталей A/B-теста, который содержит информацию о состоянии, продолжительности, плейсментах и других связанных деталях A/B-теста.
## Определения метрик \{#metrics-definitions\}
Вот ключевые метрики, доступные для A/B-тестов:
### Доход \{#revenue\}
Доход — это общая сумма в USD, полученная от покупок и продлений подписок в рамках A/B-теста. Включает первоначальную покупку и последующие продления подписки. Метрика рассчитывается до вычета комиссии App Store или Play Store.
Подробнее о метриках [дохода пейвола](paywall-metrics#revenue).
### CR to purchases \{#cr-to-purchases\}
Коэффициент конверсии в покупки измеряет эффективность A/B-теста в плане конвертации просмотров в реальные покупки. Рассчитывается путём деления числа покупок на число просмотров. Например, если было 10 покупок и 100 просмотров, коэффициент конверсии в покупки составит 10%.
### CR trials \{#cr-trials\}
Коэффициент конверсии (CR) в пробные периоды — это число пробных периодов, запущенных из A/B-теста, делённое на число просмотров. CR в пробные периоды измеряет эффективность A/B-теста в конвертации просмотров в активации пробного периода. Рассчитывается путём деления числа запущенных пробных периодов на число просмотров.
### Purchases \{#purchases\}
Метрика Purchases представляет общее число транзакций, совершённых в пейволе или онбординге в результате A/B-теста. Она включает следующие типы покупок:
- Новые совершённые покупки.
- Конверсии из пробных периодов, которые были активированы.
- Даунгрейды, апгрейды и кросс-грейды подписок.
- Восстановления подписок (например, когда подписка истекла без автопродления и впоследствии была восстановлена).
Обратите внимание, что продления не включаются в метрику Purchases.
### Trials \{#trials\}
Метрика Trials указывает общее число активированных пробных периодов в результате A/B-теста.
### Trials cancelled \{#trials-cancelled\}
Метрика Trials cancelled представляет число пробных периодов, в которых автопродление было отключено. Это происходит, когда пользователи вручную отменяют подписку на пробный период.
### Refunds \{#refunds\}
Refunds для A/B-теста представляют число возвратов покупок и подписок, непосредственно связанных с тестируемыми вариациями.
### Views \{#views\}
Views — это число просмотров пейволов или онбордингов, входящих в A/B-тест. Если пользователь посещает дважды, это считается двумя посещениями.
### Unique views \{#unique-views\}
Unique views — это число уникальных просмотров пейвола или онбординга. Если пользователь посещает его дважды, это считается одним уникальным просмотром.
### Probability to be the best \{#probability-to-be-the-best\}
Метрика Probability to be the best количественно оценивает вероятность того, что конкретный вариант в A/B-тесте является наилучшим среди всех протестированных пейволов или онбордингов. Она предоставляет числовую вероятность, указывающую на относительную производительность каждого пейвола или онбординга. Метрика выражается в процентах от 1% до 100%.
### ARPU (Average revenue per user) \{#arpu-average-revenue-per-user\}
Только для A/B-тестов онбординга. Измеряет средний доход, генерируемый от каждого пользователя за определённый период. Рассчитывается путём деления общего дохода на число уникальных пользователей.
### ARPPU (Average revenue per paying user) \{#arppu-average-revenue-per-paying-user\}
ARPPU расшифровывается как Average Revenue Per Paying User (средний доход на платящего пользователя) в результате A/B-теста. Рассчитывается как общий доход, делённый на число уникальных платящих пользователей. Например, если вы получили $15 000 дохода от 1 000 платящих пользователей, ARPPU составит $15.
### ARPAS (Average revenue per active subscriber) \{#arpas-average-revenue-per-active-subscriber\}
ARPAS — метрика, позволяющая измерить средний доход, генерируемый на активного подписчика в результате A/B-теста. Рассчитывается путём деления общего дохода на число подписчиков, активировавших пробный период или подписку. Например, если общий доход составляет $5 000 и у вас 1 000 подписчиков, ARPAS составит $5. Эта метрика помогает оценить средний потенциал монетизации на одного подписчика.
### Proceeds \{#proceeds\}
Метрика Proceeds для A/B-теста представляет фактическую сумму денег, полученных владельцем приложения в USD от покупок и продлений после вычета применимой комиссии App Store / Play Store. Она отражает чистый доход, непосредственно связанный с вариациями, протестированными в A/B-тесте, и напрямую влияет на заработок приложения. Дополнительную информацию о том, как рассчитываются Proceeds, см. в [документации](analytics-cohorts#revenue-vs-proceeds) Adapty.
### Unique subscribers \{#unique-subscribers\}
Метрика Unique subscribers представляет количество уникальных пользователей, оформивших подписку или активировавших пробный период через вариации в A/B-тесте. Каждый подписчик учитывается только один раз, независимо от числа инициированных подписок или пробных периодов.
### Unique paid subscribers \{#unique-paid-subscribers\}
Метрика Unique paid subscribers представляет число уникальных пользователей, успешно совершивших покупку и ставших платными подписчиками через вариации в A/B-тесте.
### Refund rate \{#refund-rate\}
Refund rate для A/B-теста рассчитывается путём деления числа возвратов, непосредственно связанных с вариациями теста, на число первичных покупок (продления исключаются). Например, если было 5 возвратов и 1 000 первичных покупок, refund rate составит 0,5%.
### Unique CR purchases \{#unique-cr-purchases\}
Уникальный коэффициент конверсии в покупки для A/B-теста рассчитывается путём деления числа покупок, непосредственно связанных с вариациями теста, на число уникальных просмотров. Например, если было 10 покупок и 100 уникальных просмотров, уникальный коэффициент конверсии в покупки составит 10%.
### Unique CR trials \{#unique-cr-trials\}
Уникальный коэффициент конверсии в пробные периоды для A/B-теста рассчитывается путём деления числа запущенных пробных периодов, непосредственно связанных с вариациями теста, на число уникальных просмотров. Например, если было запущено 30 пробных периодов и 100 уникальных просмотров, уникальный коэффициент конверсии в пробные периоды составит 30%.
### Completions & unique completions \{#completions--unique-completions\}
Только для A/B-тестов онбординга. Completions подсчитывают количество раз, когда пользователи завершают онбординг через вариации в A/B-тесте, то есть проходят путь от первого до последнего экрана. Если кто-то завершил его дважды, это два **completions**, но одно **unique completion**.
### Unique completions rate \{#unique-completions-rate\}
Только для A/B-тестов онбординга. Число уникальных завершений, делённое на число уникальных просмотров. Эта метрика помогает понять, как пользователи взаимодействуют с онбордингом через вариации в A/B-тесте, и вносить изменения, если вы замечаете, что пользователи его игнорируют.
---
# File: maths-behind-it
---
---
title: "Математика за A/B-тестами"
description: "Разберитесь в математике за аналитикой подписок для более глубокого понимания доходов."
---
A/B-тестирование — мощный инструмент для сравнения эффективности двух версий флоу, пейвола или онбординга. Конечная цель — определить, какая версия приносит больше дохода на пользователя за 12-месячный период. Однако ждать целый год ради сбора данных непрактично. Поэтому в качестве прокси-метрики используется доход на пользователя за 2 недели — этот показатель выбран на основе анализа исторических данных как аппроксимация целевой метрики. Чтобы получить точные и надёжные результаты, необходим статистический метод, способный работать с разнородными данными. Байесовская статистика — популярный подход в современном анализе данных — предоставляет гибкий и интуитивно понятный фреймворк для A/B-тестирования. Байесовские методы учитывают предварительные знания и обновляют их по мере поступления новых данных, что позволяет принимать взвешенные решения в условиях неопределённости. Этот документ содержит подробное описание математического анализа, который Adapty применяет при оценке результатов A/B-тестов и формировании выводов для принятия решений на основе данных.
## Подход Adapty к статистическому анализу \{#adaptys-approach-to-statistical-analysis\}
Adapty использует комплексный подход к статистическому анализу, чтобы оценивать результаты A/B-тестов и давать точные и надёжные выводы. Наша методология включает следующие ключевые шаги:
1. **Определение метрики:** Чтобы успешно провести A/B-тест, нужно определить ключевую метрику, которая соответствует целям и задачам анализа. Adapty проанализировал огромный массив исторических данных приложений с подписками, чтобы выяснить, какой показатель лучше всего служит прокси-метрикой для долгосрочной цели — средней выручки через 1 год. Этой метрикой оказался ARPU за 14 дней.
2. **Формулировка гипотез:** Для A/B-теста формулируются две гипотезы. Нулевая гипотеза (H0) предполагает, что значимой разницы между контрольной группой (A) и тестовой группой (B) нет. Альтернативная гипотеза (H1) предполагает, что значимая разница между двумя или более группами существует.
3. **Выбор распределения:** Мы выбираем наиболее подходящее семейство распределений, исходя из характеристик данных и наблюдаемой метрики. Чаще всего используется логнормальное распределение (с учётом нулевых значений).
4. **Расчёт вероятности быть лучшим:** Используя байесовский подход к A/B-тестированию, мы рассчитываем вероятность быть наилучшим вариантом для каждого пейвола или онбординга, участвующего в тесте. Это значение связано с p-value, которые применялись ранее, но по сути представляет собой другой подход — более надёжный и понятный.
5. **Интерпретация результатов:** Вероятность быть лучшим означает именно то, о чём говорит название. Чем выше вероятность, тем больше шансов, что конкретный вариант окажется оптимальным для решаемой задачи. Порог для принятия решений нужно определять самостоятельно с учётом множества факторов конкретной ситуации; типичное пороговое значение вероятности — 95%.
6. **Интервалы прогнозирования:** Adapty рассчитывает интервалы прогнозирования для метрик производительности каждой группы, задавая диапазон значений, в который с высокой вероятностью попадает истинный параметр генеральной совокупности. Это помогает количественно оценить неопределённость, связанную с оцениваемыми метриками.
## Определение размера выборки \{#sample-size-determination\}
Правильный выбор размера выборки — ключевое условие надёжных и однозначных результатов A/B-теста. Adapty учитывает такие факторы, как статистическая мощность и ожидаемый размер эффекта — они остаются важными и в рамках байесовского подхода, — чтобы обеспечить достаточный объём выборки. Методы оценки необходимого размера выборки, характерные для используемого байесовского подхода, гарантируют надёжность анализа.
Чтобы узнать больше о функциональности A/B-тестов, рекомендуем ознакомиться с нашей документацией по [созданию](ab-tests) и [запуску A/B-тестов](run_stop_ab_tests), а также разобраться с различными [метриками и результатами A/B-тестов](results-and-metrics).
Аналитическая система Adapty для A/B-тестов теперь использует байесовский подход, однако основные принципы остались прежними: определение метрик, формулировка гипотез и выбор распределений. Вместо p-значений мы теперь вычисляем апостериорные распределения и рассчитываем вероятность того, что каждый вариант является лучшим. Также мы определяем интервалы предсказания. Этот обновлённый подход — не менее полный, но более надёжный — даёт результаты, которые проще интерпретировать и понимать. Цель остаётся прежней: помочь бизнесу оптимизировать стратегии, улучшать показатели и расти на основе статистически обоснованного анализа A/B-тестов.
---
# File: autopilot-how-it-works
---
---
title: "AI Growth Advisor: принцип работы"
description: "Разберитесь в логике AI Growth Advisor и доверьтесь нам для роста вашего дохода."
---
[AI Growth Advisor](autopilot) помогает понять, какие эксперименты стоит запустить, опираясь на реальные данные о вашей эффективности и на то, как ведут себя похожие приложения в вашей нише. Вместо того чтобы гадать, что может сработать, вы получаете конкретные рекомендации по тестам, которые с большей вероятностью улучшат результаты.
В этой статье подробно разобрано, как работает AI Growth Advisor: какие данные он использует, как оценивает возможности и почему появляются те или иные рекомендации. Цель — чтобы вы могли уверенно использовать его в рабочем процессе роста.
## Что на самом деле делает AI Growth Advisor \{#what-ai-growth-advisor-actually-does\}
AI Growth Advisor анализирует метрики вашего приложения и пейволов, чтобы найти эксперименты, которые с наибольшей вероятностью увеличат доход. Он изучает:
- **Вашу текущую настройку**: цены, пробные периоды, продукты и их конверсию
- **Рыночные паттерны**: как похожие приложения структурируют свои предложения и что они берут
- **Историю тестов**: какие эксперименты вы уже проводили и что они показали
- **Потенциал роста**: какие изменения с наибольшей вероятностью принесут результат
Growth Advisor использует ИИ, чтобы оценить все эти факторы вместе и превратить их в A/B-тесты, которые можно запустить прямо сейчас. Вы получаете готовый план без необходимости исследовать конкурентов или гадать, что тестировать следующим.
## Данные, на которых работает AI Growth Advisor \{#the-data-behind-ai-growth-advisor\}
Каждая рекомендация строится на трёх основных источниках данных, которые работают в связке.
#### Собственные данные вашего приложения \{#your-apps-own-data\}
AI Growth Advisor анализирует, как ваше приложение работает сегодня:
- Метрики конверсии по вашим пейволам
- Структура цен и продуктов
Это даёт AI Growth Advisor отправную точку, прежде чем предлагать какие-либо изменения.
:::note
Мы не используем данные о производительности вашего приложения для обучения рекомендаций для других приложений. Ваши данные остаются конфиденциальными.
:::
#### Анализ пейвола \{#paywall-analysis\}
AI Growth Advisor анализирует скриншот вашего пейвола и сравнивает его дизайн с устоявшимися паттернами, которые используют лучшие приложения в вашей категории. Он оценивает компоновку, тексты, описание подписок и элементы, ориентированные на конверсию, — например, бейджи с выгодой или блоки с отзывами.
По результатам анализа формируются два типа рекомендаций:
- **Рекомендации на основе бенчмарков** — что делают по-другому лучшие приложения, каждая подкреплена конкретной статистикой (например, «Используется в 72% лучших приложений категории Education»).
- **Рекомендации визуального анализа**, сгенерированные ИИ на основе вашего скриншота: улучшения текста, изменения макета и другие корректировки дизайна.
Эти рекомендации напрямую попадают в ваш [план роста](autopilot-growth-plan#view-the-growth-plan) как гипотезы, которые можно [запустить в виде A/B-тестов](autopilot-execute-plan).
#### Данные о конкурентах \{#competitor-data\}
AI Growth Advisor сравнивает вашу настройку с похожими приложениями в вашей категории, используя публичные данные: ценообразование, структуру подписок и распространённые паттерны в вашей нише. Эти сравнения выполняются в разрезе стран, поскольку цены конкурентов и их структуры различаются по рынкам. Данные о ценах конкурентов поступают из сторонних и публичных источников, например из App Store, — и не связаны с анонимизированными данными сети Adapty, которые используются для анализа метрик.
Таким образом, вы тестируете стратегии, которые уже работают у похожих приложений, а не случайные идеи. Когда вы видите аналитику, вы можете сравнить свои показатели и цены конкурентов бок о бок. Если у похожих приложений дела идут лучше с другим ценообразованием или структурой — это хороший сигнал, что тот же подход может сработать и у вас.
:::tip
AI Growth Advisor автоматически подбирает релевантных конкурентов — тех, с которыми вы реально можете конкурировать. Как правило, мы рекомендуем придерживаться этих предложений, а не добавлять приложения, которые намного опережают вас или намного уступают. Если ваше приложение относится к нескольким категориям, возможно, стоит скорректировать список, чтобы сосредоточиться на наиболее релевантном сегменте рынка.
:::
#### Отраслевые бенчмарки \{#industry-benchmarks\}
AI Growth Advisor использует анонимизированные данные 20 000 приложений с подписками, отслеживаемых Adapty, чтобы показать, как вы выглядите на фоне среднего значения по категории в конкретной стране. Данные агрегируются по всей сети и никогда не привязываются к конкретному приложению.
Например, ваша воронка конверсий и доход с установки сравниваются со средними показателями приложений в вашей категории и стране. Это позволяет понять, отстаёте ли вы, держитесь на уровне среднего или уже опережаете конкурентов.
#### Данные по географическим рынкам \{#geographic-market-data\}
AI Growth Advisor анализирует отдельные географические рынки — опираясь на паттерны сети из 20 000 приложений Adapty — чтобы выявить, где региональные корректировки цен могут принести больше дохода. Для каждой страны оцениваются:
- **Конверсия**: как соотношение установок к платным пользователям соотносится с общемировым средним. Высокий показатель может говорить о возможности повысить цены; низкий — о чувствительности к ценам.
- **Ценовой индекс**: позиция страны в [Adapty Pricing Index](https://uploads.adapty.io/adapty_pricing_index.pdf), отражающая покупательную способность её жителей.
Вы можете действовать по этим рекомендациям, создавая A/B-тесты на основе [предложений по гео-ценообразованию](autopilot-growth-plan#geo-pricing-hypotheses) в вашем плане роста.
## Как AI Growth Advisor принимает решения о рекомендациях \{#how-ai-growth-advisor-decides-what-to-recommend\}
AI Growth Advisor формирует набор предложений по улучшению конверсии вашего пейвола. Эти предложения рассчитаны на поочерёдное тестирование — чтобы можно было надёжно измерить эффект каждого изменения.
Вот как AI Growth Advisor приходит к своим предложениям:
1. **Находит наиболее перспективные точки роста**
AI Growth Advisor анализирует ваши цены, продукты и эффективность воронки, а затем сравнивает их с отраслевыми паттернами и похожими приложениями. Анализ ведётся в валюте вашего основного рынка, а не только в USD, — поэтому рекомендации по ценам соответствуют тому, что реально платят ваши подписчики. Советник определяет, где у вас больше всего пространства для роста: скорректировать цену, добавить пробный период или изменить структуру оффера.
2. **Выберите следующий эксперимент**
Каждая гипотеза генерируется на основе истории ваших тестов. AI Growth Advisor знает, какие эксперименты вы уже проводили, какие из них победили и в каких направлениях ещё есть смысл работать. Следующее предложение опирается на результаты предыдущего, а не следует фиксированной последовательности.
3. **Запускайте тесты «победитель против претендента»**
После каждого эксперимента победитель становится новым базовым вариантом. Этот результат определяет следующую рекомендацию в вашем плане роста — AI Growth Advisor сохраняет то, что сработало, отсеивает то, что не дало результата, и выбирает следующий тест.
4. **Оставайтесь практичными**
AI Growth Advisor предлагает только те тесты, которые можно запустить с уже имеющимися продуктами и настройками — или с небольшими изменениями вроде создания нового продукта или корректировки цены. Цель — сделать тестирование быстрым и управляемым.
5. **Объясняет логику рекомендаций**
Для каждой рекомендации AI Growth Advisor формулирует чёткую гипотезу: почему этот тест стоит запустить. Вы увидите, как ваши текущие метрики соотносятся с показателями конкурентов и отраслевыми средними, в чём заключается возможность для роста и какие ключевые метрики должны улучшиться.
Это превращает эксперименты в повторяемый процесс, где каждый тест чему-то учит и приближает вас к более эффективному пейволу.
## Что происходит после каждого эксперимента \{#what-happens-after-each-experiment\}
Рекомендации не заканчиваются. Каждый завершённый тест становится основой для новых экспериментов. Пока вы продолжаете тестировать, AI Growth Advisor продолжает предлагать, что попробовать дальше.
Чтобы обновить рыночные данные, запустите анализ для того же плейсмента повторно. Каждый повторный запуск подтягивает актуальные цены конкурентов, эталонные показатели конверсии и тренды категории, а также добавляет новые гипотезы в ваш план роста, не затрагивая уже существующие. Все созданные ИИ гипотезы, пользовательские гипотезы и текущие A/B-тесты сохраняются при повторных запусках.
После оптимизации базового варианта вы можете перейти к конкуренции с более продвинутыми альтернативами. Такой итеративный подход помогает постоянно наращивать доход по мере роста приложения и эволюции рынка.
:::tip
Готовы попробовать? Запустите [AI Growth Advisor](autopilot-analysis), чтобы проанализировать пейволы и сформировать план роста с A/B-тестами. Воспользуйтесь [встроенным мастером](autopilot-execute-plan), чтобы легко запускать сложные тесты: он проведёт вас через создание продуктов, дублирование пейволов и настройку сегментов.
:::
---
# File: autopilot-analysis
---
---
title: "Анализ пейвола и рынка"
description: "Получите план роста на основе данных, адаптированный под ваше приложение."
---
Следуйте инструкциям в статье, чтобы запустить анализ AI Growth Advisor и сгенерировать план роста.
Если вы уже создавали план роста для целевого плейсмента, этот анализ предложит новые гипотезы на выбор.
:::tip
Убедитесь, что вы выполнили [требования для анализа](autopilot#prerequisites) перед началом работы.
:::
## Анализ пейвола \{#paywall-analysis\}
### Выберите пейвол для анализа \{#select-a-paywall-for-analysis\}
1. Откройте страницу **AI Growth Advisor** и нажмите кнопку [Get Growth plan](https://app.adapty.io/ab-tests/analysis/start).
2. На странице **Paywall Diagnostic** выберите **Placement** и **Paywall** из выпадающих списков. Adapty автоматически предлагает плейсмент с наибольшей выручкой и его лучший пейвол. Чтобы проанализировать другой пейвол, сначала смените плейсмент.
3. Загрузите скриншот. AI Growth Advisor нужен скриншот для анализа дизайна и содержимого вашего пейвола.
4. Проверьте активные продукты пейвола. Карточки продуктов справа показывают длительность подписки, цену и пробный период для каждого продукта.
5. Нажмите **Confirm & Analyze**, чтобы продолжить. Adapty проанализирует ваш пейвол и отобразит диагностический отчёт.
### Отчёт об анализе пейвола \{#paywall-analysis-report\}
После того как вы выберете пейвол и загрузите скриншот, Adapty проанализирует его на соответствие устоявшимся паттернам дизайна и укажет как на удачные решения, так и на точки роста.
#### Что работает хорошо \{#whats-working-well\}
В этом разделе отображаются применённые вами паттерны, которые максимизируют конверсию. Например: заметный бейдж с экономией, выделенный блок с отзывами пользователей или понятная разбивка подписок.
#### Что исправить на пейволе \{#what-to-fix-on-your-paywall\}
Adapty разбивает рекомендации на две категории:
- **Рекомендации на основе бенчмарков**: предложения на основе данных о лучших приложениях в вашей категории. Каждая рекомендация содержит статистику бенчмарка (например, «Используется в 72% лучших приложений категории Education») и описание того, что нужно изменить.
- **Рекомендации на основе визуального анализа**: предложения, сгенерированные ИИ на основе скриншота вашего пейвола. Они включают: улучшения текста, изменения макета и многое другое.
:::tip
Ваш [план роста](autopilot-growth-plan#view-the-growth-plan) будет включать гипотезы на основе бенчмарковых рекомендаций. Визуальные предложения по анализу можно добавить в план вручную.
:::
Нажмите **Get Market Insights**, чтобы продолжить.
## Анализ рынка и конкурентов \{#market-and-competitor-analysis\}
:::note
Анализ рынка и конкурентов требует предварительного завершения [анализа пейвола](#paywall-analysis).
:::
Анализ Market Insights сравнивает цены и метрики конверсии вашего приложения с конкурентами и средними показателями по отрасли. Сравнения выполняются в разрезе стран. Для формирования эталонных показателей Adapty агрегирует и анализирует данные приложений App Store в вашей подкатегории и стране — эти данные не публикуются в открытом доступе.
### Выбор конкурентов \{#select-competitors\}
Выберите до 5 конкурентов для сравнения.
Adapty автоматически подберёт 5 приложений и предложит ещё 5. Вы также можете добавить приложения вручную по ссылке из App Store. Для лучших результатов выбирайте приложения с MRR выше вашего.
Нажмите **Generate report**, чтобы подтвердить список, и дождитесь завершения анализа.
### Выберите страну \{#select-a-country\}
Используйте выпадающий список **Country**, чтобы выбрать одну из ваших ключевых стран для детального анализа.
### Распределение выручки \{#revenue-distribution\}
Этот график распределения выручки показывает, из каких стран поступает ваш доход, с разбивкой по процентам. На нём выделены топ-5 стран, которые и будут в центре внимания дальнейшего анализа.
### Таблица цен конкурентов \{#competitor-pricing\}
Таблица цен конкурентов сравнивает цены на подписки вашего пейвола с ценами конкурентов в [выбранной стране](#select-a-country). Для каждой длительности подписки предусмотрен отдельный столбец.
### Конверсионная воронка \{#conversion-funnel\}
График показывает коэффициенты конверсии — Views-to-Trial, Trial-to-Paid и Views-to-Paid — в сравнении со средними значениями по похожим приложениям.
### Распределение выручки по длительности подписки \{#revenue-distribution-by-duration\}
Этот график показывает, какие длительности подписок вносят наибольший вклад в вашу выручку, в сравнении со средними показателями по индустрии. Если выручка сильно сконцентрирована в одной длительности, это может указывать на возможность оптимизировать ценовую стратегию.
### Activation ARPU
График **Activation ARPU: your app vs. category** сравнивает средний доход с одной новой установки вашего приложения со средним показателем по категории.
Используйте его вместе с [воронкой конверсии](#conversion-funnel):
- Конверсия показывает, сколько пользователей платят.
- Activation ARPU показывает средний доход на одного пользователя.
Высокая конверсия при низком Activation ARPU может свидетельствовать о том, что предложения недооценены.
Метрика основана на **когортах**. Adapty берёт пользователей, установивших приложение за последние 90 дней, и делит полученный от них доход на их количество.
#### Сравнение с другими метриками \{#comparison-to-other-metrics\}
ARPU при активации не совпадёт со значениями ARPU, которые вы видите в других разделах дашборда — каждая метрика измеряет разные вещи.
- **[График ARPU](arpu)**: учитывает продления от более старых когорт, поэтому значение в несколько раз выше, чем ARPU при активации.
- **[График Revenue](revenue), фильтр Period установлен на «Activation»**: учитывает только первый платёж каждого пользователя. Продления когорты в рамках 90-дневного окна не учитываются.
- **[Доход когорты](analytics-cohorts) (90 дней)**: наиболее близкий эквивалент — используйте эту метрику как ориентир.
## Дальнейшие шаги \{#next-steps\}
Прочитайте статью [Управление и выполнение плана роста](autopilot-growth-plan), чтобы узнать, как запускать A/B-тесты на основе результатов анализа.
Результаты анализа всегда можно посмотреть на странице плана роста — просто перейдите на вкладку **Analysis Results**.
---
# File: autopilot-growth-plan
---
---
title: "Управление планом роста"
description: "Добавляйте пользовательские гипотезы, архивируйте их и обновляйте план роста."
---
После завершения [анализа](autopilot-analysis) Adapty формирует план роста — список **конкретных гипотез по улучшению**. Каждый пункт предлагает новую ценовую точку или изменение дизайна.
Откройте гипотезу, чтобы [проверить её с помощью A/B-теста](autopilot-execute-plan).
У каждого плейсмента есть свой план роста. По мере изменения рыночных условий вы можете повторно запустить анализ, чтобы обновить предложения. Предыдущие запуски сохраняются в истории версий.
## Гипотезы \{#hypotheses\}
Переключайтесь между вкладками вверху раздела growth plan, чтобы фильтровать гипотезы по типу:
- **Top priority** включает гипотезы с наибольшим потенциалом, заслуживающие вашего внимания. Если таких гипотез нет, вкладка скрыта.
- **All** показывает все гипотезы из активного плана.
- **Pricing** — гипотезы, исследующие новые ценовые точки или конфигурации пробного периода. Каждая основана на конкретной рекомендации из диагностики пейвола или отчёта о рыночных инсайтах.
- **Visual** — предложения по улучшению дизайна. Могут включать изменения текста, макета или других визуальных элементов.
- Гипотезы [**Geo-pricing**](#geo-pricing-hypotheses) тестируют корректировку цен для отдельных стран.
- Гипотезы [**Archived**](#archive-a-hypothesis) — предложения, удалённые из активного плана. Их можно восстановить в любой момент.
Вы можете [добавить собственную гипотезу](#add-your-own-hypothesis) или [архивировать](#archive-a-hypothesis) те, которые не хотите тестировать.
Проверяйте гипотезы по одной, в любом порядке. Исключение — тесты гео-ценообразования: их аудитории не пересекаются, поэтому они могут выполняться параллельно.
### Гипотезы гео-прайсинга \{#geo-pricing-hypotheses\}
:::important
Разовые покупки не поддерживают региональную оптимизацию цен.
:::
Откройте вкладку **Geo-pricing**, чтобы увидеть список рекомендаций по гео-прайсингу. Каждая рекомендация направлена на одну страну с одним изменением цены и запускается как отдельный A/B-тест.
Adapty определяет страны, в которых требуется корректировка цен, и предоставляет рекомендации на основе данных, проверенных с помощью [Adapty Pricing Index](https://uploads.adapty.io/adapty_pricing_index.pdf).
Также можно [получить те же данные через API](export-analytics-api). Независимо от способа, файл с данными будет одинаковым.
Эта функция открывает доступ к исходным данным, которые можно дополнительно анализировать в табличных редакторах или других инструментах для более глубокого изучения.
### Отображение валовой или чистой выручки \{#display-gross-or-net-revenue\}
Для графиков, связанных с выручкой ([Revenue](revenue), [MRR](mrr), [ARR](arr), [ARPU](arpu), [ARPPU](arppu)), Adapty предлагает выпадающий список с тремя режимами отображения:
- **Gross revenue** — общая выручка без каких-либо вычетов.
- **Proceeds after store commission** — выручка за вычетом комиссии стора, без учёта налогов.
- **Proceeds after store commission and taxes** — выручка за вычетом как комиссии, так и налогов.
Подробнее о расчёте комиссий и налогов см. в разделе [Комиссии и налоги](how-adapty-analytics-works#commissions-and-taxes) статьи *Как работает аналитика Adapty*.
---
# File: revenue
---
---
title: "Выручка"
description: "Отслеживайте и анализируйте выручку вашего приложения с помощью аналитики подписок Adapty."
---
График Revenue отображает суммарный доход от подписок и разовых покупок за вычетом возвратов. Это основная метрика для отслеживания финансовых результатов приложения.
Переключитесь на месячное разрешение, чтобы оценить общие тренды за последние 12 месяцев. Сгруппируйте график по продукту, сегменту пользователей или источнику атрибуции, чтобы понять, откуда приходит доход, и следите за соотношением новых и повторных платежей — это поможет разобраться, что именно движет ростом.
## Расчёт \{#calculation\}
:::warning
Калькулятор ниже **не учитывает** [комиссию стора и налоги](how-adapty-analytics-works#commissions-and-taxes). Сравнивайте результат с расчётами **валовой выручки**.
:::
Выручка — это сумма всех платных транзакций за период (новые подписки, продления, конвертации из пробного периода, разовые покупки) за вычетом возвратов, обработанных в этом же периоде: **Выручка = все транзакции − возвраты**.
Полная сумма каждой транзакции учитывается в день покупки, а не распределяется по сроку действия подписки.
График по умолчанию отображает валовую выручку. Используйте [настройки графика](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue), чтобы переключиться между валовой выручкой, выручкой за вычетом комиссии или выручкой за вычетом комиссии и налогов.
## Воронка шаг за шагом \{#funnel-chart-step-by-step\}
Разберём элементы воронки, чтобы понять, как читать пользовательский путь на графике.
### Установки \{#installs\}
1-я колонка (1) — количество установок. Отображается как абсолютное значение (2) общего числа установок (не уникальных пользователей), а также как 100% — максимальное исходное число для расчёта относительных конверсий на последующих шагах. Если пользователь удаляет приложение и устанавливает его заново, это считается двумя отдельными установками.
Серая область рядом отражает параметры перехода между шагами. Процент конверсии на следующий шаг (Отображённый пейвол) показан на флажке (3). Ниже (4) указаны процент отсева и абсолютное значение оттока.
### Пейвол показан
Во 2-м столбце (5) отображается количество пользователей приложения, которые увидели пейвол хотя бы один раз (6). Учитываются только те установки, которые произошли в выбранный период. Если пользователь увидел пейвол в выбранный период, но дата его установки выходит за пределы диапазона, этот просмотр не засчитывается.
Здесь также указывается процент таких просмотров от 1-го шага (7). Можно заметить, что этот процент совпадает с серым флагом (3) 1-го шага. Такое совпадение характерно только для этих первых шагов.
Мы собираем данные для этого шага со всех ваших пейволов, которые используют метод `logShowFlow()` (iOS SDK v4+) / `logShowPaywall()`. Поэтому обязательно отправляйте каждый просмотр пейвола в Adapty с помощью этого метода, как описано в [документации](present-remote-config-paywalls#track-paywall-view-events).
Серая область рядом со 2-м столбцом обозначает переход. Процент конверсии на следующий шаг (Trial) отображается на флажке (8). Процент оттока и абсолютное значение ушедших пользователей после пейвола показаны ниже (9).
### Пробные периоды \{#trials\}
3-й столбец (10) показывает количество пробных периодов, активированных на пейволах пользователями, установившими приложение в выбранный период (11). Если в фильтре указан продукт без пробного периода, это значение равно нулю и столбец остаётся пустым.
Также обратите внимание на процент пробных периодов от первого шага, отражающий конверсию из установок в триалы (12).
Заметьте, что это значение не совпадает с серым флажком (8) конверсии предыдущего шага. Это объясняется тем, что мы сравниваем текущее значение с первым шагом вверху графика, а с предыдущим шагом — на серых флажках.
Серая область рядом с третьим столбцом показывает процент конверсии на следующий шаг (Платный), который отображается на флажке (13). Ниже указаны процент оттока и абсолютное количество пользователей, покинувших воронку в течение пробного периода (14).
### Подписки и продления \{#subscriptions-and-renewals\}
В 4-м столбце отображается количество активированных подписок (15). Для продуктов без пробного периода это число включает прямые подписки с пейвола. Для продуктов с пробным периодом — количество триалов, конвертированных в платные подписки. Если у вас есть продукты обоих типов — с триалом и без — отображается их суммарное значение.
Процент в верхней части показывает конверсию с установок (16).
Процент на сером флаге показывает конверсию на следующий шаг (продление на 2-й период) (17).
Отток до продления на 2-й период — процент и абсолютное значение — отображаются под конверсией (18).
Этот шаг начинает последовательность шагов с аналогичной структурой. После 2-го продления идёт 3-е, затем 4-е и так далее. Если в истории вашего приложения достаточно данных, с помощью горизонтальной прокрутки можно увидеть десятки периодов. Логика этих шагов одинакова:
- процент от установок — вверху,
- процент от предыдущего шага — внизу,
- абсолютное количество продлений — вверху,
- абсолютное количество оттока — внизу,
- всплывающее окно с причинами оттока при наведении курсора.
### Причины оттока \{#churn-reasons\}
Adapty детализирует статистику *оттока* начиная со стадии Trial. Каждый пользователь, который прошёл одну стадию, но не перешёл к следующей, засчитывается как случай оттока.
* Если конкретное событие (например, истечение триала или проблема с оплатой) стало причиной отсутствия конверсии, Adapty отображает эту причину.
* Статус **unknown** — временный. Он означает, что пользователь ещё не столкнулся с событием, которое позволило бы ему перейти к следующей стадии.
На этапе Trial это обычно означает, что пробный период ещё не завершился. Чаще всего это происходит при просмотре воронок за короткие периоды или за один день, поскольку пробные периоды требуют времени для завершения.
Adapty обновит информацию, как только пользователь конвертируется или отменит пробный период.
### Таблица, фильтры и экспорт в CSV \{#table-view-filters-and-csv-export\}
График воронки дополнен таблицей с данными — удобно работать с числами.
Эта таблица повторяет подход воронки с некоторыми изменениями.
В ней есть столбцы с данными по всем шагам, кроме шага первой платной подписки.
Вместо него — два отдельных: Install -> Paid и Trial -> Paid. Они отображают ключевой момент конверсии, когда бесплатный пользователь становится платящим.
Может показаться, что деление по типам продуктов такое: столбец Install → Paid содержит только продукты без триала, а Trial → Paid — только продукты с триалом. Но на самом деле всё немного иначе. Мы также учитываем пользователей, у которых триал истёк и которые затем купили продукт с триалом так, как будто триала у него нет вовсе.
Погружаясь глубже в цифры, вы найдёте мощные инструменты фильтрации для проверки новых гипотез.
Задавайте условия по разным параметрам. Собирайте настоящие инсайты на основе данных.
Варьируйте:
1. Тип продукта — экономика, длительность и т. д.
2. Временной диапазон.
3. Сегментация по стране.
4. Атрибуция трафика.
5. Стор.
Выберите абсолютные значения (#), относительные (%) или оба варианта, чтобы отображать только нужные данные.
Наконец, справа на панели управления есть кнопка для экспорта данных воронки в CSV. Затем вы можете открыть файл в Excel, Google Sheets или импортировать его в собственную аналитическую систему.
:::important
Уведомите Adapty, если ваше приложение участвует в программе сниженной комиссии. Для корректных расчётов укажите статус участия в [программе Small Business Program](app-store-small-business-program) и [программе Reduced Service Fee](google-reduced-service-fee) в [настройках приложения](general).
:::
---
# File: analytics-retention
---
---
title: "Анализ удержания"
description: "Изучите аналитику удержания пользователей и оптимизируйте стратегию подписок."
---
Графики удержания помогают ответить на следующие вопросы:
1. Как приложение удерживает клиентов от периода к периоду?
2. Какие продукты привлекательнее и удерживают лучше?
3. Какие группы пользователей более лояльны?
4. Какой уровень удержания можно использовать как ориентир для роста?
5. И, конечно, как сэкономить, инвестируя в привлечённую аудиторию, а не в захват новой.
Настраивая фильтры и группы, вы найдёте ценные сведения о поведении пользователей.
Данные для анализа удержания мы собираем через SDK и уведомления стора — никакой дополнительной настройки с вашей стороны не требуется.
### Как мы рассчитываем удержание? \{#how-do-we-calculate-retention\}
Наблюдая график удержания, вы видите, как количество пользователей зависит от шага, который они совершают: триал (если установлен флажок «показывать триалы»), 1-й платёж, 2-й платёж и так далее. Уточним, какие пользователи учитываются при выборе диапазона дат для графика удержания.
Например, вы выбрали последние 3 месяца в календаре, а флажок «показывать триалы» снят. Это означает, что учитываются только те, у кого первая подписка была оформлена в течение последних 3 месяцев. Если флажок «показывать триалы» установлен и в календаре выбраны последние 3 месяца, учитываются все, у кого триал начался в течение этих 3 месяцев. Для таких подписчиков абсолютное удержание на N-м шаге отображается как количество тех, кто совершил N-й платёж. Относительное значение удержания на N-м шаге рассчитывается как отношение абсолютного числа N-х платежей к общему числу подписок (или триалов) за выбранный период.
:::info
Retention изменяется ретроспективно
Независимо от того, когда вы смотрите на график, базовое значение (100%) остаётся неизменным для выбранного периода. При этом retention к следующему периоду может расти со временем.
Например, для ежемесячной подписки: если с 1 по 31 декабря было совершено 20 первых покупок, ожидается, что retention ко второму периоду будет расти на протяжении января (а возможно и дольше) — пока пользователи будут переходить в следующий период подписки вовремя или с задержкой по тем или иным причинам (например, из-за льготного периода).
:::
### Обработка возвратов \{#refund-handling\}
Возвраты **не** исключаются из удержания. Пользователь, оформивший возврат, остаётся на кривой удержания, из-за чего Retention может выглядеть выше, чем [Активные подписки](active-subscriptions) или [Выручка](revenue) для той же когорты.
Подробное сравнение по метрикам см. в разделе [Как метрики обрабатывают возвраты](refund-events#how-metrics-handle-refunds).
### Возможности удержания \{#retention-opportunities\}
Разберёмся, как выжать максимум из функции удержания в Adapty.
Чтобы видеть не просто цифры, а реальную бизнес-ценность от аналитических данных, стоит сначала подумать о целях. Углубившись в возможности графиков, важно понять, какое влияние эти данные могут оказать.
Итак, рассмотрим вместе — ЗАЧЕМ и КАК.
1 - работа с аудиторией.
Прежде всего, удержание — это про целевую аудиторию, её предпочтения и то, насколько ваш продукт оправдывает её ожидания на протяжении всего жизненного цикла. Если вы хотите измерить ключевые отношения с теми, кто приносит деньги вашему бизнесу, — удержание именно для этого.
Такой подход выгоден, потому что продавать существующему клиенту обычно дешевле, чем новому. И дешевле по двум причинам: меньше усилий на продажу и более высокий средний чек. Поэтому, когда удержание падает, имеет смысл инвестировать в лояльность подписчиков.
2 — работа с продуктом.
Вторая причина «ЗАЧЕМ» — графики удержания показывают реальное время жизни вашего продукта и позволяют строить долгосрочные прогнозы. Если хотите улучшить показатели, скорректируйте работу, которая обеспечивает продукт, чтобы изменить его время жизни, а затем снова постройте прогноз — и так постепенно приближайтесь к бизнес-целям. Такие обновления могут быть частью стратегического видения, которое работает в связке с регулярным прогнозированием. И да, этот процесс никогда не заканчивается — мы все бежим всё быстрее, чтобы оставаться на месте в постоянно меняющейся среде.
3 — работа с рынком.
Опережать основных конкурентов — хорошо, но иногда выход за рамки привычной гонки приносит больше пользы. Анализируя поведение пользователей в разных странах и сторах, можно заметить местные особенности, которые открывают неожиданные инсайты и новые возможности для бизнеса. Культурный и рыночный контекст можно изучать через призму удержания, а затем использовать для сегментации и дальнейшего развития. Например, в отдельных регионах можно обнаружить «голубой океан» и расти там значительно быстрее.
Конечно, использование данных об удержании не ограничивается этой базовой интерпретацией, но это хорошая отправная точка, если вы хотите быстро получить реальную пользу.
### Кривые, табличное представление, фильтры и экспорт в CSV \{#curves-table-view-filters-and-csv-export\}
Теперь, когда у нас есть общее понимание целей удержания и базовых способов интерпретации, давайте разберём инструменты, которые делают работу с этим удобной.
Основа функции удержания в Adapty — это график. Он показывает, как уровень удержания зависит от шагов в жизненном цикле пользователя.
Шаги отображаются на горизонтальной оси: Trial, Paid (1-я подписка), P2 (2-я подписка), P3, P4 и т. д.
Обратите внимание: ось начинается с шага Trial только тогда, когда установлен флажок «Show trials».
С точки зрения расчёта данных этот флажок работает следующим образом. Когда «Show trials» включён и ось начинается с шага Trial, вы видите только сценарии, содержащие триалы — транзакции напрямую с установок не отображаются, а шаг Paid включает только транзакции, пришедшие из триалов. Когда «Show trials» выключен и ось начинается с шага Paid, этот первый шаг содержит все первые транзакции — как из триалов, так и напрямую с установок.
При наведении курсора на график появляется всплывающее окно с сводкой данных. А при наведении на столбец в таблице ниже отображается аналогичное всплывающее окно с соответствующими данными на графике.
Таблица содержит те же группировки и фильтры, которые выбраны для графика.
Используйте комбинации фильтров и группировок для углублённого анализа и получения реальных инсайтов на основе данных.
Варьируйте:
1. Тип продукта.
2. Длительность.
3. Временной диапазон.
4. Страна.
5. Атрибуция трафика.
6. Стор.
Используйте переключатель #Абсолютные / %Относительные значения для отображения нужных данных.
Наконец, справа на панели управления есть кнопка экспорта данных воронки в CSV. Вы можете открыть файл в Excel или Google Sheets, либо импортировать его в собственную аналитическую систему для дальнейшего анализа и прогнозирования в удобной среде.
:::warning
Обязательно укажите, что ваше приложение входит в Small Business Program, в [основных настройках Adapty](https://app.adapty.io/settings/general).
:::
---
# File: analytics-conversion
---
---
title: "Анализ конверсий"
description: "Измеряйте коэффициенты конверсии подписок с помощью аналитических инструментов Adapty."
---
Воронки дают общее представление, удержание отражает лояльность пользователей, а анализ конверсий позволяет оценить эффективность на каждом ключевом шаге пути пользователя — в динамике.
Конверсии помогают ответить на следующие вопросы:
1. Как конверсия приложения меняется со временем? Есть ли сезонные тренды?
2. Как конверсия изменяется в моменты маркетинговых активностей или других новых обстоятельств?
3. Как пользователи из разных регионов реагируют на обновления вашего приложения?
4. Какие типы продуктов лучше конвертируют со временем?
Конверсия рассчитывается на основе данных, которые мы собираем через Adapty SDK и уведомления стора, и не требует никакой дополнительной настройки с вашей стороны.
## Основные элементы управления и графики \{#main-controls-and-charts\}
Выручка — привычный способ измерить успех, но это лишь часть общей картины. Не менее важно понимать, как ведёт себя ваш бизнес с течением времени — в разрезе разных пользовательских сценариев и этапов жизненного цикла. Именно здесь на помощь приходит аналитика конверсий.
Фильтры и группировки помогут глубже изучить поведение пользователей. Чтобы выявлять и отслеживать тенденции, следите за динамикой конверсий в разбивке по дням, месяцам или годам.
С левой стороны графика расположен блок управления шагами конверсии. Он позволяет выбрать конкретные конверсии для отслеживания — например, Install → Trial, Trial → Paid или Paid → Renewal.
Каждая метрика конверсии рассчитывается по следующей логике:
- Пусть **X** — количество пользователей, которые вошли в начальное состояние в выбранную дату (например, установки).
- Пусть **Y** — количество из них, кто в итоге достиг целевого состояния (например, начал пробный период).
- Конверсия рассчитывается как: **Конверсия = (Y / X) × 100%**
:::note
Дата на графике соответствует моменту, когда пользователи перешли в начальное состояние (X) — то есть стали потенциальными покупателями.
:::
Ниже приведено описание каждой конверсии с примерами.
### Install -> Paid
Эта метрика показывает, какой процент пользователей, установивших приложение в определённый день, в итоге совершили первую покупку подписки.
3. Нажмите кнопку **Done**, чтобы сохранить изменения.
---
# File: discrepancies-and-troubleshooting
---
---
title: "Устранение расхождений в данных"
description: "Найдите причину расхождений в данных"
---
Пользователи Adapty могут замечать **расхождения** при сравнении похожих наборов данных из разных источников. В частности, это может происходить при сравнении:
* графиков Adapty с отчётами сторов
* графиков Adapty с графиками сторонних сервисов
* разных графиков внутри Adapty
## Алгоритм устранения расхождений \{#troubleshooting-algorithm\}
Большинство расхождений между Adapty и другими платформами — ожидаемы и нормальны. Они возникают потому, что **разные источники обрабатывают одни и те же данные по-разному**.
В других случаях они указывают на **проблему в конфигурации Adapty**.
Если вы подозреваете, что данные различаются от платформы к платформе, лучший способ разобраться — [экспортировать необработанные данные](export-analytics-api-requests) и **сравнить файлы**.
* Даже в сторах случаются проблемы с обработкой и отображением данных. Для наиболее точного сравнения используйте **необработанные данные о транзакциях** из сторов.
* При сравнении Adapty с другой аналитической платформой опирайтесь на отчёты о транзакциях из сторов как на источник истины.
* Расхождения проще выявлять на небольших объёмах данных. Сравнивайте ограниченные выборки — возьмите конкретный продукт и один день.
* Определите, в чём причина расхождения: в **ценах** или в **количестве событий**. Проблемы с ценами решаются через [обновление продукта](#product-pricing). Проблемы с событиями могут указывать на [неполадки на стороне сервера](#issues-with-server-notifications-and-rtdn).
* Следите за входящими событиями в [ленте событий](event-feed) — там можно заметить неожиданное поведение.
После того как вы определите, где данные расходятся, изучите следующие распространённые причины:
## Проблемы с серверными уведомлениями и RTDN \{#issues-with-server-notifications-and-rtdn\}
Adapty не получает необходимые данные о событиях, если вы неправильно настроили подключение к стору. Это особенно важно для событий, которые происходят без прямого участия пользователя, — продление подписок, проблемы с оплатой и т. д.
Настройте серверную интеграцию как можно скорее ([App Store](enable-app-store-server-notifications) | [Play Store](enable-real-time-developer-notifications-rtdn)) и [подождите](#data-delays), пока сторы установят соединение.
Вы можете [вручную загрузить](importing-historical-data-to-adapty) недостающие данные из App Store Connect в Adapty.
## Отсутствующие данные \{#missing-data\}
### Пользователи с устаревшими версиями приложения \{#users-with-out-of-date-app-versions\}
Если часть пользователей использует старую версию приложения без Adapty SDK, Adapty не получает их данные. По этой причине показатели Adapty и других источников будут расходиться.
### Проблемы с интеграциями \{#integration-issues\}
Некоторые интеграции Adapty (например, Adjust или AppsFlyer) требуют дополнительного кода в приложении. Если вы настроили дашборд Adapty, но не обновили приложение, необходимые данные не появятся в Adapty.
### Отсутствие исторических данных \{#missing-historical-data\}
Adapty не имеет доступа к историческим данным вашего приложения, если вы не [импортировали](importing-historical-data-to-adapty) их вручную. Если [временной диапазон](controls-filters-grouping-compare-proceeds#time-ranges) графика начинается раньше момента интеграции Adapty, а исторические данные не были импортированы, его значения будут отличаться от других источников.
## Задержки данных \{#data-delays\}
Adapty стремится обеспечить анализ экономики вашего приложения практически в режиме реального времени. При этом действуют следующие ограничения и исключения:
* При первой интеграции Adapty данные могут появиться не сразу.
* При подключении интеграции со сторонней платформой синхронизация данных может занять некоторое время.
* После того как Adapty получает данные из стора, их обработка и отображение на странице Analytics занимает ещё **15–30 минут**.
* Обмен данными между Adapty и сторонними сервисами **не всегда происходит мгновенно** из-за множества переменных.
* Расчёт некоторых продвинутых метрик (например, [прогнозов для когорт](predicted-ltv-and-revenue)) требует достаточного объёма данных. Adapty выполняет эти расчёты только после накопления необходимого количества данных.
## Время и календарь \{#time-and-calendar\}
#### Даты и часовые пояса \{#dates-and-timezones\}
Одна из самых распространённых причин расхождений в данных — разные настройки часового пояса.
Adapty считает дни по часовому поясу `UTC`. Если другая платформа использует иной часовой пояс, результаты будут отличаться. По мере увеличения масштаба разница сглаживается.
Вы можете [изменить настройку часового пояса](general#3-reporting-timezone) для каждого приложения.
#### Фискальный календарь Apple \{#the-apple-fiscal-calendar\}
Apple использует собственный [финансовый календарь](https://adapty.io/apple-fiscal-calendar/) для определения периодов продаж и дат выплат.
Каждый «месяц» в этом календаре состоит из **4 или 5 недель** и **может включать дни из соседних календарных месяцев**. Выплаты, как правило, производятся через 30–45 дней после окончания периода продаж.
Например, период продаж «январь 2026» начинается 28 декабря 2025 года — за 4 дня до начала календарного месяца. Ориентировочная дата выплаты за этот период — 5 марта.
Не сравнивайте данные из отчётов о выплатах Apple с календарными месяцами. Вместо этого выберите [произвольный диапазон дат](controls-filters-grouping-compare-proceeds#set-the-date-range), соответствующий нужному периоду продаж.
#### Даты транзакций \{#transaction-dates\}
Некоторые сервисы (например, AppsFlyer) могут применять правила [когорт](analytics-cohorts) при отображении транзакций и относить их к дате установки приложения, а не к дате самой транзакции.
## Расчёт выручки \{#revenue-calculation\}
### Комиссии и налоги \{#fees-and-taxes\}
В зависимости от [настройки](controls-filters-grouping-compare-proceeds#store-commission-and-taxes) графики Adapty могут отображать **валовую выручку**, **выручку после комиссии стора** или **выручку после комиссии стора и налогов**.
Некоторые сторы и сторонние платформы могут не поддерживать отображение валовой выручки или автоматически вычитать налоги. Если вы видите расхождение между двумя графиками выручки, убедитесь, что сравнение корректно.
### Отмены и возвраты \{#cancellations-and-refunds\}
Разные платформы по-разному отображают данные о возвратах. Adapty учитывает возвраты как отрицательную выручку. Если пользователь оформил подписку, а на следующий день запросил возврат, оба события отразятся в графиках Adapty — каждое в свой день. Другие платформы могут вычитать сумму возврата из исходной транзакции.
## Покупки в песочнице \{#sandbox-purchases\}
[Лента событий](event-feed) отображает покупки, сделанные sandbox-аккаунтами. Графики аналитики — нет. Однако если импортированные исторические данные содержат покупки из песочницы, Adapty не сможет их распознать, и графики будут отражать исторические покупки из песочницы.
## Установки и загрузки \{#installs-and-downloads\}
Сторы (особенно Apple App Store) могут отслеживать загрузки напрямую. Их статистика может включать случаи, когда приложение было установлено, но так и не запущено.
Adapty может зарегистрировать установку только тогда, когда пользователь запускает приложение, независимо от вашего [определения установки](general#4-installs-definition-for-analytics).
## Страна и стор \{#country-and-store\}
Для точной отчётности Adapty [может определять](controls-filters-grouping-compare-proceeds#filtering-and-grouping) страну пользователя по IP-адресу. Сторы всегда привязывают загрузки и покупки к конкретному магазину приложений.
Если вам нужно чётко разграничить эти два подхода, вы можете [создать новый сегмент пользователей](segments) с атрибутом `Country by store account` и [фильтровать аналитику по сегменту](controls-filters-grouping-compare-proceeds#filtering-and-grouping).
## Ценообразование продукта \{#product-pricing\}
Если из-за неверного ценообразования возникло расхождение в выручке, изменение цены не исправит его ретроактивно. Чтобы изменить цены в существующих транзакциях, необходимо принудительно перезаписать их путём импорта корректных данных.
Когда пользователь восстанавливает старую покупку после изменения цены, Apple может неверно указать её стоимость. Для корректного отображения в Adapty необходимо импортировать исторические данные.
## Конфликты атрибуции \{#attribution-conflicts\}
Adapty может использовать [только один источник атрибуции](attribution-integration#prevent-data-issues) для каждой транзакции. Впоследствии эти данные нельзя переопределить.
Если в вашей конфигурации несколько провайдеров атрибуции расходятся друг с другом, одна и та же транзакция на двух разных платформах может отображаться с двумя разными источниками трафика.
## Различия в терминологии \{#differences-in-terminology\}
На разных платформах одни и те же понятия могут называться по-разному. Метрики, связанные с [выручкой](#fees-and-taxes), на разных платформах имеют разные названия:
| Adapty | App Store Connect | Google Play Console |
|--------|-------------------|----------------------|
| **Gross revenue** | Sales | Gross Revenue |
| **Proceeds after store commission** | N/A | N/A |
| **Proceeds after store commission and taxes** | Proceeds | Earnings |
| **ARPPU** | Proceeds per paying user | ARPPU |
Определения других метрик также могут различаться:
- **Подписки**:
- Adapty не учитывает новые триалы как подписки. [Новая подписка](reactivated-subscriptions) всегда начинается с финансовой транзакции.
- Другие платформы, например Google Play Console, могут считать **каждый триал новой подпиской** — даже до совершения первого платежа.
- **Удержание**:
- Adapty измеряет удержание на основе количества продлений подписки.
- App Store Connect считает пользователя удержанным, если он открыл приложение в указанный день. Пользователь без подписки засчитывается, а подписчик, не открывший приложение в этот день, — нет.
- Метрика «Retained Installers» в Google Play Console измеряет удержание по количеству дней, в течение которых приложение остаётся установленным на устройстве пользователя. Пользователи, не открывающие приложение, учитываются в этой метрике.
## Метрика «Новые подписки» и событие `subscription_started` \{#new-subscriptions-metric-vs-the-subscription_started-event\}
Метрика [Новые подписки](reactivated-subscriptions) и событие интеграции `subscription_started` ([события интеграции](events)) считают разные вещи, поэтому их итоговые значения не совпадают. Метрика учитывает как первые покупки без пробного периода, так и конвертации из пробного периода в платную подписку. Событие `subscription_started` срабатывает только при первой покупке без пробного периода — когда пробный период конвертируется в платный, Adapty отправляет `trial_converted`. В результате количество новых подписок всегда выше числа событий `subscription_started`, если в вашем приложении есть конвертации из пробного периода.
---
# File: predicted-ltv-and-revenue
---
---
title: "Прогнозы в когортах"
description: "Используйте предиктивную аналитику Adapty для прогнозирования LTV и выручки."
---
Прогнозы Adapty помогают ответить на следующие вопросы:
1. Каков прогнозируемый LTV ваших когорт пользователей?
2. Какие когорты, скорее всего, принесут наибольшую выручку в будущем?
3. Сколько можно вложить с учётом ожидаемой отдачи?
С помощью Adapty Predictions вы можете принимать решения об увеличении доходов и росте приложения на основе данных.
Модель прогнозирования Adapty оценивает долгосрочный потенциал выручки когорт пользователей вашего приложения. Для каждой когорты она строит прогноз того, как будут развиваться выручка, количество платящих подписчиков и средний LTV. Это помогает принимать взвешенные решения в области привлечения пользователей, маркетинговых стратегий и развития продукта.
Adapty предлагает прогноз пожизненной ценности (LTV) и прогноз выручки для когорт платящих подписчиков. Прогнозы отображаются на странице когортного анализа через 3, 6, 9, 12, 18 и 24 месяца после создания когорты.
Для приложений с очень небольшой историей модель использует средние значения по всем приложениям, поэтому прогнозы для новых приложений могут не в полной мере отражать поведение их конкретных пользователей.
## Как работает модель \{#how-the-model-works\}
Модель прогнозирования Adapty использует паттерны удержания из исторических данных когорт для проецирования будущей выручки и LTV.
Для каждой комбинации приложения и типа подписки модель отслеживает изменение числа платящих пользователей и общей выручки от одного периода продления к следующему. Она рассчитывает два коэффициента удержания — один для подписчиков, другой для выручки — на основе прошлых когорт приложения. Затем эти коэффициенты применяются к новым когортам для прогноза их роста через 3, 6, 9, 12, 18 и 24 месяца после создания когорты. Используемые данные полностью анонимизированы.
Модель рассчитывает два значения для каждой когорты:
- **Predicted revenue**: суммарная выручка, которую когорта, по прогнозу, принесёт за выбранный горизонт.
- **Predicted LTV**: predicted revenue, делённый на прогнозируемое количество платящих подписчиков в когорте.
### Веса для конкретного приложения и кросс-приложенческие веса \{#app-specific-and-cross-app-weights\}
По умолчанию прогнозы для когорты используют веса удержания, полученные на основе исторических когорт самого приложения, — это отражает поведение именно его пользователей.
Когда у приложения недостаточно истории для конкретного горизонта прогноза, Adapty использует запасные веса удержания, усреднённые по всем приложениям с аналогичным типом подписки. Например, прогноз на 12 месяцев для приложения, которому всего шесть месяцев, строится на основе кросс-приложенческих запасных данных. Запасной вариант применяется независимо для каждого горизонта, поэтому одна и та же когорта может использовать собственные веса приложения для прогноза на 3 месяца и кросс-приложенческие веса — для прогноза на 12 месяцев.
### Доступность и обновления \{#availability-and-updates\}
Прогнозы становятся доступны после того, как когорта завершает первый период продления — как правило, через неделю после создания для еженедельных подписок и примерно через четыре недели для месячных. После этого прогнозы обновляются ежедневно на основе актуальных транзакционных данных, отражая текущее поведение когорты.
### Ограничения \{#limitations\}
- **Качество данных**: нетипичное поведение когорты или когорты с очень небольшим числом платящих пользователей снижают точность. Когорты с менее чем 100 платящими подписчиками исключаются из обучающих данных модели.
- **Новые приложения**: приложения без достаточной истории используют общие веса на основе данных других приложений, которые могут не отражать специфику поведения пользователей конкретного приложения.
- **Возраст когорты**: прогнозы для заданного горизонта скрываются, как только когорта превышает этот горизонт. Например, трёхмесячные прогнозы перестают отображаться по истечении трёх месяцев, а для когорт старше 24 месяцев прогнозы не показываются вовсе.
## В дашборде \{#in-the-dashboard\}
Чтобы посмотреть прогнозы, перейдите на страницу когортного анализа в дашборде Adapty. Подробнее о когортах — в разделе [Когортный анализ](analytics-cohorts).
Столбец **Predicted revenue** показывает предполагаемую совокупную выручку, которую когорта подписчиков должна принести за выбранный период после её создания. Значение рассчитывается с помощью модели прогнозирования Adapty на основе исторических паттернов удержания когорт приложения.
Столбец **Predicted LTV** показывает предполагаемую пожизненную ценность каждого пользователя в выбранной когорте. Значение рассчитывается путём деления прогнозируемой выручки на прогнозируемое количество платящих пользователей в когорте.
### Выберите горизонт прогноза \{#select-the-horizon\}
Чтобы изменить горизонт прогноза, выберите нужное значение в выпадающем списке **Predictions**. Доступные варианты: 3, 6, 9, 12, 18 и 24 месяца с момента создания когорты.
### Фильтрация по продукту \{#filter-by-product\}
Вы можете фильтровать прогнозируемый доход и LTV по продукту. По умолчанию прогнозы строятся на основе всех данных о покупках — фильтрация по продукту показывает вклад каждого продукта.
## Когда прогнозы недоступны \{#when-predictions-are-unavailable\}
Если для когорты невозможно построить прогноз, в столбцах Predicted Revenue и Predicted LTV отображаются длинные тире (—) вместо значений. Это может происходить по нескольким причинам:
- **Недостаточно времени с момента создания когорты**: Прогнозы становятся доступны только после того, как когорта завершит первый период продления — примерно через неделю для недельных подписок и около четырёх недель для месячных.
- **Маленький размер когорты**: Слишком мало платящих подписчиков для надёжного прогноза.
- **Нестандартное поведение когорты**: Когорта значительно отклоняется от паттернов, ожидаемых моделью. Подождите несколько недель — по мере накопления данных ситуация может исправиться.
- **Горизонт превышен**: Когорта старше выбранного горизонта прогнозирования. Например, 3-месячный прогноз скрывается через три месяца, 12-месячный — через двенадцать, а для когорт старше 24 месяцев прогнозы не отображаются вовсе.
:::warning
При включении прогнозов учтите, что данные прогнозов по Revenue и LTV могут появиться на дашборде Adapty с задержкой до 24 часов.
:::
---
# File: predictions-in-ab-tests
---
---
title: "Прогнозы в A/B-тестах"
description: "Узнайте, как прогнозы в A/B-тестах помогают уточнять стратегии ценообразования подписок."
---
Добро пожаловать в документацию по предиктивной аналитике Adapty для функции A/B-тестирования. Этот инструмент даёт представление о будущих результатах ваших текущих A/B-тестов и помогает принимать решения на основе данных быстрее 🚀 — с помощью прогнозов Adapty на базе машинного обучения.
### Что такое прогнозы A/B-тестов? \{#what-are-ab-test-predictions\}
Прогнозы A/B-тестов в Adapty используют продвинутые методы машинного обучения (а именно модели градиентного бустинга), чтобы предсказать долгосрочный потенциальный доход от пейволов, сравниваемых в A/B-тесте.
Прогнозная модель позволяет выбрать наиболее эффективный пейвол на основе прогнозируемой выручки за год, а не опираться только на метрики, которые вы наблюдаете в ходе теста. Это помогает быстрее и надёжнее определить победителя — без необходимости ждать неделями, пока накопится достаточно данных.
### Как работает модель? \{#how-does-the-model-work\}
Модель обучена на обширных исторических данных A/B-тестов из множества приложений разных категорий. Она использует широкий набор признаков для прогнозирования выручки, которую пейвол, вероятно, сгенерирует в течение года после начала эксперимента. В числе этих признаков:
- Транзакции пользователей и конверсии за разные периоды
- Географическое распределение пользователей
- Используемая платформа (iOS или Android)
- Показатели отказов и возвратов
- Продукты с подписками и их периоды (ежедневные, ежемесячные, ежегодные и т. д.)
- Другие данные, связанные с транзакциями
Модель также учитывает пробные периоды в пейволах, используя исторические коэффициенты конверсии для прогнозирования дохода так, как если бы пользователи уже конвертировались. Это обеспечивает справедливое сравнение пейволов с пробными периодами и без них, поскольку мы также учитываем, что активные пробные периоды потенциально принесут доход в будущем.
### Чем Predicted P2BB отличается от обычного P2BB? \{#how-is-predicted-p2bb-different-from-just-the-p2bb\}
В наших A/B-тестах используется байесовский подход: мы моделируем распределение дохода на пользователя (точнее, «Доход на 1000 пользователей») и затем вычисляем вероятность того, что одно распределение «действительно» лучше другого, а не случайно — это и называется вероятностью быть лучшим, или P2BB (подробнее о нашем подходе можно узнать [здесь](maths-behind-it)).
Важно учитывать, что при этом мы опираемся только на выручку, накопленную за время проведения теста. Поэтому если вы сравниваете годовую подписку с еженедельной, вам придётся ждать очень долго, чтобы действительно понять, что работает лучше. Похожая ситуация возникает при сравнении триальных подписок с нетриальными в A/B-тесте — активные триалы, которые потенциально могут изменить расстановку сил, всегда остаются за рамками учитываемой выручки.
Именно здесь в дело вступает наша прогностическая модель. Имея текущее распределение выручки в A/B-тесте и будучи обученной на большом наборе данных, она способна предсказать будущий вид этого распределения (а именно — спустя 1 год). После этого модель вычисляет прогнозируемый P2BB — тот, который вы получили бы, если бы запускали тест в течение целого года.
Обратите внимание, что иногда прогнозируемый P2BB может противоречить текущему P2BB. В таких случаях мы выделяем строки с вариантами жёлтым цветом, вот так:
Мы считаем это сигналом к тому, чтобы накопить больше данных и подтвердить победителя или глубже изучить A/B-тест, чтобы выяснить причину. Как правило, мы рекомендуем доверять прогнозируемому P2BB, а не текущему, поскольку он учитывает больше данных — но окончательное решение, конечно, остаётся за вами.
### Точность и достоверность модели \{#model-accuracy-and-certainty\}
Модель обеспечивает высокий уровень точности: средняя абсолютная процентная ошибка (MAPE) составляет чуть менее 10%. Такая точность позволяет уверенно опираться на прогнозы модели при принятии решений на основе данных.
Для дополнительной стабильности модель использует критерий «достоверности», основанный на трёх факторах:
- Узкий доверительный интервал прогноза — модель уверена в результате
- Достаточное количество подписок и выручки в тесте
- С момента начала теста прошло не менее 2 недель
Прогноз считается надёжным, если выполнены хотя бы два из трёх критериев.
Когда запускается новый A/B-тест, модель формирует прогноз годового дохода на 1000 пользователей (основная метрика A/B-теста) для каждого пейвола. Прогнозы отображаются только при соответствии критериям достоверности. Если данных недостаточно, модель выведет сообщение «insufficient data for prediction».
### Ограничения и особенности \{#limitations-and-considerations\}
Несмотря на то что наша прогностическая модель — мощный инструмент, важно учитывать её ограничения.
Качество работы модели зависит от полноты и репрезентативности доступных данных. Нетипичное поведение когорты или новые приложения, не вошедшие в обучающую выборку, могут снизить точность прогнозов.
Тем не менее прогнозы обновляются ежедневно, отражая актуальные данные и поведение пользователей. Это гарантирует, что получаемые вами сведения всегда основаны на самой свежей информации.
:::warning
🚧 Примечание: Этот инструмент дополняет, но не заменяет ваши профессиональные суждения и понимание уникальной динамики вашего приложения. Используйте эти прогнозы как ориентир наряду с другими метриками и знанием рынка для принятия взвешенных решений.
:::
---
# File: adapty-ads-manager
---
---
title: "Adapty Ads Manager"
description: "Получайте аналитику в реальном времени из Apple Ads и управляйте своими кампаниями и оптимизируйте их"
---
**Adapty Ads Manager** — это комплексная платформа для управления, оптимизации и масштабирования ваших кампаний Apple Ads. Она связывает данные о эффективности Apple Search Ads с ключевыми метриками дохода — установками, триалами, подписками и пожизненной ценностью пользователя — без необходимости подключать MMP.
Благодаря аналитике в реальном времени, AI-прогнозам и умной автоматизации Adapty Ads Manager избавляет вас от утомительной ручной корректировки ставок, таблиц и догадок, заменяя их понятными инсайтами и инструментами для быстрых решений.
С Adapty Ads Manager вы получаете:
- **[Обзор](ads-manager-overview)**: Все ключевые метрики на одном экране — расходы, выручка, ROAS, CPA и другие — каждая с графиком динамики по дням
- **[AI-агент](ads-manager-ai-agent)**: Задавайте вопросы на естественном языке и получайте ответы и рекомендации по всей воронке
- **Данные о производительности в реальном времени**: По кампаниям, группам объявлений и ключевым словам
- **Сквозное отслеживание выручки**: От поиска → установки → пробного периода → подписки → LTV
- **Прогнозы и рекомендации AI**: Для прибыльного масштабирования
- **Массовое управление**: Ставками, бюджетами, статусами и структурой
- **[Автоматизации на основе правил](ads-manager-automations)**: Управление полным жизненным циклом ключевых слов
- **[Рыночная аналитика](ads-manager-market-intelligence)**: Стратегии конкурентов по ключевым словам в более чем 50 странах
- **[CPP A/B-тесты](ads-manager-cpp-ab-tests)**: Сравнивайте кастомные страницы продукта друг с другом и находите лучшую
## Шаг 2. Подключите рекламную платформу и добавьте ссылки для отслеживания \{#step-2-connect-your-ad-platform-and-add-tracking-links\}
Adapty использует ссылки для отслеживания, чтобы связать установки приложения с данными кампаний.
Ссылку для отслеживания нужно использовать в качестве целевого URL в каждой рекламной кампании, результаты которой вы хотите измерять в Adapty Attribution.
Если вы размещаете рекламу на нескольких платформах, настройте ссылки для отслеживания для каждой платформы отдельно.
Adapty работает с рекламными платформами двумя способами:
- **Нативные интеграции (Meta Ads, TikTok Ads).** Adapty подключается напрямую к рекламной платформе. Трекинговые ссылки создаются автоматически, а параметры кампании заполняются динамически в зависимости от того, где используется ссылка. Одну и ту же ссылку можно использовать в разных кампаниях, группах объявлений или креативах — Adapty автоматически получит актуальные данные о кампании и расходах на рекламу.
- **Только трекинговые ссылки (все остальные рекламные платформы).** Adapty не подключается к рекламной платформе напрямую. Трекинговые ссылки создаются вручную, и все параметры кампании нужно задавать явно при создании ссылки. Данные о расходах на рекламу для этих платформ недоступны.
3. В редакторе политик вставьте следующий JSON и замените `adapty-s3-integration-test` на имя вашего бакета:
```json showLineNumbers title="Json"
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListObjectsInBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::adapty-s3-integration-test"
},
{
"Sid": "AllowAllObjectActions",
"Effect": "Allow",
"Action": "s3:*Object",
"Resource": [
"arn:aws:s3:::adapty-s3-integration-test/*",
"arn:aws:s3:::adapty-s3-integration-test"
]
},
{
"Sid": "AllowBucketLocation",
"Effect": "Allow",
"Action": "s3:GetBucketLocation",
"Resource": "arn:aws:s3:::adapty-s3-integration-test"
}
]
}
```
4. После завершения настройки политики вы можете добавить теги (по желанию), а затем нажмите **Next**, чтобы перейти к последнему шагу
5. На этом шаге укажите название политики и нажмите **Create policy**, чтобы завершить её создание
#### 1.2. Создайте пользователя IAM \{#12-create-iam-user\}
Чтобы Adapty Attribution мог загружать отчёты с сырыми данными в ваш бакет, вам нужно предоставить Access Key ID и Secret Access Key пользователя с правом записи в этот бакет.
1. Перейдите в консоль IAM и откройте [раздел Users](https://console.aws.amazon.com/iamv2/home#/users)
2. Нажмите кнопку **Add users**
3. Задайте имя пользователя, выберите **Access key – Programmatic access** и перейдите к настройке прав доступа
4. На следующем шаге выберите опцию **Add user to group**, затем нажмите кнопку **Create group**
5. Затем нужно задать имя для вашей группы пользователей и выбрать политику, которую вы создали ранее
6. После выбора политики нажмите кнопку **Create group**, чтобы завершить процесс
7. После успешного создания группы **выберите её** и перейдите к следующему шагу
8. Это последний шаг данного раздела — просто нажмите кнопку **Create User**
9. Наконец, вы можете **скачать учётные данные в формате .csv** или скопировать их напрямую из дашборда
### Шаг 2. Настройка интеграции в Adapty Attribution
1. Перейдите в [**Integrations** -> **Amazon S3**](https://app.adapty.io/ua/integrations/s3)
2. Включите переключатель **Export install events to Amazon S3**.
3. Заполните следующие поля, чтобы установить связь между Amazon S3 и профилями Adapty Attribution:
| Поле | Описание |
|:-----------------------------| :----------------------------------------------------------- |
| **Access Key ID** | Уникальный идентификатор для аутентификации пользователя или приложения при доступе к сервису AWS. Найдите этот идентификатор в скачанном [csv-файле](ua-amazon-s3#step-1-create-amazon-s3-credentials). |
| **Secret Access Key** | Приватный ключ, используемый вместе с Access Key ID для аутентификации при доступе к сервису AWS. Найдите этот ключ в скачанном [csv-файле](ua-amazon-s3#step-1-create-amazon-s3-credentials). |
| **S3 Bucket Name** | Глобально уникальное имя, идентифицирующее конкретный бакет S3 в облаке AWS. Бакеты S3 — это простое хранилище, позволяющее загружать и получать объекты данных (файлы, изображения и т. д.) в облаке. |
| **Folder Inside the Bucker** | Имя папки, которую вы хотите создать внутри выбранного бакета S3. Обратите внимание, что S3 эмулирует папки с помощью префиксов ключей объектов, которые по сути и являются именами папок. |
| **Region** (опционально) | Узнайте ваш регион в консоли управления AWS в разделе вашего IAM-аккаунта. |
## Ручной экспорт данных \{#manual-data-export\}
Помимо автоматического экспорта данных о событиях в Amazon S3, Adapty UA поддерживает и ручной экспорт файлов. С его помощью вы можете выбрать конкретную дату для данных по привлечению пользователей и экспортировать их в свой бакет S3 вручную. Это даёт больше контроля над тем, какие данные и когда экспортировать.
## Структура таблицы \{#table-structure\}
В интеграции с AWS S3 Adapty Attribution предоставляет таблицу для хранения исторических данных о событиях установки. Таблица содержит информацию о профиле пользователя, выручке и доходах, источнике стора и других параметрах.
:::warning
Обратите внимание, что эта структура может со временем расширяться — мы или наши партнёры можем добавлять новые данные. Убедитесь, что ваш код, обрабатывающий эти данные, достаточно устойчив и опирается на конкретные поля, а не на структуру в целом.
:::
Вот структура таблицы для событий:
| Столбец | Описание |
|--------------------------|---------------------------------------------------|
| `adapty_profile_id` | Уникальный идентификатор профиля Adapty |
| `install_id` | Уникальный идентификатор установки |
| `created_at` | Временная метка создания записи (ISO 8601) |
| `installed_at` | Временная метка установки приложения (ISO 8601) |
| `store` | Стор (`ios`, `android`) |
| `country` | Код страны пользователя (ISO 3166-1 alpha-2) |
| `ip_address` | IP-адрес клиента |
| `idfa` | iOS Identifier for Advertisers |
| `idfv` | iOS Identifier for Vendors |
| `gaid` | Google Advertising ID (Android) |
| `android_id` | ID устройства Android |
| `app_set_id` | Android App Set ID |
| `channel` | Канал атрибуции |
| `campaign_id` | Идентификатор кампании |
| `campaign_name` | Название кампании |
| `adset_id` | Идентификатор группы объявлений |
| `adset_name` | Название группы объявлений |
| `ad_id` | Идентификатор объявления |
| `ad_name` | Название объявления |
| `keyword_id` | Идентификатор ключевого слова |
| `keyword_name` | Ключевое слово |
| `asa_org_id` | ID организации Apple Search Ads |
| `asa_keyword_match_type` | Тип соответствия ключевого слова ASA (`Exact`, `Broad`) |
| `asa_attribution` | Данные атрибуции ASA (строка JSON) |
| `asa_conversion_type` | Тип конверсии ASA |
| `asa_country_or_region` | Страна или регион ASA |
| `asa_creative_set_name` | Название набора креативов ASA |
| `fbclid` | Facebook Click ID |
| `ttclid` | TikTok Click ID |
| `utm_source` | Параметр UTM source |
| `utm_medium` | Параметр UTM medium |
| `utm_campaign` | Параметр UTM campaign |
| `utm_term` | Параметр UTM term |
| `utm_content` | Параметр UTM content |
---
# File: ua-google-cloud-storage
---
---
title: "Google Cloud Storage в Adapty Attribution"
description: "Интегрируйте Google Cloud Storage с Adapty Attribution для безопасного хранения данных по привлечению пользователей."
---
Интеграция Adapty Attribution с Google Cloud Storage позволяет безопасно хранить данные кампаний по привлечению пользователей в одном централизованном месте. Вы сможете сохранять данные об эффективности кампаний, данные атрибуции и события привлечения пользователей в своём бакете Google Cloud Storage в виде файлов .csv.
Чтобы настроить интеграцию, нужно выполнить несколько простых шагов в Google Cloud Console и дашборде Adapty Attribution.
:::note
Расписание
Adapty Attribution отправляет данные в Google Cloud Storage каждые 24 часа в 4:00 UTC.
Каждый файл содержит данные о событиях, созданных за весь предыдущий календарный день по UTC. Например, данные, экспортируемые автоматически в 4:00 UTC 8 марта, будут содержать все события, созданные 7 марта с 00:00:00 до 23:59:59 по UTC.
:::
## Как настроить интеграцию с Google Cloud Storage \{#how-to-set-up-google-cloud-storage-integration\}
### Шаг 1. Создание учётных данных Google Cloud Storage \{#step-1-create-google-cloud-storage-credentials\}
Этот гайд поможет вам создать необходимые учётные данные в Google Cloud Platform Console.
Чтобы Adapty Attribution мог загружать отчёты с сырыми данными в ваш бакет, требуется ключ сервисного аккаунта и права на запись в соответствующий бакет. Предоставив ключ сервисного аккаунта и разрешив запись в бакет, вы позволяете Adapty Attribution безопасно и эффективно передавать отчёты с сырыми данными из платформы в ваше хранилище.
:::warning
Обратите внимание, что мы поддерживаем только авторизацию через Service Account HMAC key. Убедитесь, что вашему Service Account HMAC key добавлены роли «Storage Object Viewer», «Storage Legacy Bucket Writer» и «Storage Object Creator» — это необходимо для корректного доступа к Google Cloud Storage.
:::
#### 2.1. Создайте сервисный аккаунт \{#21-create-service-account\}
1. Перейдите в раздел [IAM](https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts) вашего аккаунта Google Cloud и выберите нужный проект или создайте новый
2. Затем создайте новый сервисный аккаунт для атрибуции Adapty, нажав кнопку **+ CREATE SERVICE ACCOUNT**
3. Заполните поля на первом шаге — права доступа будут назначены позже. Подробнее об этой странице читайте в документации [здесь](https://docs.cloud.google.com/iam/docs/service-accounts-create)
4. Чтобы создать и скачать [приватный JSON-ключ](https://docs.cloud.google.com/iam/docs/keys-create-delete), перейдите в раздел KEYS и нажмите кнопку «ADD KEY»
5. В разделе DETAILS найдите значение Email, привязанное к только что созданному сервисному аккаунту, и скопируйте его. Эта информация понадобится на следующих шагах для авторизации аккаунта и предоставления ему прав на запись в бакет
#### 2.2. Настройка прав доступа к бакету \{#22-configure-bucket-permissions\}
6. Перейдите на страницу [Buckets](https://console.cloud.google.com/storage/browser) в Google Cloud Storage и выберите существующий бакет или создайте новый для хранения отчётов об атрибуции из Adapty Attribution
7. Перейдите в раздел PERMISSIONS и выберите опцию [GRANT ACCESS](https://docs.cloud.google.com/identity/docs/how-to?hl=en)
8. В разделе PERMISSIONS введите Email сервисного аккаунта, полученный на пятом шаге, затем выберите роль Storage Object Creator
9. Нажмите SAVE, чтобы сохранить изменения
10. Запомните название бакета для дальнейшего использования
11. После выполнения этих шагов вы успешно завершили необходимую настройку в Google Cloud Console! Последний шаг — ввести название бакета и скачать JSON-файл для использования в атрибуции Adapty
### Шаг 2. Настройте интеграцию в Adapty Attribution \{#step-2-configure-integration-in-adapty-attribution\}
1. Перейдите в [**Integrations** -> **Google Cloud Storage**](https://app.adapty.io/ua/integrations/google-cloud-storage)
2. Включите переключатель **Export install events to Google Cloud Storage**
3. Заполните обязательные поля для настройки соединения между Google Cloud Storage и Adapty Attribution:
| Поле | Описание |
|:------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Google Cloud service account key file** | Скачанный приватный [JSON-файл ключа](ua-google-cloud-storage#step-1-create-google-cloud-storage-credentials). |
| **Google Cloud bucket name** | Название бакета в Google Cloud Storage, в котором вы хотите хранить данные. Оно должно быть уникальным в рамках Google Cloud Storage и не должно содержать пробелов. |
| **Folder inside the bucket** | Название папки внутри бакета, в которой вы хотите хранить данные. Оно должно быть уникальным в рамках бакета и может использоваться для организации данных. Это поле необязательно для заполнения. |
## Ручной экспорт данных \{#manual-data-export\}
Помимо автоматического экспорта событий в Google Cloud Storage, Adapty UA поддерживает ручной экспорт файлов. С его помощью можно выбрать конкретную дату и вручную экспортировать данные по привлечению пользователей в бакет GCS. Это даёт больше контроля над тем, какие данные и когда экспортировать.
## Структура таблицы \{#table-structure\}
В интеграции с Google Cloud Storage Adapty Attribution предоставляет таблицу для хранения исторических данных о событиях установки. Таблица содержит информацию о профиле пользователя, выручке и доходах, источнике стора и другие данные.
:::warning
Обратите внимание, что эта структура может расширяться со временем — по мере добавления новых данных с нашей стороны или со стороны третьих лиц, с которыми мы работаем. Убедитесь, что ваш код, обрабатывающий эти данные, достаточно устойчив и опирается на конкретные поля, а не на структуру в целом.
:::
Ниже представлена структура таблицы для событий:
| Столбец | Описание |
|--------------------------|----------------------------------------------------|
| `adapty_profile_id` | Уникальный идентификатор профиля Adapty |
| `install_id` | Уникальный идентификатор установки |
| `created_at` | Временная метка создания записи (ISO 8601) |
| `installed_at` | Временная метка установки приложения (ISO 8601) |
| `store` | Стор (`ios`, `android`) |
| `country` | Код страны пользователя (ISO 3166-1 alpha-2) |
| `ip_address` | IP-адрес клиента |
| `idfa` | iOS Identifier for Advertisers |
| `idfv` | iOS Identifier for Vendors |
| `gaid` | Google Advertising ID (Android) |
| `android_id` | Идентификатор устройства Android |
| `app_set_id` | Android App Set ID |
| `channel` | Канал атрибуции |
| `campaign_id` | Идентификатор кампании |
| `campaign_name` | Название кампании |
| `adset_id` | Идентификатор группы объявлений |
| `adset_name` | Название группы объявлений |
| `ad_id` | Идентификатор объявления |
| `ad_name` | Название объявления |
| `keyword_id` | Идентификатор ключевого слова |
| `keyword_name` | Название ключевого слова |
| `asa_org_id` | Идентификатор организации Apple Search Ads |
| `asa_keyword_match_type` | Тип соответствия ключевого слова ASA (`Exact`, `Broad`) |
| `asa_attribution` | Данные атрибуции ASA (строка JSON) |
| `asa_conversion_type` | Тип конверсии ASA |
| `asa_country_or_region` | Страна или регион ASA |
| `asa_creative_set_name` | Название набора креативов ASA |
| `fbclid` | Facebook Click ID |
| `ttclid` | TikTok Click ID |
| `utm_source` | Параметр UTM source |
| `utm_medium` | Параметр UTM medium |
| `utm_campaign` | Параметр UTM campaign |
| `utm_term` | Параметр UTM term |
| `utm_content` | Параметр UTM content |
---
# File: adapty-mail
---
---
title: "Adapty Mail"
description: "Создаваемые с помощью ИИ email-кампании, которые превращают пользователей пробного периода в платных подписчиков."
---
Для каждой интеграции доступны следующие параметры конфигурации, которые влияют на все отправляемые через неё события:
| Параметр | Описание |
|:--------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Reporting Proceeds** | Выберите, как отображать значения выручки: за вычетом комиссий App Store и Play Store или до их удержания. Установите флажок «Send sales as proceeds», чтобы показывать продажи уже после вычета комиссий. |
| **Send Trial Price** | Если флажок установлен, Adapty будет передавать цену подписки для события Trial Started. |
| **Exclude Historical Events** | Позволяет исключить события, произошедшие до того, как пользователь установил приложение с Adapty SDK. Это предотвращает дублирование событий и обеспечивает точность отчётов. Например, если пользователь оформил ежемесячную подписку 10 января, а обновил приложение с Adapty SDK 6 марта, Adapty пропустит все события до 6 марта и сохранит последующие. |
| **Report User's Currency** | Выберите, в какой валюте отображать продажи: в валюте пользователя или в USD. |
| **Send User Attributes** | Если вы хотите передавать атрибуты пользователя (например, языковые настройки) и ваш тарифный план OneSignal поддерживает более 10 тегов, включите этот параметр. Он позволяет передавать дополнительные данные сверх стандартных 10 тегов. Обратите внимание: превышение лимита тегов может привести к ошибкам. |
| **Send Attributions** | Включите этот параметр, чтобы передавать информацию об атрибуции (например, атрибуцию AppsFlyer) и получать соответствующие данные. |
| **Send Play Store purchase token** | Включите этот параметр, чтобы получать токен покупки Play Store, необходимый для повторной валидации покупки. В событие будет добавлен параметр `play_store_purchase_token`. |
| **Delay events with future datetime** | **Только для AppsFlyer и пользовательских вебхуков**: при включении события продления и конверсии пробного периода отправляются в дату их фактического наступления. При отключении (по умолчанию) эти события отправляются сразу при обнаружении, даже если их дата ещё не наступила. |
| **Data residency** | **Только для Mixpanel и Amplitude**: выберите регион хранения данных, чтобы определить, где будут обрабатываться и храниться ваши события. |
## Настройка событий \{#configure-the-events\}
Ниже раздела с учётными данными находятся три группы событий, которые можно отправлять в выбранную интеграцию из Adapty. Включите те, которые вам нужны.
Обратите внимание: в одних интеграциях названия событий можно изменять, в других они фиксированы и не редактируются. Кроме того, в некоторых интеграциях — например, в [Airbridge](airbridge#configure-events-and-tags) — одному событию Adapty можно сопоставить несколько названий. Полный список событий Adapty смотрите [здесь](events).
Мы рекомендуем использовать стандартные названия событий Adapty, однако вы можете изменить их под свои нужды.
---
# File: events
---
---
title: "События для отправки в сторонние интеграции"
description: "Отслеживайте ключевые события подписок с помощью аналитических инструментов Adapty."
---
Apple и Google отправляют события подписок напрямую на серверы через [App Store Server Notifications](enable-app-store-server-notifications) и [Real-time Developer Notifications (RTDN)](enable-real-time-developer-notifications-rtdn). Из-за этого мобильные приложения не могут надёжно отправлять события в аналитические системы в реальном времени. Например, если пользователь оформил подписку, но больше не открывал приложение, разработчик не получит никаких обновлений о статусе подписки без сервера.
Adapty решает эту проблему: собирает данные о подписках и преобразует их в понятные человеку события. Эти события для интеграций отправляются в формате JSON. Все события имеют одинаковую структуру, но набор полей зависит от типа события, стора и конкретных настроек. Точный список полей для каждого события можно найти на страницах соответствующих интеграций.
Чтобы понять, было ли событие успешно обработано или что-то пошло не так, ознакомьтесь со страницей [Статусы событий](event-statuses).
## Типы событий \{#event-types\}
Большинство событий создаются и отправляются во все настроенные интеграции, если они включены. Однако событие **Access level updated** срабатывает только в том случае, если настроена [интеграция с вебхуком](webhook) и это событие включено. Оно будет отображаться в [Event Feed](https://app.adapty.io/event-feed) и отправляться в вебхук, но не будет передаваться в другие интеграции.
Если интеграция с вебхуком не настроена или данный тип события не включён, событие **Access level updated** не будет создаваться и не появится в [Event Feed](https://app.adapty.io/event-feed).
| Event name | Description |
|:-----------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| subscription_started | Срабатывает, когда пользователь активирует платную подписку без пробного периода, то есть с него сразу списывается оплата. |
| subscription_renewed | Происходит при продлении подписки и списании оплаты с пользователя. Это событие фиксируется начиная со второго платежа — как для пробных, так и для обычных подписок. |
| subscription_renewal_cancelled | Пользователь отключил автопродление подписки. Доступ к премиум-функциям сохраняется до конца оплаченного периода. |
| subscription_renewal_reactivated | Срабатывает, когда пользователь повторно включает автопродление подписки. |
| subscription_expired | Срабатывает, когда подписка полностью завершается после отмены. Например, если пользователь отменил подписку 12 декабря, но она активна до 31 декабря, событие фиксируется 31 декабря, когда подписка истекает. |
| subscription_paused | Происходит, когда пользователь активирует [паузу подписки](https://developer.android.com/google/play/billing/lifecycle/subscriptions#pause) (только Android). |
| subscription_deferred | Срабатывает, когда покупка подписки [откладывается](https://adapty.io/glossary/subscription-purchase-deferral/), — пользователь может перенести платёж, сохраняя доступ к премиум-функциям. Функция доступна через Google Play Developer API и может использоваться для пробных периодов или в поддержку пользователей, испытывающих финансовые трудности. |
| non_subscription_purchase | Любая покупка без подписки: пожизненный доступ или расходуемые покупки, например внутриигровые монеты. |
| trial_started | Срабатывает, когда пользователь активирует пробную подписку. |
| trial_converted | Происходит, когда пробный период заканчивается и с пользователя списывается первый платёж. Например, если пробный период действует до 14 января, но оплата проходит 7 января, событие фиксируется 7 января. |
| trial_renewal_cancelled | Пользователь отключил автопродление подписки в течение пробного периода. Доступ к премиум-функциям сохраняется до конца пробного периода, но оплата не будет списана и подписка не активируется. |
| trial_renewal_reactivated | Происходит, когда пользователь повторно включает автопродление подписки в течение пробного периода. |
| trial_expired | Срабатывает, когда пробный период заканчивается без перехода в подписку. |
| entered_grace_period | Происходит, когда попытка оплаты завершается неудачей и пользователь переходит в льготный период (если он включён). В течение этого времени доступ к премиум-функциям сохраняется. |
| billing_issue_detected | Срабатывает при возникновении проблемы с оплатой во время попытки списания (например, недостаточно средств на карте). |
| subscription_refunded | Срабатывает при возврате средств за подписку (например, через службу поддержки Apple). |
| non_subscription_purchase_refunded | Срабатывает при возврате средств за покупку без подписки. |
| access_level_updated | Происходит при обновлении уровня доступа пользователя. |
Перечисленные выше события полностью описывают состояние пользователей с точки зрения покупок. Рассмотрим несколько примеров.
### Пример 1 \{#example-1\}
_Пользователь активировал месячную подписку 1 апреля с 7-дневным пробным периодом. На 4-й день он отменил подписку._
В этом случае будут отправлены следующие события:
1. `trial_started` 1 апреля
2. `trial_renewal_cancelled` 4 апреля
3. `trial_expired` 7 апреля
### Пример 2 \{#example-2\}
_Пользователь активировал месячную подписку 1 апреля с 7-дневным пробным периодом. На 10-й день он отменил подписку._
В этом случае будут отправлены следующие события:
1. `trial_started` 1 апреля
2. `trial_converted` 7 апреля
3. `subscription_renewal_cancelled` 10 апреля
4. `subscription_expired` 1 мая
Подробное описание того, какие события срабатывают в каждом сценарии, можно найти в разделе [Потоки событий](event-flows).
---
# File: event-flows
---
---
title: "Потоки событий"
description: "Изучите подробные схемы потоков событий подписки в Adapty. Узнайте, как генерируются и отправляются события подписок в интеграции, помогая отслеживать ключевые моменты в путях ваших клиентов."
---
В Adapty вы будете получать различные события подписки на протяжении всего пути клиента в вашем приложении. Описанные ниже сценарии помогут понять, какие события генерирует Adapty, когда пользователи оформляют, отменяют или возобновляют подписку.
Обратите внимание, что Apple обрабатывает платежи за подписку за несколько часов до фактического начала/продления. В приведённых ниже схемах начало/продление подписки и списание средств показаны одновременно — для наглядности.
Кроме того, события, связанные с одним действием, происходят одновременно и могут появляться в вашем **Event Feed** в произвольном порядке, который может отличаться от последовательности, показанной на наших диаграммах.
## Жизненный цикл подписки \{#subscription-lifecycle\}
### Процесс первой покупки \{#initial-purchase-flow\}
Этот процесс происходит, когда пользователь впервые оформляет подписку без пробного периода. В этом случае создаются следующие события:
- **Subscription started**
- **Access level updated** — для предоставления доступа пользователю
Когда наступает дата продления подписки, подписка обновляется. При этом создаются следующие события:
- **Subscription renewal** — для начала нового периода подписки
- **Access level updated** — для обновления даты истечения подписки и продления доступа ещё на один период
Ситуации, когда оплата не проходит или пользователь отменяет продление, описаны в [Billing Issue Outcome Flow](event-flows#billing-issue-outcome-flow) и [Subscription Cancellation Flow](event-flows#subscription-cancellation-flow) соответственно.
### Процесс отмены подписки \{#subscription-cancellation-flow\}
Когда пользователь отменяет подписку, создаются следующие события:
- **Subscription renewal canceled** — указывает, что подписка остаётся активной до конца текущего периода, после чего пользователь потеряет доступ
- **Access level updated** — создаётся для отключения автопродления для уровня доступа
Когда подписка заканчивается, срабатывает событие **Subscription expired (churned)**, фиксирующее окончание подписки.
Если возврат средств одобрен, следующее событие заменяет **Subscription expired (churned)**:
- **Subscription refunded** — завершает подписку и предоставляет информацию о возврате средств
В Stripe подписку можно отменить немедленно, минуя оставшийся период. В этом случае все события создаются одновременно:
- **Subscription renewal cancelled**
- **Subscription expired (churned)**
- **Access Level updated** — для снятия доступа у пользователя
Если возврат одобрен, при его подтверждении также срабатывает событие **Subscription refunded**.
### Процесс реактивации подписки \{#subscription-reactivation-flow\}
Если пользователь отменяет подписку, она истекает, а затем он снова покупает ту же подписку, будет создано событие **Subscription renewed**. Даже если в доступе был перерыв, Adapty рассматривает это как единую цепочку транзакций, связанных через `vendor_original_transaction_id`. Поэтому повторная покупка считается продлением.
Событие **Access level updated** будет создано дважды:
- в момент окончания подписки — чтобы отозвать доступ у пользователя
- в момент повторной покупки подписки — чтобы предоставить доступ
### Поток паузы подписки (только Android) \{#subscription-pause-flow-android-only\}
Этот поток применяется, когда пользователь ставит подписку на паузу, а затем возобновляет её на Android.
Пауза подписки имеет отложенный эффект. Если пользователь ставит подписку на паузу до момента её продления, подписка остаётся активной, и пользователь сохраняет оплаченный доступ до конца расчётного периода.
1. Когда пользователь ставит подписку на паузу, срабатывает событие **Subscription paused (Android only)**.
2. По окончании периода подписки Adapty инициирует событие **Access level updated**, отзывая доступ пользователя.
3. Когда пользователь возобновляет подписку, срабатывают следующие события:
- **Subscription renewed**
- **Access level updated** — для восстановления доступа пользователя
Эти подписки относятся к одной цепочке транзакций, связанных одним **vendor_original_transaction_id**.
## Триальные сценарии \{#trial-flows\}
Если вы используете триальный период в приложении, вы будете получать дополнительные события, связанные с триалом.
### Пробный период с успешной конверсией \{#trial-with-successful-conversion-flow\}
Самый распространённый сценарий: пользователь начинает пробный период, указывает банковскую карту и по окончании пробного периода успешно переходит на стандартную подписку. В этом случае в момент начала пробного периода создаются следующие события:
- **Trial started** — фиксирует начало пробного периода
- **Access level updated** — предоставляет доступ
Событие **Trial converted** создаётся в момент начала стандартной подписки.
### Пробный период без успешной конвертации \{#trial-without-successful-conversion-flow\}
Если пользователь отменяет пробный период до его конвертации в подписку, в момент отмены создаются следующие события:
- **Trial renewal cancelled** — отключает автоматическую конвертацию пробного периода в подписку
- **Access level updated** — отключает продление доступа
Пользователь сохраняет доступ до окончания пробного периода, после чего создаётся событие **Trial expired**, фиксирующее его завершение.
### Повторная активация подписки после истёкшего триала \{#subscription-reactivation-after-expired-trial-flow\}
Если триал истёк (из-за проблем с оплатой или отмены) и пользователь позже оформляет подписку, создаются следующие события:
- **Access level updated** — открывает пользователю доступ
- **Trial converted**
Даже при наличии разрыва между триалом и подпиской Adapty связывает их через `vendor_original_transaction_id`. Такая конвертация считается частью непрерывной цепочки транзакций, начатой с триала с нулевой ценой. Именно поэтому создаётся событие **Trial converted**, а не **Subscription started**.
## Изменения продукта \{#product-changes\}
Этот раздел охватывает любые изменения активных подписок: апгрейды, даунгрейды или покупку продукта из другой группы.
### Немедленная смена продукта \{#immediate-product-change-flow\}
После того как пользователь меняет продукт, изменение может вступить в силу сразу, не дожидаясь окончания подписки (как правило, при апгрейде или замене продукта). В момент смены продукта происходит следующее:
- Уровень доступа изменяется, и создаются два события **Access level updated**:
1. для отзыва доступа к первому продукту.
2. для предоставления доступа ко второму продукту.
- Старая подписка завершается, и выплачивается возврат средств (создаётся событие **Subscription refunded** с `cancellation_reason` = `upgraded`). Обратите внимание, что событие **Subscription expired (churned)** не создаётся — его заменяет событие **Subscription refunded**.
- Новая подписка запускается (для нового продукта создаётся событие **Subscription started**).
Если пользователь понижает подписку, первая подписка будет действовать до конца оплаченного периода, а когда она завершится — заменится новой подпиской более низкого уровня. В этом случае сразу будет создано только событие **Access level updated**, отключающее автопродление доступа. Все остальные события будут созданы в момент фактической замены подписки:
- Создаётся ещё одно событие **Access level updated** — чтобы предоставить доступ ко второму продукту.
- Создаётся событие **Subscription expired (churned)** — чтобы завершить подписку на первый продукт.
- Создаётся событие **Subscription started** — чтобы начать новую подписку на новый продукт.
### Отложенное изменение продукта \{#delayed-product-change-flow\}
Существует также вариант, когда пользователь меняет продукт в момент обновления подписки. Этот вариант очень похож на предыдущий: одно событие **Access level updated** создаётся сразу, чтобы отключить автообновление для старого продукта. Все остальные события создаются в тот момент, когда пользователь меняет подписку и это изменение фиксируется в системе:
- Создаётся ещё одно событие **Access level updated**, чтобы предоставить доступ ко второму продукту.
- Создаётся событие **Subscription expired (churned)**, чтобы завершить подписку на первый продукт.
- Создаётся событие **Subscription started**, чтобы начать новую подписку на новый продукт.
## Поведение системы при проблемах с оплатой \{#billing-issue-outcome-flow\}
Если попытка конвертировать пробный период или продлить подписку завершается неудачей из-за проблем с оплатой, дальнейшее поведение системы зависит от того, включён ли льготный период.
При наличии льготного периода: если платёж проходит успешно, пробный период конвертируется или подписка продлевается. Если платёж не проходит, стор продолжает попытки списать средства, и если они по-прежнему не удаются — стор самостоятельно завершает пробный период или подписку.
Таким образом, в момент возникновения проблемы с оплатой в Adapty создаются следующие события:
- **Billing issue detected**
- **Entered grace period** (если льготный период включён)
- **Access level updated** для предоставления доступа до конца льготного периода
Если оплата в итоге проходит, Adapty фиксирует событие **Trial converted** или **Subscription renewed**, и пользователь не теряет доступ.
Если оплата так и не проходит и стор отменяет подписку, Adapty генерирует следующие события:
- **Trial expired** или **Subscription expired (churned)** с `cancellation_reason: billing_error`
- **Access level updated** для отзыва доступа пользователя
Без льготного периода период повторных попыток списания (когда стор продолжает пытаться списать средства с пользователя) начинается немедленно.
Если оплата так и не проходит до конца льготного периода, сценарий тот же: стор автоматически завершает подписку и создаёт те же события:
- Событие **Trial expired** или **Subscription expired (churned)** с `cancellation_reason` равным `billing_error`
- **Access level updated** — уровень доступа отзывается у пользователя
## Передача покупок между аккаунтами пользователей \{#sharing-purchases-across-user-accounts-flows\}
Когда
Ниже приведена разбивка полей, связанных с назначением и передачей уровня доступа в событиях, генерируемых в этом сценарии:
- **Пользователь A: Уровень доступа обновлён (отправляется, когда пользователь A оформляет подписку в приложении)**
```json showLineNumbers
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": UserA,
"event_properties": {
"profile_has_access_level": true,
},
"profiles_sharing_access_level": null
}
```
- **Пользователь A: уровень доступа обновлён (отправляется при переустановке приложения и входе пользователя B, что отзывает доступ пользователя A)**
```json showLineNumbers
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": UserA,
"event_properties": {
"profile_has_access_level": false,
},
"profiles_sharing_access_level": null
}
```
- **Пользователь B: уровень доступа обновлён (отправляется, когда пользователь B входит в систему и доступ предоставляется)**
```json showLineNumbers
{
"profile_id": "00000000-0000-0000-0000-000000000001",
"customer_user_id": UserB,
"event_properties": {
"profile_has_access_level": true,
},
"profiles_sharing_access_level": null
}
```
### Совместный доступ нескольких пользователей \{#shared-access-between-users-flow\}
Этот вариант позволяет нескольким пользователям совместно использовать один уровень доступа, если их устройство привязано к одному Apple/Google ID. Это удобно, когда пользователь переустанавливает приложение и входит с другим email — он всё равно сохраняет доступ к предыдущей покупке. При этом несколько идентифицированных пользователей могут совместно использовать один уровень доступа. Пока уровень доступа является общим, все транзакции записываются под исходным
Вот описание полей, связанных с назначением и передачей уровня доступа в событиях, генерируемых в этом сценарии:
**Пользователь B: Access level updated (отправляется при входе пользователя B и предоставлении доступа)**
```json showLineNumbers
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": UserA,
"event_properties": {
"profile_has_access_level": true,
},
"profiles_sharing_access_level": [
{
"profile_id": "00000000-0000-0000-0000-000000000001,
"customer_user_id": UserB
}
]
}
```
### Поток «Доступ не передаётся между пользователями» \{#access-not-shared-between-users-flow\}
При этом варианте уровень доступа навсегда закрепляется только за первым профилем пользователя, который его получил. Это идеальное решение, если покупки нужно привязать к одному
---
# File: event-statuses
---
---
title: "Статусы событий интеграций"
description: ""
---
Adapty определяет доставляемость по HTTP-коду ответа: любой код вне диапазона `200-399` считается ошибкой.
Вы можете отслеживать статусы событий интеграций в **Event List** в дашборде Adapty. Система отображает статусы для всех включённых интеграций, независимо от того, включён ли конкретный тип события для данной интеграции.
- Чёрный: событие успешно отправлено.
- Серый: тип события отключён для этой интеграции.
- Красный: с интеграцией возникла проблема, требующая внимания.
Чтобы узнать подробности о неуспешных событиях, наведите курсор на название интеграции — появится подсказка с информацией об ошибке.
**Event Feed** отображает данные за последние две недели для оптимизации производительности. Это ограничение ускоряет загрузку страницы, упрощая навигацию и анализ событий.
---
# File: adjust
---
---
title: "Adjust"
description: "Подключите Adjust к Adapty для улучшенного отслеживания подписок и аналитики."
---
[Adjust](https://www.adjust.com/) — одна из ведущих платформ Mobile Measurement Partner (MMP), которая собирает и представляет данные маркетинговых кампаний. Это помогает компаниям отслеживать эффективность своих кампаний.
Adapty предоставляет полный набор данных, позволяющий отслеживать [события подписки](events) из сторов в одном месте. С Adapty вы легко увидите, как ведут себя ваши подписчики, узнаете, что им нравится, и сможете общаться с ними точечно и эффективно. Данная интеграция позволяет отслеживать события подписки в Adjust и точно анализировать, какой доход приносят ваши кампании.
Интеграция между Adapty и Adjust работает двумя основными способами.
1. **Adapty получает данные атрибуции от Adjust**
После настройки интеграции с Adjust Adapty начнёт получать данные атрибуции от Adjust. Вы можете легко просматривать эти данные на странице профиля пользователя.
2. **Adapty отправляет события подписки в Adjust**
Adapty может отправлять все события подписки, настроенные в вашей интеграции, в Adjust. Благодаря этому вы сможете отслеживать эти события в дашборде Adjust. Интеграция полезна для оценки эффективности рекламных кампаний.
## Настройка интеграции \{#set-up-integration\}
### Подключение Adapty к Adjust \{#connect-adapty-to-adjust\}
1. Откройте дашборд Adapty и перейдите в раздел [Integrations > Adjust](https://app.adapty.io/integrations/adjust).
2. Включите переключатель в верхней части страницы.
3. Заполните поля и укажите учётные данные для доступа.
3. Если вы включили OAuth-авторизацию на платформе Adjust, при интеграции для iOS и Android приложений необходимо указать **OAuth Token**.
4. Далее укажите **токены приложений** для iOS и Android. Откройте дашборд Adjust — там вы увидите свои приложения.
:::note
У вас могут быть разные приложения Adjust для iOS и Android, поэтому в Adapty есть два независимых раздела для этого. Если у вас только одно приложение Adjust, просто введите одинаковую информацию в оба поля.
:::
5. Выберите приложение из списка и скопируйте **App Token**. Вставьте токен в соответствующее поле на дашборде Adapty.
### Настройка событий и тегов \{#configure-events-and-tags\}
Adjust работает немного иначе, чем другие платформы. Вам нужно вручную создать события в дашборде Adjust, получить токены событий и скопировать их в соответствующие события в Adapty.
Поэтому первый шаг — найти токены событий для всех событий, которые вы хотите отправлять через Adapty. Для этого:
1. В дашборде Adjust откройте ваше приложение и перейдите на вкладку **Events**.
1. Скопируйте токен события и вставьте его в Adapty. Ниже учётных данных находятся три группы событий, которые можно отправлять из Adapty в Adjust. Полный список событий, доступных в Adapty, смотрите [здесь](events).
Adapty будет отправлять события подписок в Adjust через серверную интеграцию, что позволит вам видеть все события подписок в дашборде Adjust и связывать их с вашими рекламными кампаниями.
:::important
Учтите следующее:
- Adjust не поддерживает события старше 58 дней. Если событие старше 58 дней, Adapty всё равно отправит его в Adjust, но дата и время события будут заменены текущей меткой времени.
- Adjust не поддерживает IPv6. Если вы отключите сбор IP-адресов в SDK в разделе **App settings** или при активации SDK, на сервер может быть отправлен только IPv6, и отслеживание может не работать — оставьте сбор IP-адресов в SDK включённым, чтобы гарантировать использование IPv4.
:::
### Подключите приложение к Adjust \{#connect-your-app-to-adjust\}
После выполнения описанных выше шагов добавьте в своё приложение два следующих метода. Они обеспечат взаимодействие между вашим приложением и Adjust:
1. **Для отправки данных о подписках в Adjust**: передайте идентификатор устройства Adjust в метод SDK `setIntegrationIdentifier()`
2. **Для получения данных атрибуции от Adjust**: обновите данные атрибуции с помощью метода SDK `updateAttribution()`
Для Adjust версии 5.0 и выше используйте следующий пример:
Оба значения можно найти в вашем дашборде Airbridge в разделе [Third-party Integrations > Adapty](https://app.airbridge.io/app/testad/integrations/third-party/adapty).
Поле Adapty API token уже заполнено — значение генерируется на бэкенде Adapty. Скопируйте его и вставьте в дашборд Airbridge в поле Adapty Authorization Token.
### Настройка событий и тегов \{#configure-events-and-tags\}
Ниже учётных данных расположены три группы событий, которые можно отправлять из Adapty в Airbridge.
Просто включите нужные.
### Подключение приложения к Airbridge \{#connect-your-app-to-airbridge\}
Для интеграции нужно передать `airbridge_device_id` в профиль и вызвать `setIntegrationIdentifier`, как показано в примере ниже:
## Настройка интеграции \{#set-up-integration\}
### Подключение Adapty к фреймворку AdServices \{#connect-adapty-to-the-adservices-framework\}
Apple Ads через [AdServices](https://developer.apple.com/documentation/adservices) требует настройки в дашборде Adapty, а также включения на стороне приложения. Чтобы настроить Apple Ads с использованием фреймворка AdServices через Adapty, выполните следующие шаги:
#### Шаг 1: Получите публичный ключ \{#step-1-obtain-public-key\}
В дашборде Adapty перейдите в [Settings -> Apple Ads.](https://app.adapty.io/settings/apple-search-ads)
Найдите заранее сгенерированный публичный ключ (Adapty создаёт пару ключей за вас) и скопируйте его.
:::note
Если вы используете сторонний сервис или собственное решение для атрибуции Apple Ads, вы можете загрузить свой приватный ключ.
:::
#### Шаг 2: Настройте управление пользователями в Apple Ads \{#step-2-configure-user-management-on-apple-ads\}
В вашем [аккаунте Apple Ads](https://ads.apple.com/app-store) перейдите на страницу **Settings > User Management**. Чтобы Adapty мог получать данные атрибуции, нужно пригласить дополнительный Apple ID и предоставить ему доступ API Account Manager. Можно использовать любой доступный вам аккаунт или создать новый специально для этой цели. Главное условие — вы должны иметь возможность войти в Apple Ads под этим Apple ID.
#### Шаг 3: Генерация учётных данных API \{#step-3-generate-api-credentials\}
Войдите в только что добавленный аккаунт в Apple Ads. Перейдите в Settings -> API в интерфейсе Apple Ads. Вставьте ранее скопированный публичный ключ в соответствующее поле. Сгенерируйте новые учётные данные API.
#### Шаг 4: Настройка Adapty с учётными данными Apple Ads \{#step-4-configure-adapty-with-apple-ads-credentials\}
Скопируйте поля Client ID, Team ID и Key ID из настроек Apple Ads. В дашборде Adapty вставьте эти данные в соответствующие поля.
### Подключение приложения к сети AdServices \{#connect-your-app-to-the-adservices-network\}
После завершения [настройки фреймворка AdServices](#connect-the-adservices-framework) Adapty автоматически начинает собирать данные атрибуции Apple Search Ads. Добавлять какой-либо код в SDK не нужно.
Для iOS-приложений эти данные атрибуции **всегда** будут иметь приоритет над данными из других источников. Если такое поведение нежелательно, *отключите* атрибуцию ASA, следуя инструкциям ниже.
## Отключение интеграции \{#disable-integration\}
Чтобы отключить атрибуцию Apple Search Ads, откройте вкладку [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads) и отключите переключатель **Receive Apple Search Ads attribution**.
:::warning
Обратите внимание: отключение этой опции полностью прекратит получение аналитики ASA. В результате ASA больше не будет использоваться в аналитике и не будет передаваться в интеграции. Кроме того, SplitMetrics Acquire и Asapty перестанут работать, поскольку они зависят от атрибуции ASA.
Атрибуция, полученная до этого изменения, затронута не будет.
:::
## Загрузка собственных ключей \{#uploading-your-own-keys\}
:::note
Необязательно
Эти шаги не требуются для атрибуции Apple Ads — только для работы с другими сервисами, например Asapty, или с собственным решением.
:::
Вы можете использовать собственную пару публичного и приватного ключей, если применяете сторонние сервисы или собственное решение для атрибуции ASA.
### Шаг 1 \{#step-1\}
Сгенерируйте приватный ключ в терминале:
```text showLineNumbers title="Text"
openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem
```
Загрузите его в Adapty Settings -> Apple Ads (кнопка Upload private key).
### Шаг 2 \{#step-2\}
Сгенерируйте публичный ключ в терминале:
```text showLineNumbers title="Text"
openssl ec -in private-key.pem -pubout -out public-key.pem
```
Этот публичный ключ можно использовать в настройках Apple Ads аккаунта с ролью API Account Manager. Таким образом, сгенерированные значения Client ID, Team ID и Key ID можно применять как в Adapty, так и в других сервисах.
---
# File: switch-from-appsflyer-s2s-api-2-to-3
---
---
title: "Переход с AppsFlyer S2S API 2 на 3"
description: "Обновите интеграцию с AppsFlyer S2S API 2 до 3 в Adapty."
---
Согласно [официальному бюллетеню AppsFlyer](https://support.appsflyer.com/hc/en-us/articles/20509378973457-Bulletin-Upgrading-the-AppsFlyer-S2S-API), для повышения безопасности и снижения уровня мошенничества AppsFlyer обновил свой server-to-server (S2S) API для внутренних событий приложения. Существующий эндпоинт будет устаревшим в будущем, поэтому рекомендуем заранее спланировать переход.
Adapty поддерживает AppsFlyer S2S API 3 и обеспечивает плавный переход с API 2. Обратите внимание, что переход является односторонним: вернуться к API 2 после смены не получится.
Чтобы перейти с AppsFlyer S2S API 2 на 3:
1. Откройте [сайт AppsFlyer](https://www.appsflyer.com/home) и войдите в аккаунт.
2. Нажмите **Your account name** -> **Security Center** в левом верхнем углу дашборда.
3. В окне **Manage your account security** нажмите кнопку **Manage your AppsFlyer API and S2S tokens**.
4. Если у вас нет S2S-токена, нажмите кнопку **New token**. Если токен уже есть, перейдите к шагу 8.
5. В окне **New token** введите название токена. Оно нужно только для вашего удобства.
6. В списке **Choose type** выберите **S2S**.
7. Не забудьте нажать кнопку **Create new token**, чтобы сохранить новый токен.
8. В окне **Tokens** скопируйте S2S-токен.
9. Откройте [**Integrations** -> **AppsFlyer**](https://app.adapty.io/integrations/appsflyer) в дашборде Adapty.
10. В поле **AppsFlyer S2S API** выберите **API 3**.
11. Вставьте скопированный S2S-ключ в поля **Dev key for iOS** и **Dev key for Android**.
12. Нажмите кнопку **Save**, чтобы подтвердить переход.
После этого интеграция мгновенно переключится на AppsFlyer S2S API 3, и новые события будут отправляться на новый URL: `https://api3.appsflyer.com/inappevent`.
---
# File: asapty
---
---
title: "Asapty"
description: "Узнайте об Asapty и её роли в экосистеме подписок Adapty."
---
С помощью интеграции [Asapty](https://asapty.com/) вы можете оптимизировать кампании в Search Ads. Adapty отправляет события подписок в Asapty, чтобы вы могли строить там собственные дашборды на основе атрибуции Apple Search Ads.
Эта интеграция не добавляет данные атрибуции в Adapty, так как мы уже получаем всё необходимое напрямую из [ASA](apple-search-ads).
## Настройка интеграции \{#set-up-integration\}
### Подключение Adapty к Asapty \{#connect-adapty-to-asapty\}
Чтобы подключить Asapty, перейдите в раздел [Integrations > Asapty](https://app.adapty.io/integrations/asapty) в дашборде Adapty и заполните поле Asapty ID.
Asapty ID можно найти в разделе Settings > General в вашем аккаунте Asapty.
### Настройка событий и тегов \{#configure-events-and-tags\}
Под полем с учётными данными находятся три группы событий, которые можно отправлять в Asapty из Adapty. Просто включите нужные. Полный список событий Adapty доступен [здесь](events).
Рекомендуем использовать стандартные названия событий, предложенные Asapty. При необходимости вы можете изменить их под свои нужды.
### Подключение приложения к Asapty \{#connect-your-app-to-asapty\}
После выполнения описанных выше шагов Adapty автоматически начнёт получать данные атрибуции от Asapty. Явно запрашивать данные атрибуции в коде приложения не нужно. Для повышения точности атрибуции настройте Asapty так, чтобы `customerUserId` передавался вместе с данными каждого события.
## Структура событий Asapty \{#asapty-event-structure\}
Adapty отправляет события в Asapty через GET-запрос с query-параметрами. URL каждого события выглядит так:
```
https://asapty.com/_api/mmpEvents/?source=adapty&asaptyid=a1b2c3d4&keywordid=12345&adgroupid=67890&campaignid=11223&conversiondate=1709294400000&event_name=subscription_renewed&install_time=1709100000&app_name=MyApp&json=%7B%22af_revenue%22%3A%229.99%22%2C%22af_currency%22%3A%22USD%22...%7D
```
Query-параметры:
| Параметр | Тип | Описание |
|:-----------------|:-------|:--------------------------------------------------------------|
| `source` | String | Всегда "adapty". |
| `asaptyid` | String | Asapty ID из ваших учётных данных. |
| `keywordid` | String | Keyword ID в Apple Search Ads (если доступен). |
| `adgroupid` | String | Ad Group ID в Apple Search Ads (если доступен). |
| `campaignid` | String | Campaign ID в Apple Search Ads (если доступен). |
| `conversiondate` | Long | Временная метка события в **миллисекундах**. |
| `event_name` | String | Название события (смаппированное из события Adapty). |
| `install_time` | Long | Временная метка установки в секундах. |
| `app_name` | String | Название приложения из Adapty (если доступно). |
| `json` | String | URL-кодированная JSON-строка с деталями события (см. ниже). |
Параметр `json` — это URL-кодированная JSON-строка со следующими полями:
| Параметр | Тип | Описание |
|:--------------------------|:-------|:-----------------------------------------------------|
| `af_revenue` | String | Сумма дохода в виде строки. |
| `af_currency` | String | Код валюты (например, "USD"). |
| `transaction_id` | String | ID транзакции в сторе. |
| `original_transaction_id` | String | Оригинальный ID транзакции в сторе. |
| `purchase_date` | Long | Временная метка покупки в миллисекундах. |
| `original_purchase_date` | Long | Временная метка оригинальной покупки в миллисекундах.|
| `environment` | String | `Production` или `Sandbox`. |
| `vendor_product_id` | String | ID продукта в сторе. |
| `profile_country` | String | Код страны на основе IP-адреса пользователя. |
| `store_country` | String | Код страны стора пользователя. |
## Устранение неполадок \{#troubleshooting\}
- Убедитесь, что вы настроили [Apple Search Ads](apple-search-ads) в Adapty и [загрузили учётные данные](https://app.adapty.io/settings/apple-search-ads) — без них Asapty работать не будет.
- Только профили с детальной неорганической атрибуцией ASA будут отправлять события в Asapty. Если атрибуция недостаточна, вы увидите сообщение "The user profile is missing the required integration data."
- Профили, созданные до настройки интеграции, не смогут отправлять события в Asapty.
- Если интеграция с Adapty не работает, несмотря на корректную настройку, убедитесь, что переключатель **Receive Apple Search Ads attribution in Adapty** включён на вкладке [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads).
---
# File: branch
---
---
title: "Branch"
description: "Интегрируйте Branch с Adapty для отслеживания диплинков и конверсий приложения."
---
[Branch](https://www.branch.io/) позволяет охватывать пользователей, взаимодействовать с ними и оценивать результаты на разных устройствах, каналах и платформах. Это удобная платформа для роста мобильного дохода с помощью специализированных ссылок, которые работают на всех устройствах, каналах и платформах.
Adapty предоставляет полный набор данных, позволяющий отслеживать [события подписок](events) из сторов в одном месте. С Adapty вы легко увидите, как ведут себя ваши подписчики, поймёте их предпочтения и сможете общаться с ними целенаправленно и эффективно.
Интеграция между Adapty и Branch работает двумя способами.
1. **Получение данных атрибуции из Branch**
После настройки интеграции с Branch Adapty начнёт получать данные атрибуции из Branch. Их можно просмотреть на странице профиля пользователя.
2. **Отправка событий подписки в Branch**
Adapty может отправлять все события подписки, настроенные в вашей интеграции, в Branch. В результате вы сможете отслеживать эти события в дашборде Branch.
## Настройка интеграции \{#set-up-integration\}
### Подключение Adapty к Branch \{#connect-adapty-to-branch\}
Чтобы настроить интеграцию с Branch, перейдите в раздел [Integrations > Branch](https://app.adapty.io/integrations/branch) дашборда Adapty, включите тумблер и заполните поля.
Чтобы получить значение для поля **Branch Key**, откройте [настройки аккаунта](https://dashboard.branch.io/account-settings/profile) Branch и найдите поле **Branch Key**. Используйте его для поля **Key test** (для песочницы) или **Key live** (для Production) в дашборде Adapty. В Branch переключайтесь между окружениями Live и Tests, чтобы получить нужный ключ.
### Настройте события и теги \{#configure-events-and-tags\}
Ниже блока с учётными данными находятся три группы событий, которые можно отправлять в Branch из Adapty. Просто включите нужные. Полный список доступных событий Adapty смотрите [здесь](events).
Вы можете отправлять событие с показателем Proceeds (после вычета комиссии Apple/Google) или просто с выручкой. Также можно включить опцию отчётности в валюте пользователя.
Мы рекомендуем использовать названия событий по умолчанию, предоставленные Adapty. Однако вы можете изменить их под свои нужды.
Adapty будет отправлять события подписок в Branch через серверную интеграцию, позволяя просматривать все события подписок в вашем дашборде Branch и связывать их с вашими рекламными кампаниями.
### Подключите приложение к Branch \{#connect-your-app-to-branch\}
1. Вызовите метод SDK `.setIntegrationIdentifier()`, чтобы инициализировать соединение. Вы можете передать свой Branch Identity ID в параметр `customerUserId`.
:::note
Сторонние SDK генерируют пользовательские ID асинхронно. ID может быть ещё не готов в момент вызова `Adapty.activate()`. Если ваш **Customer User ID** приходит из одного из таких SDK, вызывайте `Adapty.activate()` без него. Как только ID будет получен, вызовите `setIntegrationIdentifier()`, а затем `identify()` с CUID.
:::
1. Чтобы найти App ID, откройте страницу вашего приложения в [App Store Connect](https://appstoreconnect.apple.com/), перейдите на страницу **App Information** в разделе **General** и найдите **Apple ID** в левом нижнем углу экрана.
2. Вам потребуется приложение на платформе [Meta for Developers](https://developers.facebook.com/). Войдите в приложение и откройте расширенные настройки. **App ID** находится в заголовке страницы.
3. Отключите клиентское отслеживание в настройках Meta SDK, чтобы избежать двойного учёта выручки в Meta Ads Manager. Эту настройку можно найти в Meta Developer Console в разделе **App Settings > Advanced Settings**. Установите **Log in-app events automatically** в значение «No». Это гарантирует, что события выручки будут отслеживаться только через интеграцию Adapty.
Для отслеживания событий установки и использования необходимо активировать Meta SDK в коде. Подробности реализации — в документации Meta SDK для вашей платформы:
- [iOS SDK](https://developers.facebook.com/docs/ios/getting-started)
- [Android SDK](https://developers.facebook.com/docs/android/getting-started)
- [Unity SDK](https://developers.facebook.com/docs/unity/getting-started/canvas)
Эту интеграцию можно использовать и с Android-приложениями. Если вы настроили конфигурацию Android SDK в **App Settings**, достаточно указать **Facebook App ID**.
### Настройка событий и тегов \{#configure-events-and-tags\}
Интеграция Facebook Ads предназначена для компаний, использующих Meta для рекламных кампаний и оптимизирующих их на основе поведения пользователей. Она поддерживает стандартные события Meta для целей оптимизации. Поэтому изменение названий событий в интеграции Meta Ads недоступно. Adapty автоматически сопоставляет пользовательские события с соответствующими событиями Meta для точного анализа.
| Событие Adapty | Событие Meta Ads |
| :---------------------------- | :-------------------------- |
| Subscription initial purchase | Subscribe |
| Subscription renewed | Subscribe |
| Subscription cancelled | CancelSubscription |
| Trial started | StartTrial |
| Trial converted | Subscribe |
| Trial cancelled | CancelTrial |
| Non subscription purchase | fb_mobile_purchase |
| Billing issue detected | billing_issue_detected |
| Entered grace period | entered_grace_period |
| Auto renew off | auto_renew_off |
| Auto renew on | auto_renew_on |
| Auto renew off subscription | auto_renew_off_subscription |
| Auto renew on subscription | auto_renew_on_subscription |
StartTrial, Subscribe, CancelSubscription — стандартные события.
Чтобы включить нужные события, просто активируйте их переключателем. Если выбрано несколько названий событий, Adapty объединит данные по всем выбранным событиям в одно событие Adapty.
### Подключение приложения к Facebook Ads \{#connect-your-app-to-facebook-ads\}
Если вы выполнили описанные выше шаги, Facebook будет автоматически получать данные о подписках от Adapty.
После изменений в IDFA в iOS 14.5 мы рекомендуем запрашивать у пользователя `facebookAnonymousId` из Facebook. Тогда, если IDFA пользователя недоступен, интеграция продолжит работать. Следуйте гайду
Ниже учётных данных расположены три группы событий, которые можно отправлять в Singular из Adapty. Полный список событий, доступных в Adapty, смотрите [здесь](events).
Рекомендуем использовать названия событий по умолчанию, предоставляемые Adapty. При необходимости вы можете изменить их под свои нужды.
Adapty будет отправлять события подписок в Singular через интеграцию сервер-к-серверу, что позволит просматривать все события подписок в дашборде Singular и связывать их с вашими рекламными кампаниями.
:::warning
Профили, созданные до настройки интеграции, не смогут передавать свои события в Singular.
:::
### Подключение приложения к Singular \{#connect-your-app-to-singular\}
Интеграция между Adapty и Singular осуществляется по схеме сервер-к-серверу. Поэтому добавлять дополнительный код в приложение не нужно.
## Структура события \{#event-structure\}
Adapty отправляет события в Singular через GET-запрос с использованием параметров запроса. Каждое событие имеет следующую структуру:
```json
{
"n": "subscription_renewed",
"a": "singular_sdk_key_123",
"p": "iOS",
"i": "com.example.app",
"ip": "192.168.100.1",
"idfa": "00000000-0000-0000-0000-000000000000",
"idfv": "00000000-0000-0000-0000-000000000000",
"ve": "17.0.1",
"att_authorization_status": 3,
"custom_user_id": "user_12345",
"utime": 1709294400,
"amt": 9.99,
"cur": "USD",
"purchase_product_id": "yearly.premium.6999",
"purchase_transaction_id": "GPA.3383...",
"e": "{\"is_revenue_event\":true,\"amt\":9.99,\"cur\":\"USD\",\"purchase_product_id\":\"yearly.premium.6999\",\"purchase_transaction_id\":\"GPA.3383...\"}"
}
```
Где:
| Параметр | Тип | Описание |
|:---------------------------|:--------|:----------------------------------------------------------------|
| `n` | String | Название события (сопоставленное с событием Adapty). |
| `a` | String | Ваш Singular SDK Key. |
| `p` | String | Платформа ("iOS" или "Android"). |
| `i` | String | Store App ID (Bundle ID). |
| `ip` | String | IP-адрес пользователя. |
| `idfa` | String | **Только iOS**. ID для рекламодателей (в верхнем регистре). |
| `idfv` | String | **Только iOS**. ID для вендоров (в верхнем регистре). |
| `aifa` | String | **Только Android**. Google Advertising ID (в нижнем регистре). |
| `andi` | String | **Только Android**. Android ID (в нижнем регистре). |
| `asid` | String | **Только Android**. App Set ID (в нижнем регистре). |
| `ve` | String | Версия ОС. |
| `att_authorization_status` | Integer | **Только iOS**. Статус ATT (например, `3` — авторизован). |
| `custom_user_id` | String | Customer User ID пользователя. |
| `utime` | Long | UNIX-временная метка события в секундах. |
| `amt` | Float | Сумма дохода. |
| `cur` | String | Код валюты (например, "USD"). |
| `purchase_product_id` | String | ID продукта в сторе. |
| `purchase_transaction_id` | String | Оригинальный ID транзакции. |
| `e` | String | JSON-строка с деталями события (см. ниже). |
Параметр `e` (данные пользовательского события) — это JSON-строка, содержащая:
| Параметр | Тип | Описание |
|:--------------------------|:--------|:------------------------------------------------------|
| `is_revenue_event` | Boolean | `true`, если событие содержит данные о доходе. |
| `amt` | Float | Сумма дохода. |
| `cur` | String | Код валюты. |
| `purchase_product_id` | String | ID продукта в сторе. |
| `purchase_transaction_id` | String | Оригинальный ID транзакции. |
---
# File: tenjin
---
---
title: "Интеграция с Tenjin"
description: ""
---
Tenjin — это платформа мобильной атрибуции и аналитики для разработчиков приложений и маркетологов. Она предоставляет инструменты для измерения и оптимизации кампаний по привлечению пользователей, предлагая подробную информацию об эффективности приложений и поведении пользователей. Благодаря прозрачному и гибкому подходу Tenjin агрегирует данные из рекламных сетей и сторов, позволяя командам анализировать ROI, отслеживать конверсии и мониторить ключевые метрики эффективности.
Передавая [события подписок](events) в Tenjin, вы можете точно видеть, откуда приходят конверсии и какие кампании приносят наибольшую ценность по всем каналам, платформам и устройствам. По сути, дашборды Tenjin предлагают расширенную аналитику маркетинговых кампаний.
Передавая атрибуцию Tenjin в Adapty, вы обогащаете аналитику Adapty дополнительными критериями фильтрации, которые можно использовать в анализе когорт и конверсий.
Интеграция работает двумя способами:
1. **Получение данных атрибуции от Tenjin**
После интеграции Adapty собирает данные атрибуции от Tenjin. Эту информацию можно просмотреть на странице профиля пользователя в дашборде Adapty.
2. **Отправка событий подписок в Tenjin**
Adapty отправляет события покупок в Tenjin в режиме реального времени. Эти события помогают оценить эффективность рекламных кампаний непосредственно в дашборде Tenjin.
| Характеристика интеграции | Описание |
| -------------------------- | ------------------------------------------------------------ |
| Расписание | В реальном времени |
| Направление данных | Двусторонняя передача:
3. Войдите в [Tenjin Dashboard](https://tenjin.com/).
4. Перейдите в **Configuration** -> **Apps** в меню навигации.
5. Выберите приложение для вашей платформы (iOS или Android) и перейдите на вкладку **App and SDK**.
6. На вкладке **App and SDK** нажмите **Copy** в столбце **SDK Key**. Если у вас ещё нет SDK-ключа, нажмите кнопку **Generate SDK Key**, чтобы создать его.
7. Вернитесь в дашборд Adapty и вставьте скопированный SDK Key в соответствующее поле платформы:
- Для iOS-приложений: вставьте в поле **iOS SDK Key** или **iOS Sandbox SDK Key**
- Для Android-приложений: вставьте в поле **Android SDK Key** или **Android Sandbox SDK Key**
:::info
У Tenjin нет отдельного режима песочницы для серверной интеграции. Используйте отдельное приложение Tenjin или один и тот же ключ как для продакшн-, так и для sandbox-событий.
:::
8. Если у вас есть приложения на обеих платформах, повторите шаги 5–7 для другой платформы.
9. (опционально) При необходимости настройте раздел **How the revenue data should be sent**. Подробное описание параметров см. в разделе [Настройки интеграции](configuration#integration-settings).
10. Нажмите **Save**, чтобы завершить настройку.
Adapty начнёт отправлять события покупок в Tenjin и получать данные атрибуции. Вы можете настроить передачу событий в разделе **Events names**.
### Настройка событий и тегов \{#configure-events-and-tags\}
Tenjin принимает только события покупок и **Trial started**. В разделе **Events names** выберите, какие события следует передавать в Tenjin в соответствии с вашими целями отслеживания.
### Подключите приложение к Tenjin \{#connect-your-app-to-tenjin\}
Используйте метод SDK `Adapty.updateAttribution()`, чтобы получить данные атрибуции от Tenjin и передать их в Adapty.
2. Включите **Amplitude integration**, переключив тумблер.
3. Заполните поля интеграции:
| Поле | Описание |
| ---- | -------- |
| **Amplitude iOS/ Android/ Stripe API key** | Введите **API Key** Amplitude для iOS/ Android/ Stripe в Adapty. Найти его можно в разделе **Project settings** в Amplitude. Подробнее см. в [документации Amplitude](https://amplitude.com/docs/apis/authentication). Начните с ключей **Sandbox** для тестирования, затем переключитесь на **Production**-ключи после успешных тестов. |
4. Дополнительные настройки для тонкой настройки:
| Параметр | Описание |
| -------- | -------- |
| **How the revenue data should be sent** | Выберите, отправлять валовую выручку или выручку после вычета налогов и комиссий. Подробнее см. в разделе [Комиссия стора и налоги](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue). |
| **Exclude historical events** | Исключить события, произошедшие до установки Adapty SDK, чтобы избежать дублирования данных. Например, если пользователь оформил подписку 10 января, а SDK был установлен 6 марта, Adapty будет отправлять события только начиная с 6 марта. |
| **Send User Attributes** | Включите эту опцию, чтобы отправлять атрибуты пользователей, например языковые предпочтения. |
| **Always populate user_id** | Adapty автоматически отправляет `device_id` как `amplitudeDeviceId`. Для `user_id` это настройка определяет поведение:
Рекомендуем использовать стандартные названия событий, предложенные Adapty. При необходимости вы можете изменить их под свои нужды. Adapty будет отправлять события подписки в Amplitude через серверную интеграцию (server-to-server), что позволит просматривать все события подписки в вашем дашборде Amplitude.
### Настройка SDK \{#sdk-configuration\}
Используйте метод `setIntegrationIdentifier()`, чтобы задать параметр `amplitude_device_id`. Это обязательный шаг для настройки интеграции.
Если у вас есть регистрация пользователей, вы также можете передать `amplitude_user_id`.
:::note
Сторонние SDK генерируют пользовательские ID асинхронно. ID может быть ещё не готов в момент вызова `Adapty.activate()`. Если ваш **Customer User ID** приходит из одного из таких SDK, вызывайте `Adapty.activate()` без него. Как только ID будет получен, вызовите `setIntegrationIdentifier()`, а затем `identify()` с CUID.
:::
4. Откройте [Integrations > AppMetrica](https://app.adapty.io/integrations/appmetrica) в дашборде Adapty
5. Вставьте учётные данные AppMetrica.
### События и теги \{#events-and-tags\}
Adapty позволяет отправлять в AppMetrica три группы событий. Вы можете включить нужные события для отслеживания работы приложения. Полный список доступных событий см. в [документации по событиям](events).
:::note
AppMetrica синхронизирует события каждые 4 часа, поэтому события могут появляться в вашем дашборде с задержкой.
:::
:::tip
Мы рекомендуем использовать стандартные имена событий Adapty для единообразия, но вы можете изменить их в соответствии с вашей существующей аналитической системой.
:::
### Настройки выручки \{#revenue-settings\}
По умолчанию Adapty отправляет данные о выручке в виде свойств событий, которые отображаются в отчёте Events в AppMetrica. Вы можете настроить способ расчёта и отображения этих данных:
- **Revenue calculation**: Выберите, как рассчитываются значения выручки в соответствии с вашими потребностями финансовой отчётности:
- **Gross revenue**: Показывает общую выручку до вычетов — полезно для отслеживания суммы, которую платят пользователи
- **Proceeds after store commission**: Отображает выручку после вычета комиссии App Store/Play Store — помогает отслеживать фактический доход
- **Proceeds after store commission and taxes**: Показывает чистую выручку после вычета комиссии стора и налогов — наиболее точное отображение реального дохода
- **Report user's currency**: Если включено, продажи отображаются в локальной валюте пользователя, что упрощает анализ выручки по регионам. Если отключено, все продажи конвертируются в USD для единообразной отчётности по разным рынкам.
- **Send revenue events**: Включите эту опцию, чтобы данные о выручке отображались не только в отчёте Events, но и в отчёте AppMetrica [In-app and ad revenue](https://appmetrica.yandex.com/docs/en/mobile-reports/revenue-report). Убедитесь, что вы не отправляете выручку из других источников, иначе данные могут задвоиться.
- **Exclude historical events**: Если включено, Adapty не будет отправлять события, произошедшие до установки пользователем приложения с Adapty SDK. Это помогает избежать дублирования данных, если вы уже отправляли события в аналитику до интеграции Adapty.
### Настройка SDK \{#sdk-configuration\}
Для подключения интеграции AppMetrica в приложении необходимо задать два идентификатора:
1. `appmetrica_device_id`: обязателен для базовой интеграции
2. `appmetrica_profile_id`: необязателен, но рекомендуется, если в приложении есть регистрация пользователей
Используйте метод `setIntegrationIdentifier()` для установки этих значений. Ниже показано, как реализовать это для каждой платформы:
:::note
Сторонние SDK генерируют пользовательские ID асинхронно. ID может быть ещё не готов в момент вызова `Adapty.activate()`. Если ваш **Customer User ID** приходит из одного из таких SDK, вызывайте `Adapty.activate()` без него. Как только ID будет получен, вызовите `setIntegrationIdentifier()`, а затем `identify()` с CUID.
:::
### Получение токена Mixpanel \{#finding-your-mixpanel-token\}
Чтобы получить **Mixpanel Token**:
1. Войдите в ваш [Mixpanel Dashboard](https://mixpanel.com/settings/project/).
2. Откройте **Settings** и выберите **Organization Settings**.
3. На левой боковой панели перейдите в **Projects** и выберите ваш проект.
## Как работает интеграция \{#how-the-integration-works\}
Adapty автоматически сопоставляет нужные свойства событий — например, ID пользователя и выручку — с [нативными свойствами Mixpanel](https://docs.mixpanel.com/docs/data-structure/user-profiles). Это обеспечивает точное отслеживание и отчётность по событиям, связанным с подписками.
Кроме того, Adapty накапливает данные о выручке по каждому пользователю и обновляет их [свойства профиля](https://docs.mixpanel.com/docs/data-structure/user-profiles), включая `subscription state` и `subscription product ID`. После получения события Mixpanel обновляет соответствующие поля в реальном времени.
## События и теги \{#events-and-tags\}
Ниже учётных данных находятся три группы событий, которые можно отправлять в Mixpanel из Adapty. Просто включите нужные. Полный список событий, доступных в Adapty, смотрите [здесь](events).
Мы рекомендуем использовать названия событий по умолчанию, которые предоставляет Adapty. Однако вы можете изменить их по своему усмотрению.
## Настройка SDK \{#sdk-configuration\}
Используйте метод `.setIntegrationIdentifier()`, чтобы задать `mixpanelUserId`. Если значение не задано, Adapty использует ваш пользовательский ID (`customerUserId`) или, если он равен null, — Adapty ID. Убедитесь, что ID пользователя, который вы используете для отправки данных в Mixpanel из приложения, совпадает с тем, что вы отправляете в Adapty.
:::note
Сторонние SDK генерируют пользовательские ID асинхронно. ID может быть ещё не готов в момент вызова `Adapty.activate()`. Если ваш **Customer User ID** приходит из одного из таких SDK, вызывайте `Adapty.activate()` без него. Как только ID будет получен, вызовите `setIntegrationIdentifier()`, а затем `identify()` с CUID.
:::
2. Войдите в [дашборд PostHog](https://posthog.com/).
3. Перейдите в **Settings -> Project**.
4. В окне **Project** прокрутите вниз до раздела **Project ID** и скопируйте **Project API key**.
5. Вставьте API-ключ в поле **Project API key** в дашборде Adapty. У PostHog нет специального режима песочницы для серверной интеграции.
6. Выберите **PostHog Deployment**:
| Опция | Описание |
| ------ | ------------------------------------------------------------ |
| us/eu | Стандартные развёртывания PostHog. |
| Custom | Для self-hosted инстансов. Введите URL вашего инстанса в поле **PostHog Instance URL**. |
7. (опционально) Если вы используете self-hosted развёртывание PostHog, введите адрес вашего развёртывания в поле **PostHog Instance URL**.
8. (опционально) Настройте параметры **Reporting Proceeds**, **Exclude Historical Events**, **Report User's Currency** и **Send Trial Price**. Подробнее об этих опциях — в разделе [Настройки интеграции](configuration#integration-settings).
9. (опционально) В разделе **Events names** можно настроить, какие события отправляются в PostHog. Отключите ненужные события или переименуйте их по необходимости.
10. Нажмите **Save**, чтобы завершить настройку.
## Настройка SDK \{#sdk-configuration\}
Чтобы получать данные атрибуции от PostHog, передайте значение `distinctId` в Adapty, как показано ниже:
:::note
Сторонние SDK генерируют пользовательские ID асинхронно. ID может быть ещё не готов в момент вызова `Adapty.activate()`. Если ваш **Customer User ID** приходит из одного из таких SDK, вызывайте `Adapty.activate()` без него. Как только ID будет получен, вызовите `setIntegrationIdentifier()`, а затем `identify()` с CUID.
:::
Откройте аккаунт SplitMetrics Acquire, наведите курсор на логотип одного из MMP и нажмите кнопку **Settings**. В открывшемся диалоге найдите Client ID в пункте **5**, скопируйте его и вставьте в поле **Client ID** в Adapty.
Также потребуется указать Apple App ID. Чтобы найти его, откройте страницу приложения в App Store Connect, перейдите на страницу **App Information** в разделе **General** и найдите **Apple ID** в левом нижнем углу экрана.
## События и теги \{#events-and-tags\}
Ниже блока с учётными данными находятся три группы событий, которые можно отправлять из Adapty в SplitMetrics Acquire. Просто включите нужные. Полный список событий Adapty можно найти [здесь](events).
Рекомендуем оставить названия событий по умолчанию, предложенные Adapty. При необходимости их можно изменить. Adapty отправляет события подписок в SplitMetrics Acquire через серверную интеграцию (server-to-server), что позволяет просматривать все события подписок в дашборде SplitMetrics.
## Настройка SDK \{#sdk-configuration\}
На стороне SDK ничего настраивать не нужно, однако мы рекомендуем передавать `customerUserId` в Adapty для повышения точности данных.
:::warning
Убедитесь, что вы настроили [Apple Search Ads](apple-search-ads) в Adapty и [загрузили учётные данные](https://app.adapty.io/settings/apple-search-ads) — без этого SplitMetrics Acquire работать не будет.
:::
## Устранение неполадок \{#troubleshooting\}
Если интеграция с SplitMetrics Acquire не работает, хотя настройки верны:
- Убедитесь, что переключатель **Receive Apple Search Ads attribution in Adapty** включён в разделе [App Settings -> Apple Search Ads tab](https://app.adapty.io/settings/apple-search-ads), что [Apple Search Ads](apple-search-ads) настроены в Adapty и [учётные данные загружены](https://app.adapty.io/settings/apple-search-ads) — без этого SplitMetrics работать не будет.
- Убедитесь, что у профилей есть неорганическая атрибуция ASA. События в Adapty передаются только для профилей с детальной, неорганической атрибуцией ASA.
## Структура событий SplitMetrics Acquire \{#splitmetrics-acquire-event-structure\}
Adapty отправляет события в SplitMetrics Acquire через GET-запрос с параметрами запроса. Каждое событие имеет следующую структуру:
```json
{
"source": "Apple Search Ads",
"app_id": "123456789",
"name": "subscription_renewed",
"type": "subscription_renewed",
"revenue": 9.99,
"currency": "USD",
"tap_time": "2024-03-01 12:00:00",
"open_time": "2024-03-01 12:05:00",
"event_time": "2024-03-02 12:00:00",
"adaccount_id": "123456",
"campaign_id": "123456789",
"adgroup_id": "123456789",
"keyword_id": "123456789",
"creative_set_id": "123456789",
"Ad_id": "123456789",
"country_or_region": "US",
"conversion_type": "Download",
"user_id": "user_12345",
"att_status": "3",
"device_type": "iphone",
"app_version": "1.2.3",
"sdk_version": "2.10.0",
"ios_version": "17.2",
"event_value": "{\"vendor_product_id\":\"yearly.premium.6999\",\"original_transaction_id\":\"GPA.3383...\"}",
"event_id": "123e4567-e89b-12d3-a456-426614174000"
}
```
Где:
| Параметр | Тип | Описание |
|:--------------------|:-------|:----------------------------------------------------------------------------------------------------------------------------------|
| `source` | String | Всегда "Apple Search Ads". |
| `app_id` | String | Apple App ID. |
| `name` | String | Название события (сопоставляется с событием Adapty). |
| `type` | String | Тип события (совпадает с `name`). |
| `revenue` | Float | Сумма дохода. |
| `currency` | String | Код валюты. |
| `tap_time` | String | Дата и время нажатия на рекламное объявление. |
| `open_time` | String | Дата и время открытия приложения (установки). |
| `event_time` | String | Дата и время события. |
| `adaccount_id` | String | ID организации ASA. |
| `campaign_id` | String | ID кампании ASA. |
| `adgroup_id` | String | ID группы объявлений ASA. |
| `keyword_id` | String | ID ключевого слова ASA. |
| `creative_set_id` | String | ID креативного набора ASA. |
| `Ad_id` | String | ID объявления ASA. |
| `country_or_region` | String | Страна или регион стора. |
| `conversion_type` | String | Тип конверсии (например, "Download"). |
| `user_id` | String | Customer User ID или Adapty Profile ID. |
| `att_status` | String | Статус разрешения отслеживания (0–3). |
| `device_type` | String | Тип устройства (например, "iphone", "ipad"). |
| `app_version` | String | Версия приложения. |
| `sdk_version` | String | Версия Adapty SDK. |
| `ios_version` | String | Версия iOS. |
| `event_value` | String | JSON-строка со всеми доступными [деталями события](webhook-event-types-and-fields#for-most-event-types). |
| `event_id` | String | Уникальный ID события (UUID). |
---
# File: braze
---
---
title: "Braze"
description: "Интегрируйте Braze с Adapty для эффективного взаимодействия с клиентами и push-уведомлений."
---
[Braze](https://www.braze.com/) — одно из ведущих решений для работы с клиентами: широкий набор инструментов для push-уведомлений, email, SMS и in-app сообщений. Интегрировав Adapty с Braze, вы получите все события подписки в одном месте и сможете настраивать автоматические коммуникации на их основе.
Adapty предоставляет полный набор данных для отслеживания [событий подписки](events) из всех сторов в одном месте и может использоваться для обновления профилей пользователей в Braze. С Adapty вы легко увидите, как ведут себя ваши подписчики, поймёте их предпочтения и используете эту информацию для точечных и эффективных коммуникаций. Интеграция позволяет отслеживать события подписки в дашборде Braze и связывать их с [рекламными кампаниями](https://www.braze.com/product/journey-orchestration).
Adapty передаёт события подписки, атрибуты пользователей и покупки в Braze, чтобы вы могли выстраивать целевые коммуникации через push-уведомления после простой и быстрой настройки, описанной ниже.
## Как настроить интеграцию с Braze \{#how-to-set-up-braze-integration\}
Чтобы подключить Braze, перейдите в [Integrations -> Braze](https://app.adapty.io/integrations/braze), включите переключатель и заполните поля.
Первый шаг — предоставить необходимые учётные данные для установки соединения между Braze и Adapty. Для работы интеграции потребуются **REST API Key**, **Braze Instance ID**, а также **App IDs** для iOS и Android:
1. **REST API Key** создаётся в **Braze Dashboard** → **Settings** → **API Keys**. При создании убедитесь, что ключу назначено разрешение `users.track`:
2. Чтобы получить **Braze Instance ID**, посмотрите на URL вашего Braze Dashboard и найдите нужный идентификатор в разделе [документации Braze](https://www.braze.com/docs/api/basics/#endpoints). Он имеет региональный формат, например US-03, EU-01 и т.д.
3. iOS и Android App IDs также находятся в Braze Dashboard → **Settings** → **API Keys**. Скопируйте их отсюда:
## События, атрибуты пользователей и покупки \{#events-user-attributes-and-purchases\}
Ниже блока с учётными данными находятся три группы событий, которые можно отправлять из Adapty в Braze. Просто включите нужные. При необходимости вы можете переименовать события перед отправкой в Braze. Полный список событий Adapty доступен [здесь](events):
Adapty отправляет события подписки и атрибуты пользователей в Braze через серверную интеграцию, что позволяет просматривать их в дашборде Braze и настраивать кампании на их основе.
Для событий с выручкой, таких как конверсии пробного периода и продления, Adapty передаёт эту информацию в Braze как покупки.
[Здесь](messaging#event-properties) вы найдёте полные спецификации свойств событий, отправляемых в Braze.
:::note
Полезные атрибуты пользователей
По умолчанию Adapty отправляет ряд атрибутов пользователей для интеграции с Braze. Ознакомьтесь со списком ниже, чтобы выбрать подходящие для ваших задач.
:::
| Атрибут пользователя | Тип | Значение |
|--------------|----|-----|
| `adapty_customer_user_id` | String | Содержит уникальный идентификатор пользователя, заданный клиентом. Доступен как в [дашборде](profiles-crm) Adapty, так и в Braze. |
| `adapty_profile_id` | String | Содержит уникальный идентификатор профиля пользователя Adapty, который можно найти в [дашборде](profiles-crm) Adapty. |
| `environment` | String | Указывает, работает ли пользователь в среде песочницы или в продакшене.
Возможные значения: `Sandbox` или `Production`
| | `store` | String |Содержит название стора, через который была совершена покупка.
Возможные значения:
`app_store` или `play_store`.
| | `vendor_product_id` | String |Содержит идентификатор продукта в Apple/Google стор.
Например: org.locals.12345
| | `subscription_expires_at` | String |Содержит дату истечения последней подписки.
Формат значения:
YYYY-MM-DDTHH:mm:ss.SSS+TZ
Например: 2023-02-15T17:22:03.000+0000
| | `active_subscription` | String | Принимает значение `true` при любом событии покупки или продления, или `false`, если подписка истекла. | | `period_type` | String |Указывает последний тип периода для покупки или продления.
Возможные значения:
`trial` для пробного периода или `normal` для остальных случаев.
| Все значения типа float округляются до int. Строки передаются без изменений. Помимо предопределённого набора тегов, можно также отправлять [пользовательские атрибуты](segments#custom-attributes) с помощью тегов. Это даёт дополнительную гибкость в выборе типов данных и полезно для отслеживания специфической информации о продукте или сервисе. Все пользовательские атрибуты пользователей автоматически отправляются в Braze, если на [странице интеграции](https://app.adapty.io/integrations/braze) отмечен чекбокс **Send user attributes**. ## Настройка SDK \{#sdk-configuration\} Чтобы связать профили пользователей в Adapty и Braze, необходимо либо настроить Braze SDK с тем же идентификатором пользователя, что и в Adapty, либо использовать метод `.changeUser()`:
2. Включите переключатель интеграции.
3. Введите ваш **OneSignal App ID**.
Чтобы настроить интеграцию с OneSignal, перейдите в раздел [Integrations -> OneSignal](https://app.adapty.io/integrations/onesignal) дашборда Adapty, включите переключатель и укажите учётные данные для интеграции.
## Получение вашего OneSignal App ID \{#retrieving-your-onesignal-app-id\}
Найдите ваш **OneSignal App ID** в [дашборде OneSignal](https://dashboard.onesignal.com/login):
1. Перейдите в **Settings** → **Keys & IDs**.
2. Скопируйте ваш **OneSignal App ID** и вставьте его в поле **App ID** в дашборде Adapty.
Подробнее о OneSignal ID можно узнать в [официальной документации.](https://documentation.onesignal.com/docs/en/keys-and-ids)
### Настройка событий \{#configuring-events\}
Adapty позволяет отправлять в OneSignal три группы событий. Включите нужные в дашборде Adapty. Полный список доступных событий с подробным описанием можно найти [здесь](events).
Adapty отправляет события подписок в OneSignal через серверную интеграцию, что позволяет отслеживать всю активность, связанную с подписками, прямо в OneSignal.
:::warning
С 17 апреля 2023 года бесплатный план OneSignal больше не поддерживает эту интеграцию. Она доступна только на планах **Growth**, **Professional** и **выше**. Подробнее см. в [OneSignal Pricing](https://onesignal.com/pricing).
:::
## Пользовательские теги \{#custom-tags\}
Интеграция обновляет и назначает различные свойства ваших пользователей Adapty в виде тегов, которые затем отправляются в OneSignal. Ознакомьтесь со списком тегов ниже, чтобы выбрать те, которые лучше всего соответствуют вашим потребностям.
:::warning
В OneSignal есть ограничение на количество тегов. Оно распространяется как на теги, созданные Adapty, так и на любые существующие теги в OneSignal. Превышение лимита может вызвать ошибки при отправке событий.
:::
| Тег | Тип | Описание |
|---|----|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `adapty_customer_user_id` | String | Уникальный идентификатор пользователя в вашем приложении. Должен совпадать в вашей системе, Adapty и OneSignal. |
| `adapty_profile_id` | String | ID профиля пользователя в Adapty, доступен в [дашборде Adapty](profiles-crm). |
| `environment` | String | `Sandbox` или `Production` — среда, в которой находится пользователь. |
| `store` | String | Стор, в котором был куплен продукт. Варианты: **app_store**, **play_store**, **stripe** или название вашего [кастомного стора](custom-store). |
| `vendor_product_id` | String | ID продукта в сторе (например, `org.locals.12345`). |
| `subscription_expires_at` | String | Дата истечения последней подписки (`YYYY-MM-DDTHH:MM:SS+0000`, например `2023-02-10T17:22:03.000000+0000`). |
| `last_event_type` | String | Последний тип события из [списка событий Adapty](events).
1. **App ID** можно найти в дашборде Pushwoosh.
2. **Auth token** можно найти в разделе API Access в настройках Pushwoosh.
## События и теги \{#events-and-tags\}
Ниже учётных данных расположены три группы событий, которые можно отправлять из Adapty в Pushwoosh. Просто включите нужные. При необходимости вы можете переименовать события перед отправкой в Pushwoosh. Полный список событий Adapty доступен [здесь](events).
Adapty будет отправлять события подписки в Pushwoosh через серверную интеграцию, что позволит просматривать все события подписки в дашборде Pushwoosh.
:::note
Пользовательские теги
В рамках интеграции с Pushwoosh вы также можете использовать собственные теги. Ознакомьтесь со списком тегов ниже, чтобы выбрать подходящий для ваших задач.
:::
| Тег | Тип | Значение |
|---|----|-----|
| `adapty_customer_user_id` | String | Содержит уникальный идентификатор пользователя, который можно найти на стороне Pushwoosh. |
| `adapty_profile_id` | String | Содержит уникальный идентификатор профиля пользователя Adapty, который можно найти в вашем [дашборде](profiles-crm) Adapty. |
| `environment` | String | Указывает, в какой среде работает пользователь — песочнице или продакшене.
Возможные значения: `Sandbox` или `Production`.
| | `store` | String |Содержит название стора, через который была совершена покупка.
Возможные значения:
`app_store` или `play_store`.
| | `vendor_product_id` | String |Содержит Product ID в Apple/Google стор.
Например: org.locals.12345
| | `subscription_expires_at` | String |Содержит дату истечения последней подписки.
Формат значения:
year-month dayThour:minute:second
Например: 2023-02-10T17:22:03.000000+0000
| | `last_event_type` | String | Указывает тип последнего полученного события из списка стандартных [событий Adapty](events), включённых для интеграции. | | `purchase_date` | String |Содержит дату последней транзакции (первоначальной покупки или продления).
Формат значения:
year-month dayThour:minute:second
Например: 2023-02-10T17:22:03.000000+0000
| | `original_purchase_date` | String |Содержит дату первой покупки согласно транзакции.
Формат значения:
year-month dayThour:minute:second
Например: 2023-02-10T17:22:03.000000+0000
| | `active_subscription` | String | Принимает значение `true` при любом событии покупки или продления, или `false`, если подписка истекла. | | `period_type` | String |Указывает последний тип периода для покупки или продления.
Возможные значения:
`trial` для пробного периода или `normal` для остальных.
| Все значения с плавающей точкой округляются до целых. Строки остаются без изменений. Помимо предопределённого списка тегов, можно отправлять [пользовательские атрибуты](segments#custom-attributes) в виде тегов. Это даёт больше гибкости в выборе передаваемых данных и полезно для отслеживания специфической информации о продукте или сервисе. Все пользовательские атрибуты пользователя автоматически отправляются в Pushwoosh, если отмечен чекбокс **Send user custom attributes** на [странице интеграции](https://app.adapty.io/integrations/pushwoosh). ## Настройка SDK \{#sdk-configuration\} Чтобы связать Adapty с Pushwoosh, необходимо передать значение `HWID`:
2. Дайте ему любое имя (например, `Adapty`) и добавьте в свой воркспейс:
### 2\. Дайте разрешение на публикацию и получите токен для приложения \{#2-give-permission-to-post-and-get-a-token-for-your-app\}
После этого вы будете перенаправлены на страницу вашего приложения в Slack.
1. Прокрутите вниз и нажмите **Permissions**:
2. После перехода прокрутите вниз до раздела **Scopes** и нажмите **Add an OAuth Scope**:
3. Добавьте разрешения `chat:write`, `chat:write.public` и `chat:write.customize`. Они необходимы для публикации сообщений в каналах и их кастомизации:
4. Прокрутите страницу обратно вверх и нажмите **Install to Workspace**:
5. Нажмите **Allow**:
После этого вы снова окажетесь на той же странице, но теперь там будет доступен OAuth-токен (`xoxb-...`). Именно он нужен для завершения настройки:
### 3\. Настройте интеграцию в Adapty \{#3-configure-the-integration-in-adapty\}
1. Перейдите в [**Integrations** → **Slack**](https://app.adapty.io/integrations/slack):
2. Вставьте токен `xoxb-...` из предыдущего шага и выберите каналы, в которые приложение будет публиковать сообщения. Вы можете настроить получение событий только для продакшна, только для песочницы или для обоих режимов. Также можно выбрать валюту для отображения сумм (оригинальная или конвертированная в USD).
:::note
Если вы хотите отправлять сообщения от Adapty в приватный канал, необходимо вручную добавить созданное вами приложение `Adapty` в этот канал — иначе отправка не сработает.
:::
3. Наконец, выберите события, о которых хотите получать уведомления, в разделе **Events**:
Готово!
События будут поступать в указанные вами каналы. Там же вы увидите информацию о доходе (где применимо) и сможете перейти к профилю пользователя в Adapty:
---
# File: s3-exports
---
---
title: "Amazon S3"
description: "Экспортируйте данные о подписках в S3 для расширенной аналитики и отчётности."
---
Интеграция Adapty с Amazon S3 позволяет безопасно хранить данные о событиях и посещениях пейволов в одном центральном месте. Вы сможете сохранять свои [события подписки](events) в виде .csv-файлов в бакете Amazon S3.
Чтобы настроить эту интеграцию, нужно выполнить несколько простых шагов в AWS Console и дашборде Adapty.
:::note
Расписание
Adapty отправляет данные каждые **24 часа** в 4:00 UTC.
Каждый файл содержит данные о событиях, созданных за весь предыдущий календарный день по UTC. Например, данные, автоматически экспортированные в 4:00 UTC 8 марта, будут содержать все события, созданные 7 марта с 00:00:00 до 23:59:59 по UTC.
:::
## Как настроить интеграцию с Amazon S3 \{#how-to-set-up-amazon-s3-integration\}
Для получения данных вам понадобятся следующие учётные данные:
1. Access key ID
2. Secret access key
3. S3 bucket name
4. Folder name inside the S3 bucket
:::note
Вложенные директории
В поле имени бакета Amazon S3 можно указывать вложенные директории, например: adapty-events/com.sample-app
:::
Чтобы подключить Amazon S3, перейдите в [**Integrations** -> **Amazon S3**](https://app.adapty.io/integrations/s3), включите переключатель и заполните поля.
Сначала укажите учётные данные для установки соединения между Amazon S3 и профилями Adapty.
В дашборде Adapty для настройки подключения нужны следующие поля:
| Поле | Описание |
| :--------------------------- | :----------------------------------------------------------- |
| **Access Key ID** | Уникальный идентификатор для аутентификации пользователя или приложения при доступе к сервису AWS. Найдите этот идентификатор в загруженном [csv-файле](s3-exports#how-to-create-amazon-s3-credentials). |
| **Secret Access Key** | Приватный ключ, используемый совместно с Access Key ID для аутентификации при доступе к сервису AWS. Найдите этот ключ в загруженном [csv-файле](s3-exports#how-to-create-amazon-s3-credentials). |
| **S3 Bucket Name** | Глобально уникальное имя, идентифицирующее конкретный S3-бакет в облаке AWS. S3-бакеты — это простой сервис хранения, позволяющий хранить и получать объекты данных (файлы, изображения и т. д.) в облаке. |
| **Folder Inside the Bucker** | Название папки, которую вы хотите создать внутри выбранного S3-бакета. Обратите внимание: S3 имитирует папки с помощью префиксов ключей объектов, которые по сути и являются именами папок. |
## Как создать учётные данные Amazon S3 \{#how-to-create-amazon-s3-credentials\}
Этот гайд поможет вам создать необходимые учётные данные в консоли AWS.
### 1\. Создайте политику доступа \{#create-access-policy\}
Сначала перейдите на [страницу управления политиками IAM](https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/policies) в консоли AWS и выберите **Create Policy**.
В редакторе политики вставьте следующий JSON и замените `adapty-s3-integration-test` на название вашего бакета:
```json showLineNumbers title="Json"
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListObjectsInBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::adapty-s3-integration-test"
},
{
"Sid": "AllowAllObjectActions",
"Effect": "Allow",
"Action": "s3:*Object",
"Resource": [
"arn:aws:s3:::adapty-s3-integration-test/*",
"arn:aws:s3:::adapty-s3-integration-test"
]
},
{
"Sid": "AllowBucketLocation",
"Effect": "Allow",
"Action": "s3:GetBucketLocation",
"Resource": "arn:aws:s3:::adapty-s3-integration-test"
}
]
}
```
После завершения настройки политики вы можете добавить теги (необязательно), а затем нажать **Next**, чтобы перейти к последнему шагу. На этом шаге нужно указать название политики и нажать кнопку **Create policy**, чтобы завершить создание.
### 2\. Создайте пользователя IAM \{#2-create-iam-user\}
Чтобы Adapty мог загружать отчёты с сырыми данными в ваш бакет, необходимо предоставить Access Key ID и Secret Access Key пользователя с правом записи в этот бакет.
Для этого перейдите в IAM Console и откройте раздел [Users](https://console.aws.amazon.com/iamv2/home#/users). Затем нажмите кнопку **Add users**.
Дайте пользователю имя, выберите **Access key – Programmatic access** и перейдите к настройке прав доступа.
На следующем шаге выберите опцию **Add user to group**, затем нажмите кнопку **Create group**.
Далее укажите имя для вашей группы пользователей и выберите политику, созданную ранее. После выбора политики нажмите кнопку **Create group**, чтобы завершить процесс.
После успешного создания группы **выберите её** и перейдите к следующему шагу.
Это последний шаг данного раздела — просто нажмите кнопку **Create User**.
Наконец, вы можете **скачать учётные данные в формате .csv** или скопировать и вставить их прямо с дашборда.
## Экспорт данных вручную \{#manual-data-export\}
Помимо автоматического экспорта событий в Amazon S3, Adapty также поддерживает ручной экспорт файлов. С помощью этой функции вы можете выбрать конкретный временной интервал и экспортировать данные о событиях в свой S3-бакет вручную. Это даёт вам больше контроля над тем, какие данные и когда экспортировать.
Указанный диапазон дат используется для экспорта событий, созданных с Date A 00:00:00 UTC по Date B 23:59:59 UTC.
## Структура таблицы \{#table-structure\}
В интеграции с AWS S3 Adapty предоставляет таблицу для хранения исторических данных о транзакционных событиях и посещениях пейвола. Таблица содержит информацию о профиле пользователя, выручке и чистом доходе, источнике стора и других параметрах. По сути, эти таблицы фиксируют все транзакции, сгенерированные приложением за определённый период времени.
:::warning
Обратите внимание, что эта структура может расширяться со временем — по мере добавления новых данных нами или третьими сторонами, с которыми мы работаем. Убедитесь, что ваш код, обрабатывающий её, достаточно устойчив и опирается на конкретные поля, а не на структуру в целом.
:::
Ниже представлена структура таблицы для событий:
:::note
Adapty конвертирует другие валюты в USD по курсу [currencylayer.com](https://currencylayer.com/) (обновляется каждые 8 часов). Курс **фиксируется на момент транзакции** — последующие изменения не влияют на результат конвертации.
:::
| Столбец | Описание |
|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **profile_id** | ID пользователя Adapty. |
| **event_type** | Название события в нижнем регистре. Типы событий описаны в разделе [События](events). |
| **event_datetime** | Дата в формате ISO 8601. |
| **transaction_id** | Уникальный идентификатор транзакции — покупки или продления. |
| **original_transaction_id** | Идентификатор транзакции первоначальной покупки. |
| **subscription_expires_at** | Дата истечения подписки. Как правило, в будущем. |
| **environment** | Sandbox или Production. |
| **revenue_usd** | Выручка в USD. Может быть пустым. |
| **proceeds_usd** | Поступления в USD. Может быть пустым. |
| **net_revenue_usd** | Чистая выручка (доход после уплаты налогов) в USD. Может быть пустым. |
| **tax_amount_usd** | Сумма налоговых отчислений в USD. Может быть пустым. |
| **revenue_local** | Выручка в местной валюте. Может быть пустым. |
| **proceeds_local** | Поступления в местной валюте. Может быть пустым. |
| **net_revenue_local** | Чистая выручка (доход после уплаты налогов) в местной валюте. Может быть пустым. |
| **tax_amount_local** | Сумма налоговых отчислений в местной валюте. Может быть пустым. |
| **customer_user_id** | ID пользователя на стороне разработчика. Например, UUID, email или любой другой идентификатор. Null, если не задан. |
| **store** | Может быть _app_store_ или _play_store_. |
| **product_id** | ID продукта в Apple App Store, Google Play Store или Stripe. |
| **base_plan_id** | [ID базового плана](https://support.google.com/googleplay/android-developer/answer/12154973) в Google Play Store или [ID цены](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) в Stripe. |
| **developer_id** | ID пейвола (SDK) разработчика, с которого была совершена транзакция. |
| **ab_test_name** | Название A/B-теста, в рамках которого была совершена транзакция. |
| **ab_test_revision** | Ревизия A/B-теста, в рамках которого была совершена транзакция. |
| **paywall_name** | Название пейвола, с которого была совершена транзакция. |
| **paywall_revision** | Ревизия пейвола, с которого была совершена транзакция. |
| **profile_county** | Страна профиля, определённая Adapty по IP-адресу. |
| **install_date** | Дата установки в формате ISO 8601. |
| **idfv** | [identifierForVendor](https://developer.apple.com/documentation/uikit/uidevice/identifierforvendor) на устройствах iOS. |
| **idfa** | [advertisingIdentifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/advertisingidentifier) на устройствах iOS. |
| **advertising_id** | Advertising ID — уникальный код, присваиваемый операционной системой Android, который рекламодатели могут использовать для идентификации устройства пользователя. |
| **ip_address** | IP-адрес устройства (IPv4 или IPv6; при наличии предпочтение отдаётся IPv4). Обновляется при каждой смене IP-адреса устройства. |
| **cancellation_reason** | Причина отмены подписки пользователем.
Возможные значения:
**iOS & Android** _voluntarily_cancelled_, _billing_error_, _refund_
**iOS** _price_increase_, _product_was_not_available_, _unknown_, _upgraded_
**Android** _new_subscription_replace_, _cancelled_by_developer_
| | **android_app_set_id** | [AppSetId](https://developer.android.com/design-for-safety/privacy-sandbox/reference/adservices/appsetid/AppSetId) — уникальный, сбрасываемый пользователем идентификатор на уровне устройства и аккаунта разработчика для рекламных сценариев без монетизации. | | **android_id** | На Android 8.0 (API level 26) и выше — 64-битное число (в шестнадцатеричном формате), уникальное для каждой комбинации ключа подписи приложения, пользователя и устройства. Подробнее см. [документацию для разработчиков Android](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID). | | **device** | Название модели устройства, отображаемое конечному пользователю. | | **currency** | Трёхбуквенный код валюты транзакции (ISO-4217). | | **store_country** | Страна профиля, определённая Apple/Google store. | | **attribution_source** | Источник атрибуции. | | **attribution_network_user_id** | ID пользователя, присвоенный источником атрибуции. | | **attribution_status** | Может быть organic, non_organic или unknown. | | **attribution_channel** | Название маркетингового канала. | | **attribution_campaign** | Название маркетинговой кампании. | | **attribution_ad_group** | Группа объявлений атрибуции. | | **attribution_ad_set** | Набор объявлений атрибуции. | | **attribution_creative** | Ключевое слово креатива атрибуции. | | **attributes** | JSON с [пользовательскими атрибутами](setting-user-attributes#custom-user-attributes). Включает все пользовательские атрибуты, настроенные для отправки из мобильного приложения. Чтобы их отправлять, включите опцию **Send User Attributes** на странице [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). | | **integration_ids** | Все интеграционные ID, связанные с профилем. Словарь. Пример: {'mixpanel_user_id': 'mixpanelUserId-test', 'facebook_anonymous_id': 'facebookAnonymousId-test'} | Here is the table structure for the paywall visits: | Столбец | Описание | | :-------------------- | :-------------------------------------------------------------------------------------------------------------------- | | **profile_id** | Идентификатор пользователя Adapty. | | **customer_user_id** | Идентификатор пользователя, заданный разработчиком. Например, это может быть UUID, email или любой другой ID. Null, если не задан. | | **profile_country** | Страна профиля, определённая стором Apple/Google. | | **install_date** | Дата установки в формате ISO 8601. | | **store** | Может быть _app_store_ или _play_store_. | | **paywall_showed_at** | Дата, когда пейвол был показан пользователю. | | **developer_id** | Developer (SDK) ID пейвола, из которого совершена транзакция. | | **ab_test_name** | Название A/B-теста, из которого совершена транзакция. | | **ab_test_revision** | Ревизия A/B-теста, из которого совершена транзакция. | | **paywall_name** | Название пейвола, из которого совершена транзакция. | | **paywall_revision** | Ревизия пейвола, из которого совершена транзакция. | ## События и теги \{#events-and-tags\} Вы можете управлять тем, какие данные передаются в рамках интеграции. Доступны следующие параметры настройки: | Настройка | Описание | | :--------------------------------- | :----------------------------------------------------------- | | **Exclude Historical Events** | Исключить события, произошедшие до установки приложения с Adapty SDK. Это предотвращает дублирование событий и обеспечивает точность отчётов. Например, если пользователь активировал ежемесячную подписку 10 января, а обновил приложение с Adapty SDK 6 марта, Adapty пропустит события до 6 марта и сохранит последующие. | | **Include events without profile** | Включить транзакции, не связанные с профилем пользователя в Adapty. Сюда могут входить покупки, совершённые до установки Adapty SDK, или транзакции, полученные из серверных уведомлений стора, которые невозможно сразу сопоставить с конкретным пользователем. | | **Send User Attributes** | Если вы хотите передавать атрибуты пользователей, например языковые настройки, и ваш тарифный план OneSignal поддерживает более 10 тегов, выберите эту опцию. При включении можно передавать дополнительную информацию сверх стандартных 10 тегов. Учтите, что превышение лимита тегов может приводить к ошибкам. |
Ниже настроек интеграции находятся три группы событий, которые можно экспортировать, отправлять и хранить в Amazon S3 из Adapty. Просто включите нужные. Полный список событий, предоставляемых Adapty, доступен [здесь](events).
---
# File: google-cloud-storage
---
---
title: "Google Cloud Storage"
description: "Интегрируйте Google Cloud Storage с Adapty для безопасного хранения данных."
---
Включите интеграцию с Google Cloud Storage, чтобы безопасно хранить [события подписок](events) и [данные о посещениях пейвола](paywall-metrics) в одном месте — вашем бакете Google Cloud Storage.
Каждый день в 4:00 UTC Adapty загружает .csv-файлы с данными за предыдущий день в ваши бакеты. Вы можете выбрать, какие данные получать: **событий**, **посещений пейвола** или **оба варианта**. Также можно экспортировать данные [вручную](#manual-data-export) в любое время за любой период.
Чтобы настроить интеграцию, [создайте ключ доступа к бакету](#create-google-cloud-storage-credentials) в Google Cloud Console и [добавьте его в настройки Adapty](#set-up-google-cloud-storage-integration).
## Расписание и продолжительность загрузки \{#upload-schedule-and-duration\}
Adapty загружает данные в Google Cloud Storage каждые 24 часа в 04:00 UTC.
Файлы содержат данные о событиях, созданных в течение предыдущего календарного дня (UTC). Файл, загруженный 8 марта, будет содержать все события, созданные 7 марта с 00:00:00 до 23:59:59 UTC.
Процесс может занять несколько часов — в зависимости от общего числа файлов в очереди и объёма запрошенных вами данных. Если Adapty включает в первую загрузку исторические данные, это займёт больше времени, чем последующие ежедневные загрузки.
## Настройка интеграции с Google Cloud Storage \{#set-up-google-cloud-storage-integration\}
Вам понадобится действующий ключ сервисного аккаунта Google Cloud с **правом на запись**. Чтобы его создать, следуйте инструкциям в разделе [создания учётных данных](#create-google-cloud-storage-credentials).
:::warning
Для событий и посещений пейволов можно использовать разные бакеты с разными учётными данными. Однако если **хотя бы один** набор учётных данных окажется недействительным, [**обе загрузки завершатся ошибкой**](#troubleshooting).
:::
Перейдите в [**Integrations** -> **Google Cloud Storage**](https://app.adapty.io/integrations/google-cloud-storage) и откройте нужную вкладку (**Events** или **Paywall visits**). Включите интеграцию.
Загрузите файл с вашим **ключом сервисного аккаунта Google Cloud**. Укажите целевой **бакет** и **папку**. Сохраните изменения.
### Дополнительные настройки для данных о событиях \{#optional-settings-for-event-data\}
Вы можете указать, какие события включать в отчёт, и задать для них пользовательские названия. Полный список доступных событий см. в статье [Events](events).
| Название | Значение по умолчанию | Описание |
| ------------------------------ | ----------------- | ----------- |
| Exclude historical events | true | Исключить информацию о событиях, произошедших до интеграции Adapty SDK в ваше приложение. Пользователь оформил ежемесячную подписку 10 января. Обновление приложения от 1 марта было первым, включавшим Adapty SDK.
Если этот параметр **включён**, отчёт не будет содержать событие «подписка оформлена» от января и событие «подписка продлена» от февраля. **Будет** включено событие «подписка продлена» от 10 марта.
Причина отмены подписки пользователем.
Возможные значения:
**iOS и Android** — *voluntarily_cancelled*, *billing_error*, *refund*
**Только iOS** — *price_increase*, *product_was_not_available*, *unknown*, *upgraded*
**Только Android** — *new_subscription_replace*, *cancelled_by_developer*
| | **android_app_set_id** | [AppSetId](https://developer.android.com/design-for-safety/privacy-sandbox/reference/adservices/appsetid/AppSetId) — уникальный, сбрасываемый пользователем идентификатор для каждого устройства и аккаунта разработчика, предназначенный для некоммерческих рекламных сценариев. | | **android_id** | На Android 8.0 (API level 26) и выше — 64-битное число (в шестнадцатеричном формате), уникальное для каждой комбинации ключа подписи приложения, пользователя и устройства. Подробнее см. в [документации для разработчиков Android](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID). | | **device** | Название модели устройства, отображаемое конечному пользователю. | | **currency** | Трёхбуквенный код валюты транзакции (ISO-4217). | | **store_country** | Страна профиля, определённая Apple/Google store. | | **attribution_source** | Источник атрибуции. | | **attribution_network_user_id** | Идентификатор пользователя, присвоенный источником атрибуции. | | **attribution_status** | Может быть organic, non_organic или unknown. | | **attribution_channel** | Название маркетингового канала. | | **attribution_campaign** | Название маркетинговой кампании. | | **attribution_ad_group** | Группа объявлений атрибуции. | | **attribution_ad_set** | Набор объявлений атрибуции. | | **attribution_creative** | Ключевое слово креатива атрибуции. | | **attributes** | JSON с [пользовательскими атрибутами](setting-user-attributes#custom-user-attributes). Включает любые пользовательские атрибуты, настроенные для отправки из мобильного приложения. Для отправки включите параметр **Send User Attributes** на странице [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). | | **integration_ids** | Все идентификаторы интеграций, связанные с профилем. Словарь. Пример: {'mixpanel_user_id': 'mixpanelUserId-test', 'facebook_anonymous_id': 'facebookAnonymousId-test'} | ### Посещения пейволов \{#paywall-visits\} | Столбец | Описание | | :-------------------- | :----------------------------------------------------------------------------------------------------------- | | **profile_id** | Идентификатор пользователя Adapty. | | **customer_user_id** | Идентификатор пользователя разработчика. Например, UUID пользователя, email или любой другой идентификатор. Null, если не задан. | | **profile_country** | Страна профиля, определённая Apple/Google store. | | **install_date** | Дата установки в формате ISO 8601. | | **store** | Может быть *app_store* или *play_store*. | | **paywall_showed_at** | Дата, когда пейвол был показан пользователю. | | **developer_id** | ID разработчика (SDK) пейвола, из которого пришла транзакция. | | **ab_test_name** | Название A/B-теста, из которого пришла транзакция. | | **ab_test_revision** | Ревизия A/B-теста, из которого пришла транзакция. | | **paywall_name** | Название пейвола, из которого пришла транзакция. | | **paywall_revision** | Ревизия пейвола, из которого пришла транзакция. | ## Устранение неполадок \{#troubleshooting\} Adapty проверяет действительность ключей доступа **до** начала загрузки. Если хотя бы один ключ Google Cloud Storage окажется недействительным, Adapty **прерывает загрузку** и выдаёт ошибку. Чтобы загрузки проходили без перебоев, заменяйте ключи до истечения срока их действия. Если вы обновляете ключ для **событий**, не забудьте обновить ключ для **посещений пейволов**, и наоборот. --- # File: webhook-event-types-and-fields --- --- title: "Типы событий и поля вебхука" description: "" --- Adapty отправляет вебхуки в ответ на события подписки. В этом разделе описаны типы таких событий и данные, которые содержатся в каждом вебхуке. ## Типы событий вебхука \{#webhook-event-types\} Вы можете отправлять в вебхук все типы событий или выбрать только нужные. Ознакомьтесь с нашими [потоками событий](event-flows), чтобы понять, какие данные ожидать и как выстроить вокруг них бизнес-логику. Ненужные типы событий можно отключить при [настройке интеграции с вебхуком](set-up-webhook-integration#configure-webhook-integration-in-the-adapty-dashboard). Там же можно заменить стандартные идентификаторы событий Adapty на собственные, если это необходимо. | Event name | Description | |:-----------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | subscription_started | Срабатывает, когда пользователь активирует платную подписку без пробного периода, то есть с него сразу списывается оплата. | | subscription_renewed | Происходит при продлении подписки и списании оплаты с пользователя. Это событие фиксируется начиная со второго платежа — как для пробных, так и для обычных подписок. | | subscription_renewal_cancelled | Пользователь отключил автопродление подписки. Доступ к премиум-функциям сохраняется до конца оплаченного периода. | | subscription_renewal_reactivated | Срабатывает, когда пользователь повторно включает автопродление подписки. | | subscription_expired | Срабатывает, когда подписка полностью завершается после отмены. Например, если пользователь отменил подписку 12 декабря, но она активна до 31 декабря, событие фиксируется 31 декабря, когда подписка истекает. | | subscription_paused | Происходит, когда пользователь активирует [паузу подписки](https://developer.android.com/google/play/billing/lifecycle/subscriptions#pause) (только Android). | | subscription_deferred | Срабатывает, когда покупка подписки [откладывается](https://adapty.io/glossary/subscription-purchase-deferral/), — пользователь может перенести платёж, сохраняя доступ к премиум-функциям. Функция доступна через Google Play Developer API и может использоваться для пробных периодов или в поддержку пользователей, испытывающих финансовые трудности. | | non_subscription_purchase | Любая покупка без подписки: пожизненный доступ или расходуемые покупки, например внутриигровые монеты. | | trial_started | Срабатывает, когда пользователь активирует пробную подписку. | | trial_converted | Происходит, когда пробный период заканчивается и с пользователя списывается первый платёж. Например, если пробный период действует до 14 января, но оплата проходит 7 января, событие фиксируется 7 января. | | trial_renewal_cancelled | Пользователь отключил автопродление подписки в течение пробного периода. Доступ к премиум-функциям сохраняется до конца пробного периода, но оплата не будет списана и подписка не активируется. | | trial_renewal_reactivated | Происходит, когда пользователь повторно включает автопродление подписки в течение пробного периода. | | trial_expired | Срабатывает, когда пробный период заканчивается без перехода в подписку. | | entered_grace_period | Происходит, когда попытка оплаты завершается неудачей и пользователь переходит в льготный период (если он включён). В течение этого времени доступ к премиум-функциям сохраняется. | | billing_issue_detected | Срабатывает при возникновении проблемы с оплатой во время попытки списания (например, недостаточно средств на карте). | | subscription_refunded | Срабатывает при возврате средств за подписку (например, через службу поддержки Apple). | | non_subscription_purchase_refunded | Срабатывает при возврате средств за покупку без подписки. | | access_level_updated | Происходит при обновлении уровня доступа пользователя. | :::note `subscription_renewal_reactivated` содержит **предыдущий** идентификатор продукта — тот, который был активен на момент отмены, — даже если пользователь впоследствии реактивировал подписку, купив другой продукт. Apple сохраняет один и тот же `original_transaction_id` на протяжении всей цепочки «отмена → реактивация», поэтому событие отражает исходный продукт. Новый продукт появится в следующем событии `subscription_renewed`, когда начнётся списание за новый продукт. ::: ## Структура события вебхука \{#webhook-event-structure\} Adapty будет отправлять только те события, которые вы выбрали в разделе **Events names** на странице [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). События webhook сериализуются в JSON. Тело `POST`-запроса к вашему серверу будет содержать сериализованное событие, обёрнутое в структуру ниже. Все события следуют одной и той же структуре, но их поля различаются в зависимости от типа события, стора и вашей конкретной конфигурации. Атрибуты пользователя — это [пользовательские атрибуты](setting-user-attributes#custom-user-attributes), которые вы настроили, поэтому они содержат именно те данные, которые вы задали. Поля данных атрибуции одинаковы для всех типов событий, однако список атрибуций зависит от того, какие источники атрибуции вы используете в мобильном приложении. Ниже приведён пример события: ```json title="Json" showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem", "idfv": "00000000-0000-0000-0000-000000000000", "idfa": "00000000-0000-0000-0000-000000000000", "advertising_id": "00000000-0000-0000-0000-000000000000", "profile_install_datetime": "2000-01-31T00:00:00.000000+0000", "user_agent": "ExampleUserAgent/1.0 (Device; OS Version) Browser/Engine", "email": "john.doe@company.com", "event_type": "subscription_started", "event_datetime": "2000-01-31T00:00:00.000000+0000", "event_properties": { "store": "play_store", "currency": "USD", "price_usd": 4.99, "profile_id": "00000000-0000-0000-0000-000000000000", "cohort_name": "All Users", "environment": "Production", "price_local": 4.99, "original_price_usd": 4.99, "original_price_local": 4.99, "discount_amount_usd": 0, "discount_amount_local": 0, "base_plan_id": "b1", "developer_id": "onboarding_placement", "ab_test_name": "onboarding_ab_test", "ab_test_revision": 1, "paywall_name": "UsedPaywall", "proceeds_usd": 4.2315, "variation_id": "00000000-0000-0000-0000-000000000000", "purchase_date": "2024-11-15T10:45:36.181000+0000", "store_country": "AR", "event_datetime": "2000-01-31T00:00:00.000000+0000", "proceeds_local": 4.2415, "tax_amount_usd": 0, "transaction_id": "0000000000000000", "net_revenue_usd": 4.2415, "profile_country": "AR", "paywall_revision": "1", "profile_event_id": "00000000-0000-0000-0000-000000000000", "tax_amount_local": 0, "net_revenue_local": 4.2415, "vendor_product_id": "onemonth_no_trial", "profile_ip_address": "10.10.1.1", "consecutive_payments": 1, "rate_after_first_year": false, "original_purchase_date": "2000-01-31T00:00:00.000000+0000", "original_transaction_id": "0000000000000000", "subscription_expires_at": "2000-01-31T00:00:00.000000+0000", "profile_has_access_level": true, "profile_total_revenue_usd": 4.99, "promotional_offer_id": null, "store_offer_category": null, "store_offer_discount_type": null }, "event_api_version": 1, "profiles_sharing_access_level": [{"profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem"}], "attributions": { "appsflyer": { "ad_set": "Keywords 1.12", "status": "non_organic", "channel": "Google Ads", "ad_group": null, "campaign": "Social media influencers - Rest of the world", "creative": null, "created_at": "2000-01-31T00:00:00.000000+0000" } }, "user_attributes": {"Favourite_color": "Violet", "Pet_name": "Fluffy"}, "integration_ids": {"firebase_app_instance_id": "val1", "branch_id": "val2", "one_signal_player_id": "val3"}, "play_store_purchase_token": { "product_id": "product_123", "purchase_token": "token_abc_123", "is_subscription": true } } ``` ### Поля события \{#event-fields\} Параметры события одинаковы для всех типов событий. | **Поле** | **Тип** | **Описание** | |---|---|---| | **advertising_id** | UUID | Advertising ID (только Android). | | **attributions** | JSON | [Данные атрибуции](webhook-event-types-and-fields#attributions). Включается, если в [настройках вебхука](https://app.adapty.io/integrations/customwebhook) включён параметр **Send Attribution**. | | **customer_user_id** | String | ID пользователя из вашего приложения (UUID, email или другой идентификатор), если вы задаёте его в коде приложения при [идентификации пользователей](ios-quickstart-identify). Если пользователи не идентифицируются или конкретный пользователь анонимен (не вошёл в систему), поле равно `null`. | | **email** | String | Email пользователя, если вы задаёте его с помощью метода [`updateProfile`](setting-user-attributes) в SDK Adapty или при создании/обновлении профилей через серверный API. Если значение `email` не передаётся в метод SDK или API, поле равно `null`. | | **event_api_version** | Integer | Версия API Adapty (текущая: `1`). | | **event_datetime** | ISO 8601 | Фактическое (бизнес-) время события: например, дата покупки для события покупки или дата истечения для события истечения — не момент получения или отправки события в Adapty. Формат [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) (например, `2020-07-10T15:00:00.000000+0000`). Подробнее о порядке событий см. примечание ниже. | | **event_properties** | JSON | [Свойства события](webhook-event-types-and-fields#event-properties). | | **event_type** | String | Название события в формате Adapty. Полный список см. в разделе [Типы событий вебхука](webhook-event-types-and-fields#webhook-event-types). | | **idfa** | UUID | Advertising ID (только Apple). **IDFA** в профиле в [дашборде Adapty](https://app.adapty.io/profiles/users). Может быть `null`, если недоступен из-за ограничений отслеживания, детского режима или настроек конфиденциальности. | | **idfv** | UUID | Identifier for Vendors (IDFV), уникальный для каждого разработчика. **IDFV** в профиле в [дашборде Adapty](https://app.adapty.io/profiles/users). | | **integration_ids** | JSON | Идентификаторы интеграций пользователя, если вы задаёте их с помощью метода `setIntegrationIdentifier` в SDK Adapty или при создании/обновлении профилей через серверный API. `null`, если недоступно или интеграции отключены. | | **play_store_purchase_token** | JSON | [Токен покупки Play Store](webhook-event-types-and-fields#play-store-purchase-token). Включается, если в [настройках вебхука](https://app.adapty.io/integrations/customwebhook) включён параметр **Send Play Store purchase token**. | | **profile_id** | UUID | ID профиля, автоматически генерируемый Adapty для каждого профиля. Один Apple/Google ID может быть связан с разными profile ID, если пользователи не идентифицируются или совершают покупки до входа в систему. Подробнее о том, [как Adapty работает с родительскими и производными профилями](how-profiles-work#parent-and-inheritor-profiles). | | **profile_install_datetime** | ISO 8601 | Временная метка установки в формате [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) (например, `2020-07-10T15:00:00.000000+0000`). | | **profiles_sharing_access_level** | JSON | Список пользователей, [совместно использующих уровень доступа](general#6-sharing-paid-access-between-user-accounts), за исключением текущего профиля. Если совместное использование уровней доступа включено для вашего приложения, список содержит другие профили, привязанные к тому же Apple/Google ID.Хотя в коде мобильного приложения значения пользовательских атрибутов могут задаваться как float или строки, атрибуты, полученные через серверный API или исторический импорт, могут иметь другие форматы. В этом случае булевы и целочисленные значения будут преобразованы в float.
| :::note `event_datetime` отражает момент, когда событие произошло в жизненном цикле подписки, а не когда Adapty его обработал или доставил. Из-за этого события могут иметь одинаковое значение `event_datetime` или поступать не в хронологическом порядке. Например, событие `subscription_expired` может иметь более раннее значение `event_datetime`, чем событие `subscription_renewal_cancelled`, которое Adapty доставит раньше него. Не используйте `event_datetime` для упорядочивания событий. Вместо этого сортируйте события по времени получения на своей стороне и дедуплицируйте их с помощью `profile_event_id` или идентификаторов транзакций. ::: ### Атрибуции \{#attributions\} Чтобы отправлять данные атрибуции, включите опцию **Send Attribution** на странице [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). Если вы включили отправку данных атрибуции и настроили [интеграции атрибуции](attribution-integration), данные ниже будут отправляться вместе с событием для каждого источника. Одни и те же данные атрибуции отправляются для всех типов событий. ```json title="Json" showLineNumbers { "attributions": { "appsflyer": { "ad_set": "sample_ad_set_123", "status": "non_organic", "channel": "sample_channel", "ad_group": "sample_ad_group_456", "campaign": "sample_ios_campaign", "creative": "sample_creative_789", "created_at": "2000-01-31T00:00:00.000000+0000", "network_user_id": "0000000000000-0000000" } } } ``` | Название поля | Тип поля | Описание | | :------------------ | :------------ | :------------------------------------------------- | | **ad_set** | String | Рекламный набор атрибуции. | | **status** | String | Может быть `organic`, `non_organic,` или `unknown`. | | **channel** | String | Название маркетингового канала. | | **ad_group** | String | Рекламная группа атрибуции. | | **campaign** | String | Название маркетинговой кампании. | | **creative** | String | Ключевое слово креатива атрибуции. | | **created_at** | ISO 8601 date | Дата и время создания записи атрибуции. | | **network_user_id** | String | ID, присвоенный пользователю источником атрибуции. | ### Идентификаторы интеграций \{#integration-ids\} Следующие идентификаторы интеграций используются в событиях: - `adjust_device_id` - `airbridge_device_id` - `amplitude_device_id` - `amplitude_user_id` - `appmetrica_device_id` - `appmetrica_profile_id` - `appsflyer_id` - `branch_id` - `facebook_anonymous_id` - `firebase_app_instance_id` - `mixpanel_user_id` - `pushwoosh_hwid` - `one_signal_player_id` - `one_signal_subscription_id` - `tenjin_analytics_installation_id` - `posthog_distinct_user_id` ### Токен покупки Play Store \{#play-store-purchase-token\} Это поле содержит все данные, необходимые для повторной валидации покупки при необходимости. Оно отправляется только если включена опция **Send Play Store purchase token** в [настройках интеграции с Webhook](https://app.adapty.io/integrations/customwebhook). | Field | Type | Description | | :------------------ | :------ | :----------------------------------------------------------- | | **product_id** | String | Уникальный идентификатор продукта (SKU), приобретённого в Play Store. | | **purchase_token** | String | Токен, сгенерированный Google Play для уникальной идентификации транзакции покупки. | | **is_subscription** | Boolean | Указывает, является ли приобретённый продукт подпиской (`true`) или разовой покупкой (`false`). | ### Свойства событий \{#event-properties\} Свойства событий могут различаться в зависимости от типа события и даже между событиями одного типа. Например, событие из App Store не будет содержать Android-специфичные свойства, такие как `base_plan_id`. У события [Access Level Updated](webhook-event-types-and-fields#for-access-level-updated-event) есть особые свойства, поэтому мы выделили для него отдельный раздел. Аналогично, мы вынесли [Дополнительные свойства событий налогов и выручки](webhook-event-types-and-fields#additional-tax-and-revenue-event-properties) в отдельный раздел, поскольку они характерны лишь для отдельных типов событий. #### Для большинства типов событий \{#for-most-event-types\} Свойства событий для большинства типов событий одинаковы (кроме события **Access Level Updated**, которое описано в отдельном разделе). Ниже представлена подробная таблица свойств с указанием, к каким событиям они относятся. :::note Adapty конвертирует другие валюты в USD по курсу [currencylayer.com](https://currencylayer.com/) (обновляется каждые 8 часов). Курс **фиксируется на момент транзакции** — последующие изменения не влияют на результат конвертации. ::: | Поле | Тип | Описание | |:------------------------------|:--------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **ab_test_name** | String | Название [A/B-теста Adapty](ab-tests), в рамках которого произошла транзакция. | | **ab_test_revision** | Integer | Ревизия A/B-теста, в рамках которого произошла транзакция. | | **base_plan_id** | String | [Идентификатор базового плана](https://support.google.com/googleplay/android-developer/answer/12154973) в Google Play Store или [идентификатор цены](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) в Stripe. | | **cancellation_reason** | String |Возможные причины отмены: `voluntarily_cancelled`, `billing_error`, `price_increase`, `product_was_not_available`, `refund`, `cancelled_by_developer`, `new_subscription_replace`, `upgraded`, `unknown`, `adapty_revoked`.
Присутствует в следующих типах событий:
`subscription_cancelled`, `subscription_refunded` и `trial_cancelled`. | | **cohort_name** | String | Название [аудитории](audience), которая определила, какой пейвол был показан пользователю. | | **consecutive_payments** | Integer | Количество периодов, в течение которых пользователь подписан без перерывов. Включает текущий период. | | **currency** | String | Локальная валюта. | | **developer_id** | String | ID [плейсмента](placements), в рамках которого произошла транзакция. | | **discount_amount_local** | Float | Скидка, применённая к транзакции: стандартная цена минус фактически списанная сумма (до комиссии Apple/Google), в локальной валюте. `0` при покупке по полной цене. Для бесплатного пробного периода равна полной стандартной цене (`original_price_local`), так как ничего не списывается. `null`, если скидка применялась, но стандартная цена неизвестна (см. `original_price_local`). Всегда `null` для офферов App Store с единовременной предоплатой: единый платёж охватывает несколько расчётных периодов, поэтому его нельзя сравнить с ценой за отдельный период. | | **discount_amount_usd** | Float | Значение `discount_amount_local` в долларах США. | | **environment** | String | Возможные значения: `Sandbox` или `Production`. | | **event_datetime** | ISO 8601 date | Дата и время события. Совпадает со значением на корневом уровне события. | | **original_price_local** | Float | Стандартная цена продукта без скидки до комиссии Apple/Google, в локальной валюте. Для подписок — это цена продления. Равна `price_local` при покупке по полной цене и всегда равна `price_local` для разовых покупок, поскольку сторы не предоставляют отдельную стандартную цену для них. `null` при покупке со скидкой, если стор не возвращает достоверную стандартную цену (например, автопродление отключено, продление всё ещё содержит оффер или ожидается смена продукта). | | **original_price_usd** | Float | То же, что `original_price_local`, но в долларах США. | | **original_purchase_date** | ISO 8601 date | Для возобновляемых подписок исходная покупка — это первая транзакция в цепочке; её ID (original transaction ID) связывает всю цепочку продлений, а последующие транзакции являются её продолжением. Дата исходной покупки — это дата и время этой первой транзакции. | | **original_transaction_id** | String |Для возобновляемых подписок — это ID исходной транзакции, связывающий всю цепочку продлений. Исходная транзакция — первая в цепочке; последующие являются её продолжением.
Если продлений нет, `original_transaction_id` совпадает со `store_transaction_id`.
| | **paywall_name** | String | Название пейвола, в рамках которого произошла транзакция. | | **paywall_revision** | String | Ревизия пейвола, в рамках которого произошла транзакция. Значение по умолчанию — 1. | | **price_local** | Float | Сумма, списанная за транзакцию до комиссии Apple/Google, в локальной валюте. `null` для бесплатных пробных периодов, так как ничего не списывается. | | **price_usd** | Float | Сумма, списанная за транзакцию до комиссии Apple/Google, в долларах США. `null` для бесплатных пробных периодов, так как ничего не списывается. | | **profile_country** | String | Определяется Adapty на основе IP-адреса профиля. | | **profile_event_id** | UUID | Уникальный ID события, который можно использовать для дедупликации. | | **profile_has_access_level** | Boolean | Булевое значение, указывающее, есть ли у профиля активный уровень доступа. | | **profile_id** | UUID | ID профиля, сгенерированный Adapty. Совпадает со значением на корневом уровне события. | | **profile_ip_address** | String | IP-адрес профиля (может быть IPv4 или IPv6, при наличии предпочтение отдаётся IPv4). `null`, если опция **Collect users' IP addresses** отключена в [настройках приложения](https://app.adapty.io/settings/general). | | **profile_total_revenue_usd** | Float | Общий доход по профилю с вычетом возвратов. | | **promotional_offer_id** | String | Adapty ID использованного [promotional offer](offers). Этот ID задаётся при создании оффера в дашборде. | | **purchase_date** | ISO 8601 date | Дата и время покупки продукта. | | **rate_after_first_year** | Boolean | Булевое значение, указывающее, что подписка соответствует условиям пониженной комиссии (как правило, 15%) после одного года непрерывного продления. Ставки комиссии варьируются в зависимости от программы и страны. Подробнее см. в разделе [Комиссия стора и налоги](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue). | | **store** | String | Стор, в котором был куплен продукт. Стандартные значения: **app_store**, **play_store**, **stripe**, **paddle**.ID продукта в Apple App Store, Google Play Store или Stripe.
Если доступ был предоставлен без реальной транзакции в сторе, `vendor_product_id` принимает одно из следующих значений:
Для возобновляемых подписок это исходный идентификатор транзакции, связывающий цепочку продлений. Исходная транзакция — первая в цепочке; последующие являются её продолжением.
Если продлений не было, `original_transaction_id` совпадает со store_transaction_id.
Идентификатор транзакции первоначальной покупки. | | **paywall_name** | String | Название пейвола, в рамках которого была совершена транзакция. | | **paywall_revision** | String | Ревизия пейвола, в рамках которого была совершена транзакция. Значение по умолчанию — 1. | | **profile_country** | String | Определяется Adapty на основе IP-адреса профиля. | | **profile_event_id** | UUID | Уникальный идентификатор события, который можно использовать для дедупликации. | | **profile_has_access_level** | Boolean | Признак того, есть ли у профиля активный уровень доступа. | | **profile_id** | UUID | Внутренний идентификатор профиля пользователя в Adapty. | | **profile_ip_address** | String | IP-адрес профиля (может быть IPv4 или IPv6; IPv4 имеет приоритет при наличии). `null`, если **Collect users' IP addresses** отключено в [настройках приложения](https://app.adapty.io/settings/general). | | **profile_total_revenue_usd** | Float | Общий доход по профилю с учётом возвратов. | | **purchase_date** | ISO 8601 date | Дата и время покупки продукта. | | **renewed_at** | ISO 8601 date | Дата и время продления доступа. | | **starts_at** | ISO 8601 date | Дата и время начала уровня доступа. | | **store** | String | Стор, в котором был приобретён продукт. Стандартные значения: **app_store**, **play_store**, **stripe**, **paddle**.Идентификатор продукта в сторе (Apple/Google/Stripe).
Если доступ был предоставлен без реальной транзакции в сторе, `vendor_product_id` принимает одно из следующих значений:
1. **Вы настраиваете эндпоинт:** 1. Убедитесь, что ваш сервер может обрабатывать запросы Adapty с заголовком **Content-Type**, установленным в `application/json`. 2. Настройте сервер на получение верификационного запроса от Adapty и ответ с любым статусом `2xx` и телом в формате JSON. 3. [Обрабатывайте события подписки](#subscription-events) после подтверждения соединения. 2. **Вы настраиваете и включаете интеграцию с вебхуком** в [дашборде Adapty](#configure-webhook-integration-in-the-adapty-dashboard). Там же можно [сопоставить события Adapty с пользовательскими названиями событий](#configure-webhook-integration-in-the-adapty-dashboard). Рекомендуем сначала протестировать в среде **Sandbox**, прежде чем переходить на продакшн. 3. **Adapty отправляет верификационный запрос** на ваш сервер. 4. **Ваш сервер отвечает** статусом `2XX` и телом в формате JSON. 5. **После получения корректного ответа Adapty начинает отправлять события подписки.** ## Настройте сервер для обработки запросов от Adapty \{#set-up-your-server-to-process-adapty-requests\} Adapty будет отправлять на ваш webhook-эндпоинт запросы двух типов: 1. [Запрос верификации](#verification-request): первоначальный запрос, подтверждающий корректность настройки подключения. Он не содержит никаких событий и отправляется в момент нажатия кнопки **Save** в настройках интеграции Webhook в дашборде Adapty. Чтобы подтвердить успешное получение запроса верификации, ваш эндпоинт должен вернуть соответствующий ответ. 2. [Событие подписки](#subscription-events): стандартный запрос, который сервер Adapty отправляет каждый раз при создании нового события. Сервер не ожидает от вашего сервера никакого специального ответа — ему достаточно получить стандартный HTTP-ответ с кодом 200, подтверждающий успешное получение сообщения. ### Запрос верификации После того как вы включите интеграцию с вебхуком в дашборде Adapty, Adapty отправит POST-запрос верификации с пустым JSON-объектом `{}` в теле. Настройте эндпоинт так, чтобы **заголовок Content-Type** был `application/json`, то есть ваш сервер должен ожидать входящий вебхук-запрос с полезной нагрузкой в формате JSON. Ваш сервер должен ответить кодом статуса 2xx и вернуть любой валидный JSON, например: ```json title="Json" {} ``` После того как Adapty получит ответ верификации в правильном формате и с кодом статуса 2xx, интеграция вебхука Adapty будет полностью настроена. ### События подписок \{#subscription-events\} События подписок отправляются с заголовком **Content-Type** равным `application/json` и содержат данные события в формате JSON. Описание возможных типов событий и структур запросов см. в разделе [Типы и поля событий вебхука](webhook-event-types-and-fields). ## Настройка интеграции с вебхуком в дашборде Adapty \{#configure-webhook-integration-in-the-adapty-dashboard\} В Adapty можно настроить отдельные потоки для продакшн-событий и тестовых событий, получаемых из песочницы Apple или Stripe, либо из тестового аккаунта Google. :::tip Adapty поддерживает один URL вебхука на каждую среду (продакшн и песочница). Чтобы отправлять события в несколько сервисов, направьте вебхук на собственный бэкенд и раздавайте события уже оттуда. ::: Для production-событий используйте поле **Production endpoint URL**, указав URL, на который будут отправляться коллбэки. Также настройте поле **Authorization header value for production endpoint** — заголовок для аутентификации событий Adapty на вашем сервере. Обратите внимание: значение из поля **Authorization header value for production endpoint** будет использовано как заголовок `Authorization` ровно в том виде, в каком оно указано, без каких-либо изменений или дополнений. Для тестовых событий используйте поля **Sandbox endpoint URL** и **Authorization header value for sandbox endpoint** соответственно. Чтобы настроить интеграцию с вебхуком: 1. Откройте [Integrations -> Webhook](https://app.adapty.io/integrations/customwebhook) в дашборде Adapty.
2. Включите переключатель, чтобы активировать интеграцию.
4. Заполните поля интеграции:
| Поле | Описание |
| ------------------------------------------------------ | ------------------------------------------------------------ |
| **Production endpoint URL** | URL, на который Adapty отправляет HTTP POST-запросы для событий в продакшене. |
| **Authorization header value for production endpoint** | Заголовок, который ваш сервер будет использовать для аутентификации запросов от Adapty в продакшене. Значение из этого поля будет передано в заголовок `Authorization` ровно в том виде, в каком оно указано — без изменений и дополнений.
Хотя это поле не обязательно, настоятельно рекомендуем его заполнить для повышения безопасности.
| Кроме того, для тестирования в среде песочницы доступны ещё два поля: | Поле для тестирования | Описание | | --------------------------------------------------- | ------------------------------------------------------------ | | **Sandbox endpoint URL** | URL, на который Adapty отправляет HTTP POST-запросы для событий в среде песочницы. | | **Authorization header value for sandbox endpoint** |Заголовок, который ваш сервер будет использовать для аутентификации запросов от Adapty при тестировании в среде песочницы. Обратите внимание: значение из этого поля передаётся в заголовке `Authorization` ровно так, как указано, без каких-либо изменений или дополнений.
Хотя это поле не обязательно, настоятельно рекомендуем его заполнить для повышения безопасности.
| 4. (Опционально) Выберите события, которые хотите получать, и задайте их названия. Ознакомьтесь с разделом [Потоки событий](event-flows), чтобы узнать, какие события срабатывают в разных ситуациях. Если идентификаторы событий в вашей системе отличаются от используемых в Adapty, оставьте свои идентификаторы как есть и замените стандартные идентификаторы Adapty на ваши в разделе **Events names** на странице [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). ID события может быть любой строкой — главное, чтобы ID события на вашем сервере обработки вебхуков совпадал с тем, что вы указали в дашборде Adapty. Оставлять поле ID события пустым для включённых событий нельзя.
5. Дополнительные поля и параметры не обязательны — используйте их по мере необходимости:
| Настройка | Описание |
| :--------------------------------- | :----------------------------------------------------------- |
| **Send Trial Price** | Если включено, Adapty будет передавать цену подписки в полях `price_local` и `price_usd` для события **Trial Started**. |
| **Exclude Historical Events** | Позволяет исключить события, произошедшие до установки приложения с Adapty SDK. Это предотвращает дублирование событий и обеспечивает точную отчётность. Например, если пользователь активировал ежемесячную подписку 10 января, а обновил приложение с Adapty SDK 6 марта, Adapty пропустит события до 6 марта и сохранит последующие. |
| **Send user attributes** | Включите этот параметр, чтобы отправлять пользовательские атрибуты, например языковые настройки. Они будут отображаться в поле `user_attributes`. Подробнее см. в разделе [Поля события](webhook-event-types-and-fields#event-fields). |
| **Send attribution** | Включите этот параметр, чтобы добавлять данные атрибуции (например, данные AppsFlyer) в поле `attributions`. Подробнее см. в разделе [Данные атрибуции](webhook-event-types-and-fields#attributions). |
| **Send Play Store purchase token** | Включите этот параметр, чтобы получать токен Play Store, необходимый для повторной валидации покупок. После включения в событие добавится параметр `play_store_purchase_token`. Подробнее о его содержимом см. в разделе [Токен покупки Play Store](webhook-event-types-and-fields#play-store-purchase-token). |
6. Не забудьте нажать кнопку **Save**, чтобы сохранить изменения.
Как только вы нажмёте **Save**, Adapty отправит запрос верификации и будет ждать ответа от вашего сервера.
### Выберите события для отправки и настройте маппинг имён событий \{#choose-events-to-send-and-map-event-names\}
Выберите события, которые хотите получать на своём сервере, включив соответствующий тумблер. Если имена событий в вашей системе отличаются от используемых в Adapty, вы можете настроить маппинг — просто замените стандартные названия событий Adapty на собственные в разделе **Events names** на странице [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook).
Названием события может быть любая строка. Оставлять поля пустыми для включённых событий нельзя. Если вы случайно удалили название события Adapty, его всегда можно скопировать из раздела [События для отправки в сторонние интеграции](events).
## Обработка событий вебхука \{#handle-webhook-events\}
Вебхуки обычно доставляются в течение 5–60 секунд после события. Исключение — события отмены: они могут приходить с задержкой до 2 часов после того, как пользователь отменил подписку.
Если код ответа вашего сервера выходит за пределы диапазона 200–404, Adapty повторяет доставку с экспоненциальной задержкой. Первая попытка происходит примерно через **1 минуту** после первого сбоя, каждая следующая — вдвое позже. Всего до 9 попыток в течение 24 часов. Рекомендуем настроить вебхук так, чтобы перед ответом он выполнял только базовую валидацию тела события от Adapty. Если сервер не может обработать событие и вы не хотите повторных попыток от Adapty, используйте код ответа в диапазоне 200–404. Ресурсоёмкие задачи обрабатывайте асинхронно и отвечайте Adapty как можно быстрее. Если Adapty не получит ответ в течение 10 секунд, попытка считается неудачной и будет повторена.
---
# File: test-webhook
---
---
title: "Тестирование интеграции с webhook"
description: "Тестируйте интеграции с webhook в Adapty для автоматического отслеживания событий подписки."
---
После настройки интеграции пришло время её протестировать. Можно тестировать как интеграцию в песочнице, так и в продакшене. Рекомендуем начать с песочницы и максимально всё проверить на ней:
- События отправляются и успешно доставляются.
- Вы правильно настроили параметры для исторических событий, цену подписки для события **Trial started**, атрибуцию, пользовательские атрибуты и токен покупки Google Play Store — отправляются они с событием или нет.
- Вы правильно задали названия событий, и ваш сервер может их обрабатывать.
## Как тестировать \{#how-to-test\}
Перед началом тестирования убедитесь, что вы уже:
1. Настроили интеграцию с webhook, как описано в разделе [Настройка интеграции с webhook](set-up-webhook-integration).
2. Подготовили окружение, как описано в разделах [Тестирование встроенных покупок в Apple App Store](test-purchases-in-sandbox) и [Тестирование встроенных покупок в Google Play Store](testing-on-android). Убедитесь, что тестовое приложение собрано в окружении песочницы, а не в продакшене.
3. Совершили покупку / начали пробный период / оформили возврат — то есть выполнили действие, которое вызовет событие, выбранное для отправки на webhook. Например, чтобы получить событие **Subscription started**, оформите новую подписку.
## Проверка результата \{#validation-of-the-result\}
### Успешная отправка событий \{#successful-sending-events-result\}
При успешной интеграции событие появится в разделе **Last sent events** и будет иметь статус **Success**.
### Неудачная отправка событий \{#unsuccessful-sending-events-result\}
| Проблема | Решение |
|-----|--------|
| Событие не появилось | Покупка не была совершена, поэтому событие не было создано. Обратитесь к разделу [Устранение неполадок с тестовыми покупками](troubleshooting-test-purchases). |
| Событие появилось со статусом **Sending failed** | Доставка определяется на основе HTTP-статуса: всё **вне диапазона 200–399** считается ошибкой.
Чтобы узнать подробности, наведите курсор на статус **Sending failed** неудачного события, как показано ниже.
|
---
# File: handle-integration-errors
---
---
title: "Обработка ошибок в интеграциях"
description: "Обработка ошибок в интеграциях"
---
При использовании интеграций с атрибуцией, сервисами сообщений или аналитикой вы можете столкнуться с типичными ошибками. В этом гайде описаны способы их устранения.
## Расхождение данных \{#data-discrepancy\}
**Причина**: Это может происходить из-за того, что не все пользователи используют версию приложения с Adapty SDK.
**Решение**: Чтобы обеспечить согласованность данных, вы можете принудительно обновить приложение пользователей до версии с Adapty SDK.
## Сетевые ошибки \{#network-errors\}
**Причина**: Скорее всего, это связано с отсутствием интернет-соединения между сервером Adapty и сервером интеграции.
**Решение**: Такие проблемы обычно быстро проходят и затрагивают лишь небольшое число событий.
## Сервер интеграции не смог обработать событие \{#integration-server-failed-to-process-the-event\}
**Причина**: Интеграция настроена некорректно.
**Решение**: Обратитесь к статье об этой интеграции в нашей документации. Убедитесь, что вы выполнили все шаги настройки как в дашборде Adapty, так и на стороне стороннего инструмента и в коде приложения.
## Отсутствующие данные интеграции \{#missing-integration-data\}
**Причина**: В профиле отсутствует ID, специфичный для данной интеграции. Это может происходить, если интеграция настроена некорректно в коде приложения.
**Решение**: Обратитесь к статье об этой интеграции в нашей документации. Убедитесь, что вы реализовали методы из примеров кода в своём приложении и что эти методы действительно взаимодействуют с профилями пользователей.
## Отсутствующие учётные данные интеграции \{#missing-integration-credentials\}
**Причина**: Некоторые учётные данные интеграции отсутствуют или указаны неверно.
**Решение**: Проверьте все учётные данные для этой интеграции в дашборде Adapty. Проблема может быть связана с несоответствием версии или среды.
## Срок действия события истёк \{#the-event-has-expired\}
**Причина**: В настройках интеграции включена опция **Exclude historical events**, а дата создания события предшествует дате создания профиля в нашей системе.
Это может происходить, если цепочка транзакций, начавшаяся много лет назад, поступает в Adapty через валидацию чека для профиля, созданного недавно.
**Решение**: Убедитесь, что это не происходит для новых событий. Если вы хотите отправлять исторические события в интеграцию, отключите **Exclude historical events**.
## Отключённый или неподдерживаемый тип события \{#disabledunsupported-event-type\}
**Причина**: Либо это событие не поддерживается данной интеграцией, либо вы отключили его при настройке интеграции. Например, события `access_level_updated` не поддерживаются большинством интеграций.
**Решение**: Проверьте в документации интеграции, поддерживает ли она данный тип события. Если да, убедитесь в дашборде Adapty, что этот тип события включён в настройках интеграции.
---
# File: manage-adapty-with-ai
---
---
title: "Управление Adapty с помощью AI-агентов и инструментов разработки"
description: "Все способы использования Adapty с AI — интеграция SDK с помощью coding-агента, получение аналитики через LLM и передача документации Adapty в ваш AI-инструмент."
---
Adapty работает с AI-инструментами для разработки и агентами. Используйте их для интеграции SDK, получения ответов по аналитике или поиска в документации Adapty, не выходя из редактора. На этой странице перечислено всё доступное и для кого каждый инструмент предназначен.
## Интеграция SDK Adapty с помощью AI \{#integrate-the-adapty-sdk-with-ai\}
Два способа добавить SDK Adapty в приложение с помощью AI-инструмента для разработки. Оба работают с Cursor, Claude и другими AI-ассистентами.
### Интеграция на основе скилла \{#skill-based-integration\}
Скилл интеграции SDK Adapty выполняет всю интеграцию из вашего AI-инструмента одной командой. Используйте его, когда хотите пройти через настройку автоматически и с подсказками.
Выберите платформу: [iOS](adapty-sdk-integration-skill) · [Android](adapty-sdk-integration-skill-android) · [React Native](adapty-sdk-integration-skill-react-native) · [Flutter](adapty-sdk-integration-skill-flutter) · [Unity](adapty-sdk-integration-skill-unity) · [Kotlin Multiplatform](adapty-sdk-integration-skill-kmp) · [Capacitor](adapty-sdk-integration-skill-capacitor)
### Пошаговая интеграция \{#step-by-step-integration\}
Проведите AI-инструмент через интеграцию поэтапно, передавая нужную документацию в правильном порядке. Используйте этот способ, если хотите проверять каждый шаг по мере выполнения.
Выберите платформу: [iOS](adapty-cursor) · [Android](adapty-cursor-android) · [React Native](adapty-cursor-react-native) · [Flutter](adapty-cursor-flutter) · [Unity](adapty-cursor-unity) · [Kotlin Multiplatform](adapty-cursor-kmp) · [Capacitor](adapty-cursor-capacitor)
## Управление Adapty из командной строки \{#manage-adapty-from-the-command-line\}
[Adapty Developer CLI](developer-cli-quickstart) позволяет управлять сущностями Adapty — приложениями, уровнями доступа, продуктами, пейволами и плейсментами — из терминала, не открывая дашборд. Поскольку это инструмент командной строки, ваш AI coding-агент может запускать его напрямую.
## Запросы к вашим данным \{#ask-about-your-data\}
Направьте AI coding-агента на Export Analytics API, чтобы запрашивать ваши метрики на обычном языке — выручку, удержание, LTV и многое другое. Сервер MCP не нужен.
[Спросите AI о ваших аналитических данных](export-analytics-with-ai)
## Передача документации Adapty в AI-инструмент \{#give-your-ai-tool-the-adapty-docs\}
### Документация в виде обычного текста \{#plain-text-docs\}
Каждая страница документации Adapty доступна в формате Markdown — добавьте `.md` к URL страницы или нажмите **Copy for LLM** под заголовком. Для более широкого контекста передайте инструменту индекс [`llms.txt`](https://adapty.io/docs/ru/llms.txt) или платформенный подмножественный файл, например [`ios-llms.txt`](https://adapty.io/docs/ru/ios-llms.txt).
### Context7 \{#context7\}
[Context7](https://context7.com/adaptyteam/adapty-docs) — это MCP-сервер, который передаёт документацию Adapty в ваш AI-инструмент, однако индексирует только фрагменты кода, а не полный текст. Используйте его для быстрых примеров кода; для полного руководства передавайте инструменту документацию в виде обычного текста, описанную выше. Context7 работает с Cursor, Claude Code, Windsurf и другими инструментами, поддерживающими MCP.
---
# File: export-analytics-with-ai
---
---
title: "Задавайте вопросы ИИ о своей аналитике"
description: "Запрашивайте аналитику Adapty на естественном языке с помощью ИИ-агента, используя Export Analytics API."
---
Ask an AI coding agent about your Adapty analytics in plain language — revenue, conversions, retention, LTV — and let it pull the numbers for you. Point a tool that can make API calls at the [Export Analytics API](https://adapty.io/docs/ru/export-analytics-api.md), and it queries your metrics on demand.
## Что можно запрашивать \{#what-you-can-ask-about\}
Export Analytics API возвращает те же метрики, что вы видите на графиках дашборда Adapty. Для каждой метрики предусмотрена отдельная операция:
| Метрика | Что охватывает | Операция |
| --- | --- | --- |
| Revenue, MRR, ARR, ARPU | Деньги, заработанные за период, сгруппированные по периоду, стране или кампании | [retrieveAnalyticsData](https://adapty.io/docs/ru/api-export-analytics/operations/retrieveAnalyticsData.md) |
| Удержание когорты | Как долго подписчики из данной когорты продолжают платить | [retrieveCohortData](https://adapty.io/docs/ru/api-export-analytics/operations/retrieveCohortData.md) |
| Конверсии | Сколько пользователей переходит с одного шага или канала на следующий | [retrieveConversionData](https://adapty.io/docs/ru/api-export-analytics/operations/retrieveConversionData.md) |
| Отток и воронка | Где пользователи отваливаются и как быстро отписываются | [retrieveFunnelData](https://adapty.io/docs/ru/api-export-analytics/operations/retrieveFunnelData.md) |
| Пожизненная ценность (LTV) | Средняя выручка на пользователя по сегментам за период | [retrieveLTVData](https://adapty.io/docs/ru/api-export-analytics/operations/retrieveLTVData.md) |
| Удержание | Доля пользователей, остающихся активными спустя N дней | [retrieveRetentionData](https://adapty.io/docs/ru/api-export-analytics/operations/retrieveRetentionData.md) |
Полный список параметров и фильтров см. в [справочнике API](https://adapty.io/docs/ru/api-export-analytics.md).
## Прежде чем начать \{#before-you-start\}
Вам понадобятся три вещи:
- **Аккаунт Adapty с данными**: API возвращает те же метрики, что и графики на дашборде, поэтому ваше приложение должно уже собирать аналитику.
- **Секретный API-ключ**: Найдите его в [App settings → General](https://app.adapty.io/settings/general), в поле **Secret key**. Ключи привязаны к конкретному приложению, поэтому используйте отдельный ключ для каждого из них. Сохраните ключ в переменную окружения (например, `ADAPTY_SECRET_KEY`), чтобы агент мог его считать без необходимости вставлять в чат вручную.
- **AI-инструмент с возможностью вызова API**: Например, Claude Code, Cursor или Claude Desktop с инструментом fetch. Обычные чат-инструменты вроде claude.ai или ChatGPT не могут напрямую обращаться к API.
## Дайте агенту спецификацию API \{#give-your-agent-the-api-spec\}
[Спецификация OpenAPI](https://adapty.io/docs/ru/api-specs/export-analytics-api.yaml) описывает все эндпоинты, заголовок аутентификации, тело запроса и примеры ответов. Получив спецификацию, агент самостоятельно формирует корректные запросы — без написания кода с вашей стороны.
Передайте агенту спецификацию по URL:
- **Вставьте URL**: Если ваш агент умеет загружать URL, дайте ему `https://adapty.io/docs/ru/api-specs/export-analytics-api.yaml` и попросите прочитать спецификацию.
- **Используйте инструмент fetch**: Если у вашего агента есть инструмент для загрузки URL (например, MCP fetch server), укажите ему тот же URL.
Спецификация задаёт базовый URL `https://api-admin.adapty.io`, так что агенту будет достаточно этого, как только ключ окажется в переменных окружения.
## Задайте вопрос о своих данных \{#ask-about-your-data\}
Загрузив спецификацию и указав ключ в переменной окружения, описывайте нужную метрику на обычном языке.
Примеры запросов:
```
What was my MRR at the end of each month this year, and how does it compare to last year?
Show my trial-to-paid conversion rate for the last 90 days, broken down by product.
Which countries drive the most revenue from my yearly subscription? Top 10.
How is week-1 retention trending for subscribers who started in the last 6 months?
What's the refund rate on my annual plan since launch, by month?
Compare LTV for paid-campaign users vs. organic over the last year, and export it as CSV.
```
Агент сопоставляет ваш запрос с нужной операцией, считывает ключ из переменной окружения и возвращает данные. По умолчанию ответы возвращаются в формате JSON. Попросите CSV, если вам нужен файл для таблиц — агент передаст `format` со значением `csv` в теле запроса.
:::warning
Храните секретный ключ в переменной окружения — не вставляйте его в чат и не коммитьте в файл правил. Ключи привязаны к конкретному приложению, поэтому при утечке пересоздайте ключ в **Settings → General**. См. [ротация API-ключей](https://adapty.io/docs/ru/export-analytics-api-authorization.md).
:::
## Настройте один раз для повторного использования \{#set-up-once-for-repeated-use\}
Чтобы не повторять настройку каждый раз, сохраните спецификацию и ключ там, где агент сможет их повторно использовать:
- **Сохраните ссылку на спецификацию**: добавьте URL спецификации в правила или файл памяти вашего агента (например, `CLAUDE.md` или файл правил Cursor), чтобы он загружался при каждой сессии.
- **Храните ключ в переменных окружения**: добавьте `ADAPTY_SECRET_KEY` в профиль shell или хранилище секретов инструмента, чтобы больше не вводить его вручную.
- **Сохраните часто используемые промпты или создайте кастомный скилл**: держите типовые вопросы в виде сохранённых промптов или оберните их в кастомный скилл или slash-команду, чтобы агент запускал отчёт по запросу.
## Ограничения \{#limits\}
Учитывайте следующие ограничения:
- **Ограничение частоты запросов**: API допускает 2 запроса в секунду на один API-ключ. При превышении лимита возвращается ошибка `429 Too Many Requests`. Настройте агент так, чтобы он ждал и повторял запрос при получении `429`.
- **Ключи привязаны к приложению**: Каждый ключ работает только с одним приложением. Чтобы получать данные из нескольких приложений, используйте соответствующий ключ для каждого из них.
- **Формат ответа**: По умолчанию ответы возвращаются в формате JSON. Чтобы экспортировать данные в CSV, укажите `format` со значением `csv` в теле запроса.
Полное описание аутентификации и правил формирования запросов см. в разделе [Авторизация и формат запроса](https://adapty.io/docs/ru/export-analytics-api-authorization.md).
---
# File: handle-webhooks-with-ai
---
---
title: "Обработка событий подписки Adapty с помощью вебхуков"
description: "Получайте и обрабатывайте события подписки Adapty на своём сервере с помощью вебхуков — настройка эндпоинта, аутентификация, полезная нагрузка и тестирование на одной странице."
---
Вебхуки позволяют вашему серверу получать события подписок Adapty в режиме реального времени — покупки, продления, отмены, проблемы с оплатой и возвраты — чтобы вы могли предоставлять доступ, синхронизировать бэкенд или запускать рабочие процессы. Этот гайд проведёт вас от настройки эндпоинта до проверенной, протестированной интеграции на одной странице, а также покажет, как поручить написание обработчика AI-агенту.
:::tip
Используете AI-агент? Нажмите **Copy for LLM** под заголовком и вставьте всю страницу в агент — там есть всё необходимое: настройка, формат payload и логика обработчика.
:::
## Как работают вебхуки Adapty \{#how-adapty-webhooks-work\}
- **Однонаправленные и в реальном времени**: Adapty отправляет HTTP `POST` на ваш сервер при наступлении события — никакого поллинга.
- **Два типа запросов**: Одноразовый запрос верификации (отправляется при сохранении интеграции) и текущие события подписки.
- **Один URL на окружение**: Вы настраиваете отдельный эндпоинт для продакшена и для песочницы.
- **Подтверждение каждого запроса**: Ответьте статусом `2xx` как можно быстрее — при сбое Adapty повторит попытку.
## Создайте свой endpoint \{#build-your-endpoint\}
Создайте публичный HTTPS-endpoint, который обрабатывает два типа запросов:
- **Verification request**: отправляется один раз при сохранении интеграции. Тело запроса — пустой JSON (`{}`). В ответ верните статус `2xx` и тело в формате JSON.
- **Subscription events**: постоянные `POST`-запросы с событием в теле. Верните `200` в течение 10 секунд, а всю тяжёлую работу выполняйте асинхронно.
Выберите секретную строку и сохраните её как переменную окружения (например, `ADAPTY_WEBHOOK_SECRET`). При каждом запросе проверяйте, совпадает ли заголовок `Authorization` с ней, и отклоняйте запрос, если нет — тот же секрет вы введёте в дашборде чуть позже.
```javascript title="webhook.js"
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.ADAPTY_WEBHOOK_SECRET;
app.post("/adapty/webhook", (req, res) => {
// 1. Verify the shared secret Adapty echoes back.
if (req.get("Authorization") !== WEBHOOK_SECRET) {
return res.sendStatus(401);
}
// 2. Acknowledge fast, then process asynchronously.
res.status(200).json({});
// 3. The verification request has an empty body — nothing to handle.
const event = req.body;
if (!event.event_type) return;
switch (event.event_type) {
case "subscription_started":
case "subscription_renewed":
case "trial_converted":
// Grant or extend access.
break;
case "subscription_expired":
case "subscription_refunded":
// Revoke access.
break;
default:
break;
}
});
app.listen(3000);
```
Задеплойте эндпойнт на публичный HTTPS-адрес до того, как настраивать интеграцию — Adapty отправляет запрос верификации в момент сохранения.
### Ключевые события и их содержимое \{#key-events-and-the-payload\}
Все события используют одну и ту же оболочку. Набор полей зависит от типа события, стора и включённых вами настроек. Ниже приведён сокращённый пример события `subscription_started`:
```json title="Example event"
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": "UserIdInYourSystem",
"event_type": "subscription_started",
"event_datetime": "2024-11-15T10:45:36.181000+0000",
"event_properties": {
"store": "play_store",
"currency": "USD",
"price_usd": 4.99,
"vendor_product_id": "onemonth_no_trial",
"transaction_id": "0000000000000000",
"original_transaction_id": "0000000000000000",
"subscription_expires_at": "2024-12-15T10:45:36.181000+0000",
"profile_event_id": "00000000-0000-0000-0000-000000000000"
},
"event_api_version": 1
}
```
Самые частые события, с которыми вам придётся работать:
| Тип события | Срабатывает когда |
| --- | --- |
| `subscription_started` | Пользователь оформляет платную подписку |
| `subscription_renewed` | Подписка успешно продлевается и списывается оплата |
| `subscription_renewal_cancelled` | Пользователь отключает автопродление (доступ сохраняется до истечения срока) |
| `subscription_expired` | Доступ прекращается после окончания не продлённой подписки |
| `trial_started` | Пользователь начинает бесплатный пробный период |
| `trial_converted` | Пробный период конвертируется в платную подписку |
| `billing_issue_detected` | Платёж за продление не проходит |
| `subscription_refunded` | Покупка подписки возвращается |
Полный список событий и все поля описаны в разделе [Типы и поля событий вебхука](https://adapty.io/docs/ru/webhook-event-types-and-fields.md).
:::warning
Не сортируйте события по `event_datetime` — это бизнес-время события, поэтому события могут приходить не по порядку или иметь одинаковую временну́ю метку. Сортируйте по времени получения на вашей стороне и устраняйте дубликаты с помощью `profile_event_id` или идентификаторов транзакций.
:::
## Настройте вебхук в Adapty \{#configure-the-webhook-in-adapty\}
1. Откройте [Integrations → Webhook](https://app.adapty.io/integrations/customwebhook) в дашборде Adapty.
2. Включите интеграцию.
3. В поле **Production endpoint URL** введите HTTPS URL задеплоенного эндпоинта.
4. В поле **Authorization header value for production endpoint** введите тот же секрет, который проверяет ваш эндпоинт. Adapty отправляет это значение в заголовке `Authorization` с каждым запросом. Поле необязательное, но мы настоятельно рекомендуем его заполнить.
5. Чтобы сначала протестировать в песочнице, заполните **Sandbox endpoint URL** и соответствующее поле **Authorization header value**.
6. Нажмите **Save**. Adapty сразу отправит верификационный запрос на эндпоинт, который должен ответить кодом `2xx` — это завершит настройку.
Чтобы выбрать события для отправки, настроить названия событий или включить дополнительные поля (цена триала, исторические события, атрибуция, атрибуты пользователя, токен Play Store), см. [Настройка интеграции с вебхуком](https://adapty.io/docs/ru/set-up-webhook-integration.md).
## Создайте обработчик с помощью AI-агента \{#build-it-with-your-ai-coding-agent\}
Передайте вашему AI-агенту этот гайд и справочную документацию в формате Markdown (добавьте `.md` к любому URL страницы), укажите ваш стек и дайте ему сгенерировать обработчик:
- [Типы событий и поля вебхука](https://adapty.io/docs/ru/webhook-event-types-and-fields.md)
- [Настройка интеграции с вебхуком](https://adapty.io/docs/ru/set-up-webhook-integration.md)
Пример промпта:
```
Read these Adapty webhook docs, then write a webhook handler for my Express app:
verify the Authorization header against ADAPTY_WEBHOOK_SECRET, answer the
verification request, acknowledge events with 200, and grant or revoke access
based on event_type.
```
The agent writes the handler code, but it can't deploy your endpoint or configure the dashboard — host the endpoint yourself and set the URL and secret in **Integrations → Webhook**.
## Протестируйте вебхук \{#test-your-webhook\}
Перед запуском в продакшн протестируйте в песочнице:
1. Настройте эндпоинт и секрет для песочницы, как описано выше.
2. В приложении для песочницы совершите покупку, запустите триал или оформите возврат, чтобы вызвать событие.
3. Откройте раздел **Last sent events** интеграции. Доставленное событие отображается со статусом **Success**.
Если событие показывает **Sending failed**, ваш сервер вернул статус вне диапазона 200–399 — наведите курсор на статус для получения подробностей. Полное руководство по тестированию см. в разделе [Тест интеграции с вебхуком](https://adapty.io/docs/ru/test-webhook.md).
## Ограничения \{#limits\}
- **Подтверждение в течение 10 секунд**: если Adapty не получает ответ вовремя, попытка считается неудачной и повторяется.
- **Повторные попытки**: если статус ответа выходит за пределы диапазона 200–404, Adapty повторяет запрос с экспоненциальной задержкой — до 9 повторов в течение 24 часов.
- **Задержка отмены**: события об отмене могут поступать с задержкой до 2 часов.
- **Один URL на окружение**: чтобы доставлять события в несколько сервисов, направьте вебхук на свой бэкенд и распределяйте их уже оттуда.
---
# File: server-side-api-with-ai
---
---
title: "Проверка и предоставление доступа к подписке через бэкенд"
description: "Используйте серверный API Adapty, чтобы проверить наличие активной подписки у пользователя и предоставить доступ вручную с помощью AI-агента."
---
Используйте серверный API Adapty, чтобы из вашего бэкенда проверять наличие активной подписки у пользователя и вручную выдавать доступ. В этом гайде рассмотрены два самых распространённых запроса — `getProfile` и `grantAccessLevel` — и показано, как поручить AI-агенту написать интеграцию под ваш стек.
:::tip
Используете AI-агент? Нажмите **Copy for LLM** под заголовком и вставьте всю эту страницу в агент — там есть все вызовы, поля и важные нюансы.
:::
## Прежде чем начать \{#before-you-start\}
- **Секретный ключ API**: Найдите его в [App settings → General](https://app.adapty.io/settings/general), в поле **Secret key**. Ключи привязаны к конкретному приложению. Сохраните его в переменную окружения (например, `ADAPTY_SECRET_KEY`) и передавайте в заголовке `Authorization: Api-Key {key}`.
- **Базовый URL**: Все запросы отправляются на `https://api.adapty.io`.
- **Способ идентифицировать пользователя**: Передавайте либо `adapty-customer-user-id` (ваш собственный идентификатор пользователя — работает только если вы идентифицируете пользователей в приложении), либо `adapty-profile-id` (идентификатор профиля Adapty). Они взаимозаменяемы — используйте любой из них.
## Проверка подписки \{#check-a-subscription\}
Чтобы проверить статус, вызовите `getProfile` с методом `GET` и передайте идентификатор пользователя в заголовке — тело запроса не требуется.
```javascript title="check-access.js"
const res = await fetch("https://api.adapty.io/api/v2/server-side-api/profile/", {
headers: {
"Authorization": `Api-Key ${process.env.ADAPTY_SECRET_KEY}`,
"adapty-customer-user-id": userId,
},
});
const { data } = await res.json();
function hasActiveAccess(profile, accessLevelId = "premium") {
const level = profile.access_levels?.find(a => a.access_level_id === accessLevelId);
if (!level) return false;
if (level.is_in_grace_period) return true;
if (!level.expires_at) return true; // lifetime / non-expiring
return new Date(level.expires_at) > new Date(); // not expired yet
}
if (hasActiveAccess(data)) {
// unlock premium features
}
```
В отличие от профиля в SDK, серверный ответ **не содержит поля `is_active`**. Определяйте статус самостоятельно по `access_levels[].expires_at`: `null` означает пожизненный доступ, дата в будущем — активная подписка, дата в прошлом — истёкшая. Считайте `is_in_grace_period` активным состоянием. Полное описание полей профиля и уровней доступа см. в [getProfile](https://adapty.io/docs/ru/api-adapty/operations/getProfile.md).
## Предоставление доступа вручную \{#grant-access-manually\}
Чтобы разблокировать платные функции без покупки — промокоды, доступ для инвесторов или бета-тестеров, решение обращений в поддержку — вызовите `grantAccessLevel` через `POST`.
```javascript title="grant-access.js"
await fetch("https://api.adapty.io/api/v2/server-side-api/purchase/profile/grant/access-level/", {
method: "POST",
headers: {
"Authorization": `Api-Key ${process.env.ADAPTY_SECRET_KEY}`,
"adapty-customer-user-id": userId,
"Content-Type": "application/json",
},
body: JSON.stringify({ access_level_id: "premium" }), // add "expires_at" for temporary access
});
```
- **Уровень доступа должен уже существовать** в вашем дашборде (**Access levels**) — `access_level_id` это его идентификатор, а не новое имя.
- **Ручные выдачи не отображаются в аналитике**. Они доставляются только в вебхук-интеграцию и Event Feed, поэтому в графиках доходов и конверсий они не учитываются.
Подробнее о запросе и ответе см. [grantAccessLevel](https://adapty.io/docs/ru/api-adapty/operations/grantAccessLevel.md).
## Создайте это с помощью AI-агента
Передайте своему AI-агенту этот гайд и спецификацию API в формате Markdown (добавьте `.md` к любому URL страницы), укажите свой стек — и пусть он напишет вызовы:
- [Спецификация OpenAPI](https://adapty.io/docs/ru/api-specs/adapty-api.yaml)
- [getProfile](https://adapty.io/docs/ru/api-adapty/operations/getProfile.md)
- [grantAccessLevel](https://adapty.io/docs/ru/api-adapty/operations/grantAccessLevel.md)
Пример промпта:
```
Using the Adapty server-side API spec, write backend functions to check whether a
user has an active "premium" access level (GET /profile/, derive status from
expires_at — there's no is_active field) and to grant it (grantAccessLevel).
Authenticate with ADAPTY_SECRET_KEY and identify users by adapty-customer-user-id.
```
The agent writes the code, but it can't run your backend or set your keys — you provide the secret key and the user identifiers.
## Ограничения \{#limits\}
- **Лимит запросов**: до 40 000 запросов в минуту на приложение.
- **Ключи привязаны к приложению**: каждый ключ работает только для одного приложения — используйте соответствующий ключ для каждого из них.
- **Обязательный идентификатор**: каждый запрос должен содержать `adapty-customer-user-id` или `adapty-profile-id`.
---
# File: test-purchases-in-sandbox
---
---
title: "Тестирование в песочнице"
description: "Тестируйте покупки в среде песочницы для обеспечения бесперебойных транзакций."
---
Когда вы настроили всё в дашборде Adapty и своём мобильном приложении, самое время протестировать встроенные покупки.
**Примечание:** ни один из тестовых инструментов не списывает деньги с пользователей при тестировании покупки продукта. App Store не отправляет письма о покупках или возвратах, совершённых в тестовых средах.
:::note
**Транзакции из песочницы не отображаются в аналитических графиках.** Они по-прежнему видны на страницах отдельных профилей и в ленте событий.
:::
:::info
Перед тестированием встроенных покупок убедитесь, что:
- Вы прошли гайды по [быстрому старту](quickstart): интеграция стора, добавление продуктов и интеграция SDK Adapty.
- Ваш продукт имеет статус [**Ready to submit**](InvalidProductIdentifiers#step-2-check-products) в App Store Connect.
:::
## Тестирование в песочнице \{#sandbox-testing\}
3. Нажмите **Create**.
### Шаг 2. Включите режим разработчика \{#step-2-enable-the-developer-mode\}
:::note
Пропустите этот шаг, если режим разработчика **уже включён** на вашем тестовом устройстве или если у вас **нет Mac**.
:::
Вам понадобится Mac с установленным Xcode и кабель для тестового устройства:
1. Откройте Xcode на Mac. Если вы планируете тестировать встроенные покупки через TestFlight, достаточно просто иметь установленный Xcode — открытый проект приложения не нужен.
2. Подключите тестовое устройство к Mac с помощью кабеля.
3. На тестовом устройстве перейдите в **Settings > Privacy & Security > Developer Mode** и включите **Developer Mode**.
### Шаг 3. Скачайте приложение из TestFlight \{#step-3-download-the-app-from-testflight\}
:::info
Этот шаг применим только при тестировании через TestFlight. Если вы собираете приложение в Xcode, пропустите его.
:::
Подробнее о том, как отправить приложение в TestFlight, читайте в [документации Apple](https://developer.apple.com/documentation/StoreKit/testing-in-app-purchases-with-sandbox#Prepare-for-sandbox-testing).
Перед загрузкой приложения через TestFlight убедитесь, что на тестовом устройстве выполнен вход с вашим реальным Apple Account. Затем скачайте тестируемое приложение из TestFlight.
:::danger
Не открывайте приложение после загрузки. Просто переходите к следующим шагам.
Если вы случайно открыли его, удалите с тестового устройства и загрузите снова. Иначе история покупок может оказаться не чистой, и тестирование встроенных покупок приведёт к ошибкам.
:::
### Шаг 4. Переключитесь на тестовый аккаунт Sandbox \{#step-4-switch-to-sandbox-test-account\}
4. Прокрутите вниз до раздела **Sandbox Apple Account** и нажмите **Sign In**.
5. Войдите, используя данные вашего Sandbox Apple Account.
### Шаг 5. Очистите историю покупок \{#step-5-clear-purchase-history\}
Если вы только что создали новый тестовый аккаунт в песочнице и переключились на него, этот шаг можно пропустить — он актуален только при повторном тестировании с одним и тем же тестовым аккаунтом.
1. Перейдите в **Settings > Developer > Sandbox Apple Account** на тестовом устройстве.
2. Выберите **Manage** во всплывающем меню.
3. Перейдите в **Account Settings** и нажмите **Clear Purchase History**.
:::danger
Этот шаг обязателен каждый раз, когда вы повторно тестируете с одним и тем же тестовым аккаунтом песочницы. В этом случае также нужно [выйти из тестового аккаунта песочницы](#step-4-switch-to-sandbox-test-account), а затем войти снова, чтобы очистить кеш истории покупок на тестовом устройстве.
:::
### Шаг 6. Сборка в Xcode и запуск \{#step-6-build-in-xcode-and-run\}
:::info
Этот шаг актуален только при тестировании через сборку Xcode. Если вы используете TestFlight, пропустите его.
:::
1. Подключите тестовое устройство к Mac.
2. Откройте Xcode.
3. Нажмите **Run** на панели инструментов или выберите **Product > Run**, чтобы собрать приложение и запустить его на подключённом устройстве.
Если сборка прошла успешно, Xcode запустит приложение на устройстве и откроет сеанс отладки в области отладки.
Теперь приложение готово к тестированию на устройстве.
### Шаг 7. Совершите тестовую покупку \{#step-7-make-test-purchase\}
Откройте приложение и совершите тестовую покупку через пейвол.
После этого перейдите к статье о [проверке тестовых покупок](validate-test-purchases), чтобы убедиться, что всё работает корректно.
### Шаг 8. Продолжайте тестирование \{#step-8-keep-testing\}
Тестовая среда готова к работе. Если хотите протестировать снова, [очистите историю покупок тестового аккаунта в песочнице](https://developer.apple.com/help/app-store-connect/test-in-app-purchases/manage-sandbox-apple-account-settings/).
## Проблемы при тестировании \{#testing-issues\}
Ниже перечислены распространённые проблемы, с которыми вы можете столкнуться при тестировании приложения.
### Проблемы с TestFlight \{#testflight-issues\}
Очистить историю покупок **при использовании TestFlight без тестового аккаунта Sandbox** невозможно, что приводит к различным проблемам и некорректным результатам тестирования.
Если вы случайно забыли [переключиться на тестовый аккаунт Sandbox](#step-4-switch-to-sandbox-test-account) и хотя бы раз открыли приложение, TestFlight привяжет историю покупок к вашему основному Apple Account, что вызовет непредвиденные проблемы.
Чтобы исправить это, выполните следующие шаги:
1. Удалите приложение с тестового устройства.
2. Следуйте инструкциям по [тестированию в Sandbox](#sandbox-testing).
:::note
Важно не только переустановить приложение, но и переключиться на тестовый аккаунт Sandbox, очистить историю покупок и запустить приложение под этим тестовым аккаунтом.
:::
### Проблемы с общими уровнями доступа \{#shared-access-levels-issues\}
Если вы повторно тестируете с одним и тем же Sandbox-аккаунтом, у тестового пользователя может возникнуть неожиданное поведение с [общими уровнями доступа](sharing-paid-access-between-user-accounts).
Чтобы проверить, унаследовал ли пользователь уровень доступа, откройте [Profiles & Segments](https://app.adapty.io/profiles/users) в дашборде Adapty и перейдите в профиль пользователя.
Если у пользователя унаследованный уровень доступа, для получения точных результатов тестирования выполните следующие шаги:
1. Удалите родительский профиль.
2. Удалите приложение с тестового устройства.
3. [Загрузите приложение из TestFlight](#step-3-download-the-app-from-testflight).
4. [Переключитесь на тестовый аккаунт Sandbox](#step-4-switch-to-sandbox-test-account).
5. [Очистите историю покупок](#step-5-clear-purchase-history).
6. [Откройте приложение и сделайте тестовую покупку](#step-6-make-test-purchase).
:::note
Очистка истории покупок сбрасывает покупку на стороне стора. Удаление родительского профиля удаляет только запись на стороне Adapty. О том, почему повторно используемый аккаунт сохраняет доступ и какие действия по сбросу действительно работают, читайте в разделе [Сброс подписки тестировщика](#resetting-a-testers-subscription).
:::
### Обновление приложения в TestFlight \{#updating-app-in-testflight\}
Если приложение в TestFlight было обновлено:
1. Удалите приложение с тестового устройства.
2. [Загрузите приложение из TestFlight](#step-3-download-the-app-from-testflight).
3. [Переключитесь на тестовый аккаунт песочницы](#step-4-switch-to-sandbox-test-account).
4. [Очистите историю покупок](#step-5-clear-purchase-history).
5. [Откройте приложение и выполните тестовую покупку](#step-6-make-test-purchase).
## Сброс подписки тестировщика \{#resetting-a-testers-subscription\}
В среде песочницы покупка привязана к **аккаунту Apple sandbox**, а не к профилю Adapty. Действия с профилем — его удаление или изменение уровня доступа — не удаляют покупку из аккаунта стора. При следующей переустановке или синхронизации SDK повторно привяжет ту же транзакцию, и тестировщик снова получит доступ.
В таблице ниже показано, что именно меняет каждое действие по сбросу и что тестировщик увидит после него.
| Действие | Профиль Adapty | Аккаунт Apple sandbox | Доступ тестировщика после |
| :-------------------------------------------------------------------------------- | :------------------------------------------------------ | :--------------------- | :------------------------------------------------------------------------------------------------- |
| Удалить профиль в дашборде Adapty | Удалён | Не затронут | **Возвращается** — при переустановке новый профиль заново привязывает ту же цепочку транзакций |
| Удалить профиль через [Delete profile API](api-adapty/operations/deleteProfile) | Удалён | Не затронут | **Возвращается** — то же, что при удалении в дашборде |
| Добавить прошедшую дату истечения через **Add access level** | Перезаписывается при следующей синхронизации | Не затронут | **Возвращается** при следующем обновлении — активная подписка применяет будущую дату истечения |
| Вызвать [Revoke access level API](api-adapty/operations/revokeAccessLevel) | Истекает сейчас, генерирует событие `access_level_updated` (`is_active=false`) | Не затронут | **Возвращается** при следующем обновлении или переустановке — ненадёжный сброс для песочницы |
| Отменить подписку в аккаунте sandbox | Прямых изменений нет | Подписка отменена | Обновления прекращаются, доступ заканчивается по истечении текущего периода, тестировщик может купить продукт снова |
| Войти с новым аккаунтом Apple sandbox | Новый профиль | Новый, пустой аккаунт | **Чистый** — рекомендуется для повторного тестирования |
### Сброс тестировщика к чистому состоянию \{#reset-a-tester-to-a-clean-state\}
Для повторного тестирования флоу покупок используйте новый аккаунт песочницы Apple для каждого теста вместо сброса профиля. Следуйте [Шагу 1](#step-1-create-sandbox-test-account-in-app-store-connect), чтобы создать аккаунт, и [Шагу 4](#step-4-switch-to-sandbox-test-account), чтобы переключиться на него на устройстве. Если вы повторно используете существующий аккаунт песочницы, сначала [очистите историю покупок](#step-5-clear-purchase-history) — удаление профиля Adapty её не очищает.
### Отзыв доступа у существующего тестировщика \{#remove-access-from-an-existing-tester\}
Чтобы отозвать доступ у тестировщика, не нужно задним числом менять дату истечения или вызывать API отзыва уровня доступа. В песочнице подписка автоматически обновляется каждые несколько минут, и каждое обновление восстанавливает будущую дату истечения в рамках той же цепочки транзакций — то есть доступ возвращается сам по себе. API отзыва уровня доступа действительно генерирует событие `access_level_updated` (`is_active=false`), но следующее обновление подписки его перезаписывает.
Чтобы действительно закрыть доступ, отмените подписку на стороне стора. На тестовом устройстве перейдите в **Settings > Developer > Sandbox Apple Account**, выберите **Manage** и отмените подписку. Продления прекратятся, а доступ закроется по истечении текущего периода.
### Почему удаление профиля возвращает доступ \{#why-deleting-the-profile-brings-access-back\}
Когда тестировщик переустанавливает приложение, Adapty получает историю покупок аккаунта песочницы и привязывает новую установку к существующей покупке. Покупка привязана к аккаунту стора, а не к удалённому профилю.
- **Анонимные профили**: При переустановке без `customer_user_id` уровень доступа аккаунта стора всегда наследуется, независимо от настройки [совместного доступа к платным функциям](sharing-paid-access-between-user-accounts).
- **Идентифицированные профили**: Переносится ли доступ на новый `customer_user_id`, зависит от настройки совместного доступа к платным функциям.
О том, как Adapty связывает эти профили в цепочку, см. [Как работают профили](how-profiles-work#parent-and-inheritor-profiles).
## Тестирование подписок \{#test-subscriptions\}
При тестировании приложения через тестовый аккаунт песочницы можно настроить частоту обновления подписки для каждого тестировщика. Подробнее об изменении частоты обновления подписок в [официальной документации Apple](https://developer.apple.com/help/app-store-connect/test-in-app-purchases/manage-sandbox-apple-account-settings).
По умолчанию подписки обновляются до 12 раз, после чего прекращаются, согласно следующему расписанию:
| Длительность подписки | 1 неделя | 1 месяц | 2 месяца | 3 месяца | 6 месяцев | 1 год |
| :-------------------------------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- |
| Скорость обновления подписки | 3 минуты | 5 минут | 10 минут | 15 минут | 30 минут | 1 час |
| Длительность повторной оплаты | 10 минут | 10 минут | 10 минут | 10 минут | 10 минут | 10 минут |
| Длительность льготного периода | 3 минуты | 5 минут | 5 минут | 5 минут | 5 минут | 5 минут |
:::note
Помните, что тестовые транзакции могут появляться в [Ленте событий](validate-test-purchases) до 10 минут.
:::
Используйте песочницу, чтобы убедиться, что ваше приложение и бэкенд корректно обрабатывают продления, повторные попытки списания и льготные периоды — но не для предсказания времени продлений в продакшене. Ускоренный и ограниченный по количеству итераций график не соответствует продакшену. Чтобы воспроизвести транзакции на вашем сервере для тестирования бэкенда, используйте [Set transaction API](api-adapty/operations/setTransaction).
## Тестирование офферов \{#test-offers\}
Для корректной проверки офферов необходимо удалить все чеки пользователя, чтобы критерии получения офферов работали правильно.
Наиболее надёжный способ тестирования офферов — использовать полностью новый [тестовый аккаунт песочницы](#step-1-create-sandbox-test-account-in-app-store-connect). Повторное тестирование с одним и тем же тестовым аккаунтом песочницы может приводить к непредсказуемому поведению.
:::danger
Если вы повторно используете один и тот же тестовый аккаунт песочницы, обязательно [очистите историю покупок](#step-5-clear-purchase-history), чтобы избежать проблем с получением офферов.
:::
---
# File: local-sk-files
---
---
title: "Тестирование StoreKit в Xcode"
description: "Тестируйте покупки в среде песочницы для обеспечения корректных транзакций."
---
Тестирование StoreKit в Xcode позволяет проверять встроенные покупки локально без настройки аккаунта в песочнице.
Для этого вида тестирования нужно:
1. [Создать продукт в Adapty](quickstart-products) и назначить ему **App Store product ID**.
2. В Xcode создать локальный [файл конфигурации StoreKit](https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode) и добавить в него продукт. Идентификатор продукта должен совпадать с **App Store product ID** в Adapty.
3. Добавить файл конфигурации StoreKit в схему сборки и собрать приложение. Запустить его на эмуляторе или на устройстве.
## Стоит ли использовать тестирование StoreKit в Xcode? \{#should-i-use-storekit-testing-in-xcode\}
Этот способ тестирования наиболее удобен, если вы разработчик, который хочет проверить сборку на ходу или протестировать различные сценарии покупок с помощью инструментов Xcode.
Однако важно помнить, что этот вид тестирования выполняется локально, поэтому никакие изменения не отобразятся в дашборде Adapty. Перед выпуском приложения в продакшн мы рекомендуем протестировать [работу с профилями](ios-quickstart-identify) в [среде песочницы](test-purchases-in-sandbox).
Тестирование StoreKit **стоит** использовать, если нужно:
- Протестировать логику покупок
- Воспроизвести различные сценарии покупок с помощью инструментов Xcode (например, отменённый платёж или возврат средств)
- Протестировать на эмуляторе
Тестирование StoreKit **не стоит** использовать, если нужно:
- Протестировать логику, связанную с профилями
- Убедиться, что действия в приложении отображаются в дашборде Adapty
- Передать приложение команде, не занимающейся разработкой, для тестирования
## Шаг 1. Создайте файл конфигурации StoreKit \{#step-1-create-a-storekit-configuration-file\}
Чтобы создать файл конфигурации StoreKit в Xcode:
1. Нажмите **File > New > File from template**. Затем выберите **StoreKit Configuration File** и нажмите **Next**.
2. Задайте имя. Затем, в зависимости от того, есть ли у вас уже продукты в App Store Connect:
- Выберите **Sync this file with an app in App Store Connect**: чтобы создать файл конфигурации со всеми вашими продуктами из App Store Connect для локального тестирования.
- Не выбирайте **Sync this file with an app in App Store Connect**: чтобы создать пустой файл конфигурации, в который нужно будет добавить продукты вручную.
Нажмите **Next**.
3. Не добавляйте приложение в качестве таргета. Просто продолжите. Если вы работаете с продуктами, синхронизированными из App Store Connect, перейдите к [Шагу 2](#step-2-add-the-configuration-file-to-the-build-scheme).
4. Если продукты не синхронизированы из App Store Connect, нажмите **+** в левом нижнем углу и выберите тип продукта.
5. Введите название группы подписок и нажмите **Next**.
6. Введите имя для ссылки. В поле **Product ID** укажите **App Store product ID** вашего продукта в Adapty.
7. Настройте цену, предложение и другие параметры продукта в файле конфигурации. При необходимости добавьте больше продуктов.
## Шаг 2. Добавьте файл конфигурации в схему сборки \{#step-2-add-the-configuration-file-to-the-build-scheme\}
Чтобы собрать приложение с использованием этого файла конфигурации, нужно добавить его в схему сборки. Рекомендуется разделять схемы для тестирования и продакшна, поэтому предлагаем создать отдельную схему для тестирования:
1. Вверху нажмите на имя приложения и выберите **New scheme**.
2. Введите имя схемы и нажмите **OK**.
3. Снова нажмите на имя приложения и выберите **Edit scheme**. В поле **StoreKit configuration** выберите ваш локальный файл конфигурации, чтобы он использовался при сборке.
## Шаг 3. Соберите и протестируйте \{#step-3-build--test\}
Теперь можно собрать приложение и тестировать встроенные покупки без подключения к бэкенду App Store. Вы можете совершать покупки и получать уровни доступа локально. Эти изменения не будут отражены в дашборде Adapty, но вы сможете проверить разблокировку платных функций локально.
[Подробнее](https://developer.apple.com/documentation/xcode/testing-in-app-purchases-with-storekit-transaction-manager-in-code) о других возможностях тестирования StoreKit в Xcode.
---
# File: testing-on-android
---
---
title: "Тестирование встроенных покупок в Google Play Store"
description: "Тестируйте покупки подписок на Android с помощью Adapty."
---
Тестирование встроенных покупок в Android-приложении — важный шаг перед публичным релизом. Тестирование в песочнице позволяет проверить покупки без реального списания денег. В этом гайде мы разберём, как тестировать встроенные покупки в песочнице Google Play Store для Android.
:::note
**Транзакции из песочницы не отображаются в аналитических графиках.** Они по-прежнему видны на страницах отдельных профилей и в ленте событий.
:::
## Среда тестирования \{#testing-environment\}
Для наилучших результатов рекомендуем тестировать Android-приложение на реальном устройстве, а не на эмуляторе. Несмотря на то что эмуляторы тоже работают, Google рекомендует использовать физическое устройство.
Если всё же решите использовать эмулятор, убедитесь, что на нём установлен Google Play — это необходимо для корректной работы приложения.
## 1. Настройте тестовый аккаунт для тестирования приложения \{#1-set-up-test-account-for-app-testing\}
Чтобы упростить тестирование на более поздних этапах разработки, вам нужно настроить тестового пользователя для тестирования встроенных покупок. Именно с этого аккаунта вы впервые войдёте на своём Android-устройстве.
Обратите внимание: основной аккаунт на Android-устройстве можно сменить только через сброс до заводских настроек, который удаляет все данные. Поэтому важно заранее правильно настроить тестовый аккаунт, чтобы не прибегать к сбросу.
:::important
Способ настройки тестового аккаунта зависит от устройства, которое вы используете:
- Если у вас есть отдельное устройство для тестирования, создайте **отдельный тестовый аккаунт (новый аккаунт Gmail)**.
- Если отдельного устройства нет, можно использовать **личный аккаунт** и временно включить для него **License testing**.
- Если Android-устройства нет совсем, можно **создать отдельный тестовый аккаунт и использовать его с эмулятором**. Однако этот подход не рекомендуется, так как не позволяет выявить все возможные проблемы, характерные для реальных устройств.
:::
## 2. Включите тестирование лицензий \{#enable-license-testing\}
После настройки тестового аккаунта необходимо настроить тестирование лицензий для вашего приложения. Для этого выполните следующие шаги:
1. В боковой панели Google Play Console перейдите в **Settings** и выберите **License testing** в разделе **Monetization**.
2. Выберите существующий список тестировщиков лицензий или создайте новый.
3. Добавьте в список аккаунт, который будете использовать для тестирования, и сохраните изменения. Если другие члены команды тоже должны тестировать приложение, добавьте их email-адреса в список — тогда доступ получит вся группа.
## 3. Создайте закрытый трек и добавьте тестовый аккаунт \{#3-create-closed-track-and-add-test-account-to-it\}
Чтобы начать тестирование, нужно опубликовать подписанную версию приложения в закрытом треке:
1. Откройте своё приложение и выберите в меню **Test and release > Testing > Closed testing**. Нажмите **Create track**.
2. Введите название трека закрытого тестирования и нажмите **Create track**.
3. Добавьте список тестировщиков в трек.
4. В разделе **How testers join your test** скопируйте ссылку и отправьте её на устройство, залогиненное в тестовый аккаунт. Откройте ссылку на тестовом устройстве, чтобы сделать пользователя тестировщиком.
:::warning
Учтите следующее для успешного тестирования:
- Открытие opt-in URL отмечает ваш аккаунт Play для тестирования. Если не выполнить этот шаг, продукты не загрузятся.
- Разработчики часто используют другой application ID для тестовых сборок. Это создаст проблемы, так как Google Play Services использует application ID для поиска встроенных покупок.
- В некоторых случаях тестовый пользователь может приобрести расходуемые покупки, но не подписки, если на тестовом устройстве не установлен PIN-код. Это может проявляться в виде загадочного сообщения «Something went wrong». Убедитесь, что на тестовом устройстве установлен PIN-код и оно авторизовано в Google Play Store.
:::
## 4. Загрузите подписанный APK в закрытый трек \{#4-upload-a-signed-apk-to-the-closed-track\}
Создайте подписанный APK или используйте Android App Bundle, чтобы загрузить подписанный APK в только что созданный закрытый трек. Выпускать релиз не обязательно — достаточно просто загрузить APK. Подробнее об этом читайте в [этой](https://support.google.com/googleplay/android-developer/answer/9859348?visit_id=638929100639477968-3849460621&rd=1) справочной статье.
:::important
Если ваше приложение новое, возможно, потребуется сделать его доступным в вашей стране или регионе. Для этого перейдите в **Testing > Closed testing**, нажмите на нужный тестовый трек и откройте **Countries/regions**, чтобы добавить нужные страны и регионы.
:::
## 5. Тестируйте встроенные покупки \{#5-test-in-app-purchases\}
После загрузки APK подождите несколько минут, пока релиз обработается. Затем откройте тестовое устройство и войдите с email-аккаунтом, добавленным в список тестировщиков. После этого можно тестировать встроенные покупки так же, как в продакшн-приложении.
## Читайте также \{#read-more\}
Дополнительные материалы по тестированию встроенных покупок в Android-приложениях:
- [Периоды обновления в песочнице](https://developer.android.com/google/play/billing/test#subs)
- [Тестирование разовых покупок](https://developer.android.com/google/play/billing/test#one-time)
---
# File: validate-test-purchases
---
---
title: "Проверка тестовых покупок"
description: "Проверяйте тестовые покупки в Adapty для обеспечения корректной обработки транзакций."
---
Перед выпуском мобильного приложения в продакшн важно тщательно протестировать встроенные покупки. Подробные инструкции по тестированию можно найти в статьях [Тестирование встроенных покупок в Apple App Store](test-purchases-in-sandbox) и [Тестирование встроенных покупок в Google Play Store](testing-on-android). После начала тестирования необходимо убедиться, что тестовые покупки прошли успешно.
Каждый раз, совершая тестовую покупку на мобильном устройстве, проверяйте соответствующую транзакцию в [**Event Feed**](https://app.adapty.io/event-feed) в дашборде Adapty. Если покупка не отображается в **Event Feed**, значит Adapty её не отслеживает.
## Тестовая покупка прошла успешно \{#test-purchase-is-successful\}
Если тестовая покупка прошла успешно, событие транзакции отобразится в **Event Feed**:
Если транзакции работают корректно, перейдите к [чеклисту перед релизом](release-checklist) и затем выпустите приложение.
## Тестовая покупка не прошла \{#test-purchase-is-not-successful\}
Если в течение 10 минут событие транзакции не появилось или в мобильном приложении возникла ошибка, обратитесь к статье [Устранение неполадок](troubleshooting-test-purchases) и материалам по обработке ошибок: [для iOS](ios-sdk-error-handling), [для Android](android-sdk-error-handling), [для React Native](react-native-handle-errors), [для Flutter](error-handling-on-flutter-react-native-unity), [для Unity](unity-handle-errors) и [Kotlin Multiplatform](kmp-handle-errors).
---
# File: troubleshooting-test-purchases
---
---
title: "Устранение проблем с тестовыми покупками"
description: "Устраните проблемы с тестовыми покупками в Adapty и решите распространённые ошибки встроенных транзакций."
---
Если вы столкнулись с проблемами при транзакциях, сначала убедитесь, что выполнили все шаги из [чеклиста для релиза](release-checklist). Если вы всё проверили, но проблемы не исчезли, воспользуйтесь рекомендациями ниже:
## Мобильное приложение возвращает ошибку \{#an-error-is-returned-in-the-mobile-app\}
Обратитесь к списку ошибок для вашей платформы: [для iOS](ios-sdk-error-handling), [для Android](android-sdk-error-handling), [для React Native](react-native-troubleshoot-purchases), [Flutter](error-handling-on-flutter-react-native-unity) и [Unity](unity-troubleshoot-purchases) — и следуйте нашим рекомендациям.
## Транзакция отсутствует в Event Feed, хотя приложение не вернуло ошибку \{#transaction-is-absent-from-the-event-feed-although-no-error-is-returned-in-the-mobile-app\}
Чтобы решить эту проблему, проверьте следующее:
1. **Для iOS**: убедитесь, что используете реальное устройство, а не симулятор.
2. Убедитесь, что `Bundle ID`/`Package name` вашего приложения совпадает с тем, что указан в [**App settings**](https://app.adapty.io/settings/general).
3. Убедитесь, что `PUBLIC_SDK_KEY` в приложении совпадает с **Public SDK key** в дашборде Adapty: [**App settings** -> вкладка **General** -> раздел **API keys**](https://app.adapty.io/settings/general).
4. Убедитесь, что используете sandbox-аккаунт, а не [локальный файл конфигурации StoreKit](local-sk-files). Если вы ранее использовали локальный файл конфигурации StoreKit для тестирования, проверьте, что он не подключён в текущей сборке.
## В моём тестовом профиле нет событий \{#no-event-is-present-in-my-testing-profile\}
Это нормальное поведение. Новая запись профиля пользователя автоматически создаётся в Adapty в следующих случаях:
- пользователь запускает приложение впервые;
- пользователь выходит из приложения.
**Почему так происходит:** все транзакции и события привязаны к профилю, который совершил первую транзакцию. Это позволяет хранить всю историю транзакций (пробные периоды, покупки, продления) в рамках одного профиля.
**Что вы увидите:** новые записи профилей (так называемые «неоригинальные профили») могут появляться без событий, но с сохранёнными уровнями доступа. Вы можете видеть события `access_level_updated` — это ожидаемое поведение.
**При тестировании:** чтобы не плодить несколько профилей, создавайте новый тестовый аккаунт (Sandbox Apple ID) при каждой переустановке приложения.
Подробнее см. в разделе [Создание профиля](how-profiles-work#profile-creation).
Ниже показан пример неоригинального профиля. Обратите внимание: в разделе **User history** нет событий, но уровень доступа присутствует.
## Цены не соответствуют тем, что установлены в App Store Connect \{#prices-do-not-reflect-the-actual-prices-set-in-app-store-connect\}
В Sandbox и TestFlight (который также использует sandbox-среду для встроенных покупок) важно убедиться, что процесс покупки работает корректно, а не проверять точность цен. API Apple иногда возвращает некорректные данные, особенно когда для устройств или аккаунтов настроены разные регионы. Поскольку цены поступают напрямую из стора и бэкенд Adapty никак не влияет на цены покупок, любые расхождения в ценах при тестировании покупок через Adapty можно игнорировать.
Сосредоточьтесь на проверке самого процесса покупки, а не точности цен.
## Время транзакции в Event Feed отображается некорректно \{#the-transaction-time-in-the-event-feed-is-incorrect\}
В **Event Feed** используется часовой пояс, заданный в **App Settings**. Чтобы время событий совпадало с вашим местным временем, измените **Reporting timezone** в разделе [**App settings** -> вкладка **General**](https://app.adapty.io/settings/general).
## Пейволы и продукты загружаются слишком долго \{#paywalls-and-products-take-a-long-time-to-load\}
Эта проблема может возникать, если у тестового аккаунта длинная история транзакций. Мы настоятельно рекомендуем каждый раз создавать новый тестовый аккаунт, как описано в разделе [Создание тестового Sandbox-аккаунта (Sandbox Apple ID) в App Store Connect](test-purchases-in-sandbox#step-1-create-sandbox-test-account-in-app-store-connect).
Если создать новый аккаунт не получается, можно очистить историю транзакций текущего аккаунта на iOS-устройстве:
1. Откройте **Settings** и нажмите **App Store**.
2. Нажмите на свой **Sandbox Apple ID**.
3. Во всплывающем окне выберите **Manage**.
4. На странице **Account Settings** нажмите **Clear Purchase History**.
Подробнее см. в [документации Apple Developer](https://developer.apple.com/documentation/storekit/testing-in-app-purchases-with-sandbox).
---
# File: test-devices
---
---
title: "Тестовые устройства"
description: "Узнайте, как управлять тестовыми устройствами в Adapty для эффективного тестирования приложений."
---
В целях тестирования вы можете назначить своё устройство тестовым — это отключает кэширование и гарантирует, что внесённые изменения отображаются сразу.
:::note
Тестовые устройства поддерживаются начиная со следующих версий SDK:
- iOS: 2.11.1
- Android: 2.11.3
- React Native: 2.11.1
Поддержка Flutter и Unity будет добавлена позже.
:::
## Отметить устройство как тестовое \{#mark-your-device-as-test\}
1. Откройте [**App settings**](https://app.adapty.io/settings/general) в дашборде Adapty.
2. Прокрутите страницу вниз до раздела **Test devices** на вкладке **General**.
3. Нажмите кнопку **Add test device**.
4. В окне **Add test device** заполните поля:
| Поле | Описание |
|:-----------------------------------------| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Test device name** | Название тестового устройства (или устройств) для вашего удобства. |
| **ID used to identify this test device** | Выберите тип идентификатора для определения тестового устройства (или устройств). Следуйте нашим рекомендациям в разделе [Какой идентификатор использовать](test-devices#which-identifier-you-should-use) ниже, чтобы выбрать оптимальный вариант. |
| **ID value** | Введите значение идентификатора. |
5. Не забудьте нажать кнопку **Add test device**, чтобы сохранить изменения.
## Какой идентификатор использовать \{#which-identifier-you-should-use\}
Для идентификации устройства можно использовать несколько типов идентификаторов. Мы рекомендуем следующие:
- **Customer User ID** — для устройств iOS и Android, если вы Уникальный идентификатор, который вы задаёте самостоятельно для идентификации пользователей в вашей системе. Это может быть email пользователя, ваш внутренний ID или любая другая строка. Для использования этого варианта необходимо
Это лучший выбор для идентификации тестового устройства, особенно если вы используете несколько устройств для одного аккаунта. Все устройства с этим аккаунтом будут считаться тестовыми.
| | Adapty profile ID |Уникальный идентификатор [профиля пользователя](profiles-crm) в Adapty.
Используйте его, если не можете применить Customer User ID, IDFA для iOS или Advertising ID для Android. Обратите внимание: Adapty Profile ID может измениться при переустановке приложения или повторном входе.
| #### Как получить Customer User ID и Adapty profile ID \{#how-to-obtain-customer-user-id-and-adapty-profile-id\} Оба идентификатора можно найти в деталях **Profile** в дашборде Adapty: 1. Найдите профиль пользователя во вкладке [**Adapty Profiles** -> **Event feed**](https://app.adapty.io/event-feed). :::note Чтобы найти нужный профиль, совершите редкий тип транзакции. Когда она появится в [**Event Feed**](https://app.adapty.io/event-feed), вы легко её распознаете. ::: 2. Скопируйте значения полей **Customer user ID** и **Adapty ID** в деталях профиля:
### Идентификаторы Apple \{#apple-identifiers\}
| Идентификатор | Использование |
|----------|-----|
| IDFA | Identifier for Advertisers (IDFA) — уникальный идентификатор устройства, присваиваемый Apple.
Идеально подходит для iOS-устройств: он не меняется сам по себе, хотя вы можете сбросить его вручную.
**Примечание**: начиная с iOS 14.5 рекламодатели обязаны запрашивать согласие пользователя на доступ к IDFA. Убедитесь, что ваше приложение запрашивает такое согласие и что вы его предоставили на тестовом устройстве.
| | IDFV | Identifier for Vendors (IDFV) — уникальный буквенно-цифровой идентификатор, присваиваемый Apple всем приложениям одного издателя/поставщика на одном устройстве. Может измениться при переустановке или обновлении приложения. | #### Как получить IDFA \{#how-to-obtain-the-idfa\} Apple не предоставляет IDFA по умолчанию. Его можно получить из атрибуции профиля в дашборде Adapty: 1. Найдите профиль пользователя во вкладке [**Adapty Profiles** -> **Event feed**](https://app.adapty.io/event-feed). :::note Чтобы найти нужный профиль, совершите редкий тип транзакции. Когда она появится в [**Event Feed**](https://app.adapty.io/event-feed), вы легко её распознаете. ::: 2. Откройте детали профиля и скопируйте значение поля **IDFA** в разделе **Attributes**:
Также можно [найти в App Store приложение, которое покажет вам ваш IDFA](https://www.apple.com/us/search/idfa?src=globalnav).
#### Как получить Identifier for Vendors (IDFV) \{#how-to-obtain-the-identifier-for-vendors-idfv\}
Чтобы получить IDFV, попросите разработчика запросить его с помощью следующего метода в вашем приложении и вывести полученный идентификатор в логи или панель отладки.
```swift showLineNumbers title="Swift"
UIDevice.current.identifierForVendor
```
### Идентификаторы Google \{#google-identifiers\}
| Идентификатор | Использование |
|----------|-----|
| Advertising ID | Advertising ID — уникальный идентификатор устройства, присваиваемый Google.
Идеально подходит для Android-устройств: он не меняется сам по себе, хотя вы можете сбросить его вручную.
**Примечание**: для использования этого идентификатора отключите параметр **Opt out of Ads Personalization** в настройках **Ads**, если вы используете Android 12 или более позднюю версию.
| | Android ID | Android ID — уникальный идентификатор для каждой комбинации ключа подписи приложения, пользователя и устройства. Доступен на Android 8.0 и выше. | #### Как получить Advertising ID \{#how-to-obtain-advertising-id\} Чтобы найти рекламный идентификатор устройства: 1. Откройте приложение **Settings** на вашем Android-устройстве. 2. Нажмите **Google**. 3. Выберите **Ads** в разделе **Services**. Ваш рекламный идентификатор будет указан внизу экрана. #### Как получить Android ID \{#how-to-obtain-android-id\} Чтобы получить Android ID, попросите разработчика запросить [ANDROID_ID](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID) с помощью следующего метода в вашем приложении и вывести полученный идентификатор в логи или панель отладки. ```kotlin showLineNumbers title="Kotlin/Java" android.provider.Settings.Secure.getString(contentResolver, android.provider.Settings.Secure.ANDROID_ID); ``` --- # File: release-checklist --- --- title: "Чеклист перед релизом" description: "Следуйте чеклисту Adapty, чтобы обеспечить плавный процесс обновления приложения." --- Рады, что вы выбрали Adapty! Надеемся, интеграция прошла гладко. Этот гайд поможет убедиться, что приложение готово к публикации в сторах, а монетизация работает корректно. ## Что нужно подготовить заранее \{#pre-flight-essentials\} Перед началом проверки убедитесь, что у вас есть: - Реальное устройство с sandbox-аккаунтом - Доступ к дашборду Adapty - Доступ к App Store Connect / Google Play Console :::note Хотя sandbox-покупки можно тестировать на симуляторах, реальные устройства необходимы для полноценного тестирования всех сценариев — включая диалоги оплаты и биометрическую аутентификацию. ::: ## Универсальные проверки \{#universal-validations\} - [ ] **Подключение стора**: Убедитесь, что вы подключили Adapty к App Store и/или Google Play: - [ ] [App Store](initial_ios) - [ ] [Google Play](initial-android) - [ ] **Доставка событий подписки**: Убедитесь, что серверные уведомления настроены: - [ ] [Серверные уведомления App Store](enable-app-store-server-notifications) - [ ] [Уведомления разработчика в реальном времени (RTDN)](enable-real-time-developer-notifications-rtdn) - [ ] **Идентификация профиля**: Проверьте логику идентификации пользователей и убедитесь, что покупки привязываются к нужному профилю: - [ ] [Убедитесь, что логика идентификации в коде приложения соответствует вашему сценарию использования](ios-quickstart-identify) - [ ] [Убедитесь, что вы понимаете логику parent/inheritor при совместном использовании платного доступа между профилями пользователей](sharing-paid-access-between-user-accounts) - [ ] **Офферы**: Если в приложении используются promotional offer из App Store, убедитесь, что вы [добавили ключ встроенных покупок](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers) как в основное поле, так и в раздел **App Store promotional offers**. - [ ] **Сбор данных**: Убедитесь в соответствии требованиям конфиденциальности: - [ ] Если вам необходимо соответствовать требованиям законодательства о конфиденциальности (например, GDPR или CCPA) или приложение предназначено для детей, управляйте тем, [включён ли сбор и передача IDFA и IP-адреса](sdk-installation-ios#data-policies). - [ ] Если в приложении используется AppTrackingTransparency, убедитесь, что вы [передаёте статус авторизации в Adapty](ios-deal-with-att). - [ ] **Метки конфиденциальности**: [Узнайте подробнее](apple-app-privacy) о том, какие данные собирает Adapty и какие флаги нужно выставить при проверке. ## Проверка покупок \{#purchase-validations\} :::tip Есть вопросы или возникли проблемы? Загляните на наш [форум поддержки](https://adapty.featurebase.app/), где можно найти ответы на распространённые вопросы или задать свой. Наша команда и сообщество всегда готовы помочь! ::: Перед запуском убедитесь, что покупки в вашем приложении работают корректно и пейвол готов к ревью в сторе. Способ проверки встроенных покупок зависит от того, как вы их реализовали: - Вы отображаете пейвол, созданный в Adapty Paywall Builder - Вы реализовали собственный пейвол и используете метод `makePurchase` внутри него для обработки покупок - Вы используете Adapty в режиме наблюдателя (как с Adapty Paywall Builder, так и с собственным пейволом)
2. В верхнем меню выберите **Product** > **Archive**.
3. Дождитесь завершения архивации. Окно **Organizer** откроется автоматически. Выберите архив и нажмите **Distribute App**.
4. В качестве метода распространения выберите **App Store Connect** и следуйте инструкциям для завершения загрузки.
:::note
Загрузка может завершиться ошибкой, если отсутствуют необходимые ресурсы — например, иконка приложения или экран запуска. Подробности смотрите в журнале ошибок Xcode.
:::
### Шаг 2. Проверка сборки в App Store Connect \{#step-2-check-the-build-in-app-store-connect\}
1. Перейдите в [App Store Connect](https://appstoreconnect.apple.com) и откройте своё приложение.
2. Прокрутите до раздела **Build** и убедитесь, что только что загруженная сборка там отображается.
:::note
После загрузки сборка может появиться в App Store Connect через несколько минут.
:::
## Отправка приложения и продуктов на проверку \{#submit-your-app-and-products-for-review\}
После того как сборка появится в разделе **Build**, прикрепите встроенные подписки и отправьте приложение на проверку Apple.
### Шаг 1. Прикрепление продуктов к заявке \{#step-1-attach-products-to-the-submission\}
Каждая подписка должна иметь статус **Ready to Submit** в App Store Connect, прежде чем её можно будет прикрепить. Если подписка всё ещё в черновике или у неё отсутствуют метаданные, она не появится в списке.
1. На той же странице прокрутите до раздела **In-App Purchases and Subscriptions**.
2. Нажмите **Select in-app purchases or subscriptions**.
3. Выберите все продукты, которые хотите включить в заявку, и нажмите **Done**.
### Шаг 2. Отправка на проверку \{#step-2-submit-for-review\}
1. Заполните все обязательные поля на странице (описание, скриншоты, ключевые слова и т. д.).
2. В разделе **App Store Version Release** выберите, как выпустить приложение после одобрения: автоматически, вручную или по расписанию.
3. Нажмите **Add for Review**, затем **Submit to App Review**.
Apple проверяет приложения в течение 1–2 дней, хотя сроки могут варьироваться.
## Проверка приложения в продакшне \{#verify-your-app-in-production\}
После одобрения Apple:
1. Совершите реальную покупку (или дождитесь первой покупки от пользователя).
2. Откройте [**Event Feed**](https://app.adapty.io/event-feed) в дашборде Adapty и убедитесь, что там появляются события транзакций из продакшна.
3. Проверьте, что события подписок (продления, отмены) передаются корректно — это зависит от настроенных [серверных уведомлений App Store](enable-app-store-server-notifications).
Если события продакшна не появляются, проверьте [настройки подключения к App Store](app-store-connection-configuration).
## Следующие шаги \{#next-steps\}
Ваше приложение запущено. Начните наращивать доход от подписок:
- **[A/B-тестирование](ab-tests)**: Экспериментируйте с разными пейволами, чтобы найти наиболее конверсионный вариант.
- **[Аналитика](charts)**: Отслеживайте метрики подписок: MRR, отток, конверсию.
- **Интеграции**: Отправляйте события подписок на платформы [аналитики](analytics-integration) и [атрибуции](attribution-integration).
---
# File: general
---
---
title: "Настройки приложения"
description: "Ознакомьтесь с общими настройками и конфигурациями в Adapty для удобной работы."
---
Перейдите на вкладку **General** страницы **App Settings**, чтобы управлять поведением, внешним видом приложения и распределением дохода. Здесь можно изменить название и иконку приложения, управлять ключами Adapty SDK и API, настроить статус Small Business Program, а также выбрать часовой пояс для аналитики и графиков приложения.
## 1. Детали приложения \{#1-app-details\}
Выберите уникальное имя и иконку, которые будут представлять ваше приложение в интерфейсе Adapty. Обратите внимание, что имя и иконка приложения не влияют на его название и иконку в App Store или Google Play. Также выберите подходящую категорию приложения, которая точно отражает его назначение и содержание. Это поможет пользователям найти ваше приложение и обеспечит его отображение в соответствующих категориях стора.
## 2\. Участие в программе Small Business Program и сниженный сбор \{#member-of-small-business-program-and-reduced-service-fee\}
Если ваша организация участвует в программе Apple [Small Business Program](app-store-small-business-program) или в программе Google [Reduced Service Fee](google-reduced-service-fee), на ваши приложения распространяется сниженный комиссионный сбор стора.
Сообщите Adapty, если ваше приложение участвует в программе сниженной комиссии. Чтобы расчёты были корректными, укажите статус участия в разделе **Reduced Store Fee**.
Настройка сниженной комиссии применяется только к будущим транзакциям. Измените статус **до** вступления изменений в силу — Adapty скорректирует ставку комиссии.
:::warning
* Если вы продлеваете участие в программе сниженной комиссии, **добавьте новый период действия**.
* Если вы теряете членство в программе, **измените дату окончания** текущего периода действия.
:::
Следующие статьи подробно рассматривают эту тему:
* [Программа App Store Small Business Program](app-store-small-business-program)
* [Google Reduced Service Fee](google-reduced-service-fee)
## 3\. Часовой пояс для отчётов \{#reporting-timezone\}
Выберите часовой пояс, соответствующий вашему местоположению или региону, где аналитика и графики приложения наиболее актуальны. Рекомендуем использовать тот же часовой пояс, что и в вашем аккаунте App Store Connect или Google Play Console, — это обеспечит согласованность данных. Обратите внимание, что данная настройка часового пояса не влияет на сторонние интеграции в системе Adapty — они используют часовой пояс UTC.
Настройки часового пояса находятся в разделе **Reported timezone** на вкладке **General Tab** страницы **App Settings**. Вы также можете установить единый часовой пояс для всех приложений в своём аккаунте Adapty, поставив галочку в соответствующем поле.
## 4\. Определение установок для аналитики \{#installs-definition-for-analytics\}
Выберите, что считается новым событием установки в аналитике:
| База | Описание |
|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| New device_ids | (Рекомендуется) Каждая установка приложения из стора на устройство считается новой установкой. Это включает как первичные установки, так и переустановки.
Установки считаются по идентификатору устройства и не зависят от аутентификации пользователя. Создание профиля (при активации SDK или выходе из аккаунта), вход в систему или обновление приложения не генерируют дополнительных событий установки.
Например, если одно и то же приложение установлено на 5 разных устройствах, в аналитике будет показано 5 установок.
| | New customer_user_ids |Этот вариант предназначен для приложений, которые
Для авторизованных пользователей только первая установка, связанная с идентификатором пользователя (customer user ID), считается установкой. Установки на дополнительных устройствах новыми установками не считаются.
Анонимные пользователи (не вошедшие в систему) в аналитике не учитываются.
Переустановка приложения или повторный вход в аккаунт не создают дополнительных установок.
Сторы и платформы атрибуции (такие как App Store Connect, Google Play Console и AppsFlyer) используют подход на основе устройств для подсчёта установок. Если вы считаете установки по customer user ID в Adapty, цифры могут отличаться от данных этих внешних сервисов.
⚠️ Если вы не идентифицируете пользователей в Adapty, при включении этого варианта установки учитываться не будут.
| | New profiles in Adapty | (Устаревший) Каждая установка приложения, переустановка и анонимные профили, созданные при выходе из аккаунта, считаются новыми установками. | Помните, что этот параметр влияет только на страницу [**Analytics**](https://app.adapty.io/analytics) и не затрагивает страницу [**Overview**](https://app.adapty.io/overview), где настройки отображения задаются отдельно. ## 5. Логика повышения цен в App Store \{#5-app-store-price-increase-logic\} Чтобы данные оставались точными и не расходились между аналитикой Adapty и App Store Connect, важно выбрать правильный вариант при настройке повышения цен в App Store Connect. Итак, вы можете выбрать логику, которая будет применяться к повышению цен на подписки в Adapty:
- **Цена подписки для существующих пользователей сохраняется:** При выборе этого варианта текущая цена сохраняется для существующих подписчиков, даже если вы измените её в App Store Connect. Это значит, что существующие подписчики будут по-прежнему оплачивать подписку по первоначальной цене.
- **При изменении цены подписки в App Store Connect она меняется и для существующих подписчиков:** При выборе этого варианта любые изменения цены в App Store Connect будут применяться и к существующим подписчикам. Это значит, что с существующих подписчиков будет списываться новая цена в соответствии с обновлёнными настройками в App Store Connect.
:::warning
Важно учитывать, что выбранный параметр влияет не только на аналитику в Adapty, но и на интеграции, а также на общую логику обработки транзакций.
:::
Убедитесь, что вы выбрали нужный параметр, соответствующий вашему подходу к обработке цен подписки для существующих подписчиков. Это поможет сохранить точность данных и синхронизацию между аналитикой Adapty и данными из App Store Connect.
## 6. Совместный доступ к платным функциям между аккаунтами пользователей \{#6-sharing-paid-access-between-user-accounts\}
:::link
Основная статья: [Совместный доступ к платным функциям между аккаунтами пользователей](sharing-paid-access-between-user-accounts)
:::
Настройка **Sharing paid access between user accounts** определяет поведение Adapty, когда более одного [профиля пользователя](identifying-users) пытается получить доступ к одной и той же покупке. Вы можете указать отдельную настройку совместного доступа для [среды песочницы](test-purchases-in-sandbox).
**Включено (по умолчанию)**
Идентифицированные пользователи (те, у кого задан [Customer User ID](identifying-users#set-customer-user-id-on-configuration)) могут совместно использовать один и тот же [уровень доступа](access-level), предоставленный Adapty, если их устройство привязано к одному Apple/Google ID. Это удобно, когда пользователь переустанавливает приложение и входит с другим email — он всё равно сохранит доступ к своей предыдущей покупке. При этой опции несколько идентифицированных пользователей могут совместно использовать один уровень доступа.
Несмотря на то что уровень доступа является общим, все прошлые и будущие транзакции фиксируются как события в исходном Customer User ID — для обеспечения корректной аналитики и сохранения полной истории транзакций: пробных периодов, покупок подписок, продлений и прочего, привязанных к одному профилю.
**Передача доступа новому пользователю**
Идентифицированные пользователи сохраняют доступ к [уровню доступа](access-level), предоставленному Adapty, даже если они входят с другим [Customer User ID](identifying-users#set-customer-user-id-on-configuration) или переустанавливают приложение — при условии, что устройство привязано к одному Apple/Google ID.
В отличие от предыдущей опции, Adapty передаёт покупку между идентифицированными пользователями. Это гарантирует доступность купленного контента, однако одновременно доступ может быть только у одного пользователя. Например, если UserA оформляет подписку, а UserB входит на том же устройстве и восстанавливает транзакции, UserB получит доступ к подписке, а у UserA он будет отозван.
Если один из пользователей (новый или прежний) не идентифицирован, уровень доступа всё равно будет общим между этими профилями в Adapty.
Несмотря на передачу уровня доступа, все прошлые и будущие транзакции фиксируются как события в исходном Customer User ID — для обеспечения корректной аналитики и сохранения полной истории транзакций: пробных периодов, покупок подписок, продлений и прочего, привязанных к одному профилю.
После переключения на **Transfer access to new user** уровни доступа не будут немедленно переданы между профилями. Процесс передачи для каждого конкретного уровня доступа запускается только при получении Adapty события от стора — например, при продлении подписки, восстановлении или при валидации транзакции.
**Отключено**
Первый идентифицированный профиль пользователя, получивший уровень доступа, сохранит его навсегда. Это оптимальный вариант, если бизнес-логика вашего приложения требует привязки покупок к единственному Customer User ID.
Обратите внимание, что уровни доступа по-прежнему остаются общими между анонимными пользователями.
Вы можете «отвязать» покупку, [удалив профиль пользователя-владельца](https://adapty.io/docs/ru/api-adapty/operations/deleteProfile). После удаления уровень доступа становится доступным первому профилю, который его запросит — анонимному или идентифицированному.
Отключение совместного использования распространяется только на новых пользователей. Подписки, уже разделённые между пользователями, продолжат оставаться общими даже после отключения этой опции.
:::warning
Apple и Google требуют, чтобы встроенные покупки были доступны для совместного использования или передачи между пользователями, поскольку они привязывают покупку к Apple/Google ID. Без совместного использования восстановление покупок после повторной установки может не работать.
Отключение совместного использования может лишить пользователей возможности восстановить доступ после входа в аккаунт.
Рекомендуем отключать совместное использование только в том случае, если пользователи **обязаны войти в аккаунт** до совершения покупки. В противном случае идентифицированный пользователь может оформить подписку, войти в другой аккаунт и навсегда потерять к ней доступ.
:::
### Какой вариант выбрать? \{#which-setting-should-i-choose\}
| Моё приложение... | Вариант |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| Не имеет системы входа и использует только анонимные идентификаторы профилей Adapty. | Используйте вариант по умолчанию — уровни доступа всегда являются общими между анонимными идентификаторами профилей для всех трёх вариантов. |
| Имеет необязательную систему входа и позволяет совершать покупки до создания аккаунта. | Выберите **Transfer access to new user**, чтобы пользователи, совершившие покупку без аккаунта, могли впоследствии восстановить свои транзакции. |
| Требует создания аккаунта перед покупкой, но допускает привязку покупок к нескольким Customer User ID. | Выберите **Transfer access to new user**, чтобы одновременно доступ был только у одного Customer User ID, при этом пользователи могли входить с другим Customer User ID без потери оплаченного доступа. |
| Требует создания аккаунта перед покупкой и жёстко привязывает покупки к единственному Customer User ID. | Выберите **Disabled**, чтобы транзакции никогда не передавались между аккаунтами. |
## 7. Ключи SDK и API \{#7-sdk-and-api-keys\}
Используйте публичный ключ SDK для интеграции SDK Adapty в ваше приложение, а секретный ключ — для доступа к Server API Adapty. При необходимости можно создавать новые ключи или отзывать существующие. Для создания токенов для Developer CLI перейдите в **Settings → Developer API**. См. [Аутентификация](developer-cli-authentication).
## 8. Тестовые устройства \{#8-test-devices\}
Укажите устройства для тестирования, чтобы они получали мгновенные обновления при изменении пейвола или плейсмента, минуя задержки кэширования. Подробнее см. [Тестовые устройства](test-devices).
## 9. Постоянство вариантов между плейсментами \{#cross-placement-variation-stickiness\}
Укажите, как долго после завершения теста пользователь продолжает видеть варианты из этого теста. Это влияет на точность аналитики и пользовательский опыт — если показать пользователю другое предложение вместо того, которое он уже видел, это может повлиять на его решение о покупке.
Максимальный и дефолтный период постоянства составляет 90 дней.
:::warning
Обратите внимание:
- Изменение этой настройки затронет всех пользователей, которые ранее получили вариант. Они сразу же получат новый пейвол при следующем показе плейсмента, что может испортить результаты ваших текущих A/B-тестов.
- Если период закрепления для пользователя истёк, ему может быть показан новый пейвол или A/B-тест. Однако даже в этом случае такой пользователь не сможет участвовать ни в каком другом кросс-плейсментном тесте.
:::
## 10. Удаление приложения \{#10-delete-the-app\}
Если приложение вам больше не нужно, его можно удалить из Adapty.
:::warning
Обратите внимание, что это действие необратимо — восстановить приложение или его данные будет невозможно.
:::
---
# File: ios-settings
---
---
title: "Учётные данные Apple App Store"
description: "Настройте параметры iOS в Adapty для бесперебойного управления подписками."
---
Чтобы настроить учётные данные App Store и обеспечить корректную работу Adapty iOS SDK, перейдите на вкладку [iOS SDK](https://app.adapty.io/settings/ios-sdk) на странице **App Settings** дашборда Adapty. Затем настройте следующие параметры:
| Поле | Описание |
|----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Bundle ID** | [Bundle ID вашего приложения](app-store-connection-configuration#step-1-provide-bundle-id-and-apple-app-id). |
| **In-app purchase API (StoreKit 2)** | [Ключи](app-store-connection-configuration#step-2-provide-issuer-id-and-key-id) для безопасной аутентификации и проверки истории транзакций встроенных покупок. |
| **App Store Server Notifications** | URL для получения [серверных уведомлений](enable-app-store-server-notifications) от App Store об изменениях статуса подписок пользователей. |
| **App Store Promotional Offers** | Ключи подписки для создания [Promotional offers](generate-in-app-purchase-key) в Adapty для конкретных продуктов. |
| **Apple app ID** | ID вашего приложения в App Store. Чтобы найти его, откройте страницу приложения в App Store Connect, перейдите на страницу **App Information** в левом меню и скопируйте **Apple ID**. |
| **App Store Connect shared secret (LEGACY)** | **Устаревший ключ для Adapty SDK версий до v2.9.0**
[Ключ](app-store-connection-configuration#step-5-enter-app-store-shared-secret) для валидации чеков и защиты от мошенничества в приложении.
| --- # File: google-play-store-connection-configuration --- --- title: "Настройка интеграции с Google Play Store" description: "Настройте подключение Google Play Store в Adapty для корректной обработки встроенных покупок." --- В этом разделе описан процесс интеграции вашего мобильного приложения, распространяемого через Google Play, с Adapty. Вам нужно ввести данные конфигурации приложения из Play Store в дашборд Adapty. Этот шаг необходим для валидации покупок и получения обновлений подписок из Play Store в Adapty. Вы можете выполнить этот процесс во время первоначального онбординга или внести изменения позже в разделе **App Settings** дашборда Adapty. :::danger Изменение конфигурации допустимо только до выпуска мобильного приложения с интегрированными пейволами Adapty. Изменения после релиза нарушат интеграцию, и пейволы перестанут отображаться в вашем приложении. ::: ## Шаг 1. Укажите Package name \{#step-1-provide-package-name\} Package name — это уникальный идентификатор вашего приложения в Google Play Store. Он необходим для базовой функциональности Adapty, например для обработки подписок. 1. Откройте [Google Play Developer Console](https://play.google.com/console/u/0/developers). 2. Выберите приложение, ID которого вам нужен. Откроется окно **Dashboard**.
3. Найдите идентификатор продукта под названием приложения и скопируйте его.
4. Откройте [**App settings**](https://app.adapty.io/settings/android-sdk) в верхнем меню Adapty.
5. На вкладке **Android SDK** окна **App settings** вставьте скопированный **Package name**.
## Шаг 2. Загрузите файл ключа аккаунта \{#step-2-upload-the-account-key-file\}
1. Загрузите файл закрытого ключа сервисного аккаунта в формате JSON, созданный на шаге [Создание файла ключа сервисного аккаунта](create-service-account), в поле **Service account key file**.
Не забудьте нажать кнопку **Save**, чтобы сохранить изменения.
**Что дальше**
- [Включите уведомления разработчика в реальном времени (RTDN) в Google Play Console](enable-real-time-developer-notifications-rtdn)
---
# File: enable-real-time-developer-notifications-rtdn
---
---
title: "Включение уведомлений в реальном времени (RTDN) в Google Play Console"
description: "Будьте в курсе важных событий и обеспечьте точность данных, включив уведомления в реальном времени (RTDN) в Google Play Console для Adapty. Узнайте, как настроить RTDN для получения мгновенных обновлений о возвратах и других событиях из Play Store"
---
Настройка уведомлений в реальном времени (RTDN) необходима для обеспечения точности данных: она позволяет мгновенно получать обновления из Play Store, включая информацию о возвратах и других событиях.
## Включение уведомлений \{#enable-notifications\}
1. Убедитесь, что **Google Cloud Pub/Sub** включён. Перейдите по [этой ссылке](https://console.cloud.google.com/flows/enableapi?apiid=pubsub) и выберите проект вашего приложения. Если вы ещё не включили **Google Cloud Pub/Sub**, сделайте это здесь.
2. Перейдите в [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) из верхнего меню Adapty и скопируйте содержимое поля **Enable Pub/Sub API** рядом с заголовком **Google Play RTDN topic name**.
:::note Если содержимое поля **Enable Pub/Sub API** имеет неправильный формат (правильный формат начинается с `projects/...`), обратитесь к разделу [Исправление неправильного формата в поле Enable Pub/Sub API](enable-real-time-developer-notifications-rtdn#fixing-incorrect-format-in-enable-pubsub-api-field) за помощью. ::: 3. Откройте [Google Play Console](https://play.google.com/console/), выберите своё приложение и перейдите в **Monetize with Play** -> **Monetization setup**. В разделе **Google Play Billing** установите флажок **Enable real-time notifications**. 4. Вставьте содержимое поля **Enable Pub/Sub API**, скопированное в **App Settings** Adapty, в поле **Topic name**. 5. Нажмите **Save changes** в Google Play Console.
## Тестирование уведомлений \{#test-notifications\}
Чтобы проверить, успешно ли вы подписались на уведомления в реальном времени:
1. Сохраните изменения в настройках Google Play Console.
2. В Google Play Console под полем **Topic name** нажмите **Send test notification**.
3. Перейдите в [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) в Adapty. Если тестовое уведомление было отправлено, вы увидите его статус над названием топика.
## Исправление неправильного формата в поле Enable Pub/Sub API \{#fixing-incorrect-format-in-enable-pubsub-api-field\}
Если содержимое поля **Enable Pub/Sub API** имеет неправильный формат (правильный формат начинается с `projects/...`), выполните следующие шаги для устранения проблемы:
### 1. Проверка активации API и прав доступа \{#1-verify-api-enablement-and-permissions\}
Убедитесь, что все необходимые API включены и права доступа к сервисному аккаунту настроены правильно. Даже если вы уже выполняли эти шаги, пройдите их повторно, чтобы не пропустить ни одного. Повторите шаги из следующих разделов:
1. [Включение API разработчика в Google Play Console](enabling-of-devepoler-api)
2. [Создание сервисного аккаунта в Google Cloud Console](create-service-account)
3. [Выдача прав сервисному аккаунту в Google Play Console](grant-permissions-to-service-account)
4. [Создание файла ключа сервисного аккаунта в Google Play Console](create-service-account-key-file)
5. [Настройка интеграции с Google Play Store](google-play-store-connection-configuration)
### 2. Изменение политик домена \{#2-adjust-domain-policies\}
Измените политики **Domain restricted contacts** и **Domain restricted sharing**:
1. Откройте [Google Cloud Console](https://console.cloud.google.com/) и выберите проект, в котором создан сервисный аккаунт для управления вашим приложением.
2. В разделе **Quick Access** выберите **IAM & Admin**.
3. На левой панели выберите **Organization Policies**.
4. Найдите политику **Domain restricted contacts**.
5. Нажмите кнопку с многоточием в столбце **Actions** и выберите **Edit policy**.
6. В окне редактирования политики:
1. В разделе **Policy source** выберите переключатель **Override parent's policy**.
2. В разделе **Policy enforcement** выберите переключатель **Replace**.
3. В разделе **Rules** нажмите кнопку **ADD A RULE**.
4. В разделе **New rule** -> **Policy values** выберите **Allow All**.
5. Нажмите **SET POLICY**.
7. Повторите шаги 4–6 для политики **Domain restricted sharing**.
После этого пересоздайте содержимое поля **Enable Pub/Sub API** рядом с заголовком **Google Play RTDN topic name**. Теперь поле будет в правильном формате.
Не забудьте вернуть **Policy source** в значение **Inherit parent's policy** для обновлённых политик после успешного включения уведомлений в реальном времени (RTDN).
## Переадресация необработанных событий \{#raw-events-forwarding\}
В некоторых случаях вам может потребоваться получать необработанные S2S-события от Google. Чтобы продолжать их получать при использовании Adapty, просто добавьте свой эндпоинт в поле **URL for forwarding raw Google events** — мы будем передавать события в том виде, в котором они приходят от Google.
---
**Что дальше**
Настройте Adapty SDK для:
- [Android](sdk-installation-android)
- [React Native](sdk-installation-reactnative)
- [Flutter](sdk-installation-flutter)
- [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)
- [Unity](sdk-installation-unity)
---
# File: apple-search-ads
---
---
title: "Apple Ads"
description: "Интегрируйте Apple Ads с Adapty для оптимизации конверсий подписок."
---
:::important
Интеграция Apple Ads в **App settings** используется только для базовой аналитики, а также для интеграций SplitMetrics Acquire и Asapty.
[Adapty Ads Manager](adapty-ads-manager) использует отдельное подключение. Подключите ваш аккаунт Apple Ads в [Adapty Ads Manager](adapty-ads-manager-get-started).
:::
Adapty помогает получать данные атрибуции из Apple Ads и анализировать метрики с сегментацией по кампаниям и ключевым словам. Adapty автоматически собирает данные атрибуции для Apple Ads через SDK и AdServices Framework.
После настройки интеграции с Apple Ads Adapty начнёт получать данные атрибуции. Просмотреть их можно на странице профилей.
## Настройка интеграции \{#set-up-integration\}
### Подключение Adapty к фреймворку AdServices \{#connect-adapty-to-the-adservices-framework\}
Apple Ads через [AdServices](https://developer.apple.com/documentation/adservices) требует настройки в дашборде Adapty, а также включения на стороне приложения. Чтобы настроить Apple Ads с использованием фреймворка AdServices через Adapty, выполните следующие шаги:
#### Шаг 1: Получите публичный ключ \{#step-1-obtain-public-key\}
В дашборде Adapty перейдите в [Settings -> Apple Ads.](https://app.adapty.io/settings/apple-search-ads)
Найдите заранее сгенерированный публичный ключ (Adapty создаёт пару ключей за вас) и скопируйте его.
:::note
Если вы используете сторонний сервис или собственное решение для атрибуции Apple Ads, вы можете загрузить свой приватный ключ.
:::
#### Шаг 2: Настройте управление пользователями в Apple Ads \{#step-2-configure-user-management-on-apple-ads\}
В вашем [аккаунте Apple Ads](https://ads.apple.com/app-store) перейдите на страницу **Settings > User Management**. Чтобы Adapty мог получать данные атрибуции, нужно пригласить дополнительный Apple ID и предоставить ему доступ API Account Manager. Можно использовать любой доступный вам аккаунт или создать новый специально для этой цели. Главное условие — вы должны иметь возможность войти в Apple Ads под этим Apple ID.
#### Шаг 3: Генерация учётных данных API \{#step-3-generate-api-credentials\}
Войдите в только что добавленный аккаунт в Apple Ads. Перейдите в Settings -> API в интерфейсе Apple Ads. Вставьте ранее скопированный публичный ключ в соответствующее поле. Сгенерируйте новые учётные данные API.
#### Шаг 4: Настройка Adapty с учётными данными Apple Ads \{#step-4-configure-adapty-with-apple-ads-credentials\}
Скопируйте поля Client ID, Team ID и Key ID из настроек Apple Ads. В дашборде Adapty вставьте эти данные в соответствующие поля.
### Подключение приложения к сети AdServices \{#connect-your-app-to-the-adservices-network\}
После завершения [настройки фреймворка AdServices](#connect-the-adservices-framework) Adapty автоматически начинает собирать данные атрибуции Apple Search Ads. Добавлять какой-либо код в SDK не нужно.
Для iOS-приложений эти данные атрибуции **всегда** будут иметь приоритет над данными из других источников. Если такое поведение нежелательно, *отключите* атрибуцию ASA, следуя инструкциям ниже.
## Отключение интеграции \{#disable-integration\}
Чтобы отключить атрибуцию Apple Search Ads, откройте вкладку [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads) и отключите переключатель **Receive Apple Search Ads attribution**.
:::warning
Обратите внимание: отключение этой опции полностью прекратит получение аналитики ASA. В результате ASA больше не будет использоваться в аналитике и не будет передаваться в интеграции. Кроме того, SplitMetrics Acquire и Asapty перестанут работать, поскольку они зависят от атрибуции ASA.
Атрибуция, полученная до этого изменения, затронута не будет.
:::
## Загрузка собственных ключей \{#uploading-your-own-keys\}
:::note
Необязательно
Эти шаги не требуются для атрибуции Apple Ads — только для работы с другими сервисами, например Asapty, или с собственным решением.
:::
Вы можете использовать собственную пару публичного и приватного ключей, если применяете сторонние сервисы или собственное решение для атрибуции ASA.
### Шаг 1 \{#step-1\}
Сгенерируйте приватный ключ в терминале:
```text showLineNumbers title="Text"
openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem
```
Загрузите его в Adapty Settings -> Apple Ads (кнопка Upload private key).
### Шаг 2 \{#step-2\}
Сгенерируйте публичный ключ в терминале:
```text showLineNumbers title="Text"
openssl ec -in private-key.pem -pubout -out public-key.pem
```
Этот публичный ключ можно использовать в настройках Apple Ads аккаунта с ролью API Account Manager. Таким образом, сгенерированные значения Client ID, Team ID и Key ID можно применять как в Adapty, так и в других сервисах.
---
# File: account
---
---
title: "Данные аккаунта и биллинг"
description: "Управляйте своим аккаунтом Adapty и оптимизируйте настройки для более точного отслеживания подписок."
---
На странице **Account** можно управлять своим профилем, участниками команды и биллингом.
На странице есть три вкладки:
- [Основные настройки](#general-settings)
- [Подписка и биллинг](#billing-info)
- [Участники](#members)
Чтобы открыть настройки аккаунта, нажмите **Account** в правом верхнем углу или перейдите по ссылке [app.adapty.io/account](https://app.adapty.io/account).
## Основные настройки \{#general-settings\}
Вкладка **General** содержит настройки профиля, аккаунта, параметры отображения и конфигурацию отчётов.
- **Profile**: Введите имя, фамилию и название компании. Название компании может содержать до 256 символов.
- **Account settings**: Просмотрите зарегистрированный адрес электронной почты и смените пароль.
- **Date & Time formats**: Выберите формат отображения дат и времени в Adapty:
- **American format**: January 31, 2022 и 12-часовой формат времени (AM/PM)
- **European format**: 31 January, 2022 и 24-часовой формат времени (16:00)
- **Email reports**: Настройте ежедневные, еженедельные или ежемесячные отчёты для одного или всех приложений. Получайте сводные отчёты по всем приложениям сразу или детальный отчёт по каждому выбранному приложению.
## Подписка и биллинг \{#billing-info\}
Вкладка **Subscription & Billing** позволяет управлять платёжными данными и доступом к функциям:
- добавлять или обновлять платёжные реквизиты;
- просматривать информацию о биллинге;
- подключать дополнительные платные функции.
Подробнее о функциях и ценах — на странице [features and pricing](https://adapty.io/pricing).
## Участники \{#members\}
Вы можете управлять участниками команды в настройках аккаунта. Чтобы добавить участника, отправьте приглашение по email и назначьте ему роль.
Подробнее об управлении участниками команды и их правами доступа — [здесь](members-settings).
---
# File: members-settings
---
---
title: "Участники"
description: "Управляйте настройками и правами доступа участников в дашборде Adapty."
---
:::note
Эта страница посвящена участникам дашборда Adapty
Если вы хотите назначить разные уровни доступа пользователям вашего приложения, изучите раздел [Уровни доступа](access-level).
:::
Система участников дашборда Adapty позволяет предоставлять разные уровни доступа к Adapty и указывать приложения для каждого участника.
## Роли \{#roles\}
В дашборде Adapty доступны следующие роли для участников:
| Роль | Доступ к биллингу | Добавление участников | Изменение данных | Доступ ко всем разделам |
|-------------|-------------------|-----------------------|------------------|-------------------------|
| Owner | ✅ | ✅ | ✅ | ✅ |
| Admin | ❌ | ✅ | ✅ | ✅ |
| Developer | ❌ | ❌ | ✅ | ❌ |
| Viewer | ❌ | ❌ | ❌ | ✅ |
| Support | ❌ | ❌ | ❌ | ❌ |
| ASA manager | ❌ | ❌ | ❌ | ❌ |
- **Owner:** Owner — это первоначальный создатель аккаунта Adapty с наивысшим уровнем доступа и контроля. Owner имеет полный доступ к биллингу Adapty, включая управление платёжными данными и тарифными планами. Кроме того, только Owner и Admin могут задавать уровень доступа к приложению для новых участников. В каждом аккаунте Adapty может быть только один Owner.
- **Admin:** Участники с ролью Admin имеют полный доступ к выбранным приложениям. Они могут выполнять различные задачи по управлению: создавать и редактировать пейволы, проводить A/B-тесты, анализировать аналитику и управлять участниками в этих приложениях.
- **Developer:** Участники с ролью Developer имеют полный доступ ко всем сущностям, кроме аналитики и управления участниками аккаунта. Они не имеют доступа к настройкам биллинга. Эта роль предназначена для тех, кто настраивает пейволы, A/B-тесты и другие сущности, а также интегрирует Adapty в приложение, но не должен видеть финансовые данные.
- **Viewer:** Участники с ролью Viewer имеют доступ только для чтения к выбранным приложениям. Они могут просматривать информацию, но не могут создавать или редактировать пейволы, A/B-тесты и другие функции, приглашать новых пользователей, создавать новые приложения и изменять настройки приложения.
- **Support:** Участники с ролью Support имеют доступ только к профилям пользователей в выбранных приложениях. При этом они не могут добавлять новых участников или заходить в другие разделы Adapty. Эта роль особенно подходит для команд поддержки или сотрудников, которым нужно помогать клиентам с вопросами по подпискам или устранением неполадок.
- **ASA manager:** Участники с ролью ASA manager имеют доступ только к дашборду [Adapty Ads Manager](adapty-ads-manager).
## Добавление участника \{#add-a-member\}
В Adapty можно пригласить до 256 участников команды. Добавление новых участников бесплатно.
:::note
Приглашать можно только те email-адреса, которые ещё не зарегистрированы в Adapty. Если у вашего коллеги есть отдельный аккаунт, укажите другой email-адрес или обратитесь в службу поддержки Adapty, чтобы удалить существующий аккаунт.
:::
Чтобы добавить участника команды:
1. Нажмите **Account** в правом верхнем углу и откройте вкладку **Members**.
2. Нажмите **Invite member**.
3. Введите email-адрес участника.
4. Выберите [роль](#roles) из списка.
5. Выберите приложения, к которым нужно предоставить доступ.
6. (Опционально) Включите **Always allow access to new apps**, чтобы автоматически открывать доступ к новым приложениям.
7. Нажмите **Save**.
## Передача прав владельца аккаунта \{#transfer-account-ownership\}
Если вам нужно передать права **владельца аккаунта**, обратитесь в нашу службу поддержки по адресу [support@adapty.io](mailto:support@adapty.io).
Если вам нужно передать права **владельца приложения**, ознакомьтесь с [соответствующим гайдом](transfer-apps).
---
# File: set-up-app-store-connect
---
---
title: "Настройка App Store Connect"
description: "Гайд для начинающих разработчиков по регистрации в программе Apple Developer Program и настройке App Store Connect для встроенных покупок."
---
Если вы **создаёте своё первое iOS-приложение**, вам нужно настроить аккаунт разработчика Apple и App Store Connect до того, как вы начнёте интеграцию с Adapty.
:::note
Если у вас уже есть аккаунт Apple Developer и приложение зарегистрировано в App Store Connect, этот гайд можно пропустить — переходите сразу к [первоначальной интеграции с App Store](initial_ios).
:::
## Шаг 1. Вступите в программу Apple Developer Program \{#step-1-enroll-in-apple-developer-program\}
Чтобы публиковать приложения в App Store и продавать встроенные покупки, необходимо вступить в [Apple Developer Program](https://developer.apple.com/programs/).
### Выберите тип регистрации \{#choose-enrollment-type\}
Apple предлагает два типа регистрации:
| | Физическое лицо | Организация |
|------------------------------------|--------------------------|------------------------------------------|
| **Для кого** | Разработчики-одиночки | Компании, команды, некоммерческие организации |
| **Требуется D-U-N-S номер** | Нет | Да |
| **Приложения публикуются под** | Вашим личным именем | Названием вашей организации |
| **Управление командой** | Недоступно | Доступно |
:::tip
Если вы регистрируетесь как организация, вам потребуется **D-U-N-S номер** — уникальный девятизначный бизнес-идентификатор от Dun & Bradstreet. Вы можете [проверить, есть ли у вашей организации такой номер](https://developer.apple.com/enroll/duns-lookup/), или запросить новый — ссылка находится внизу страницы поиска. Получение D-U-N-S номера может занять до 5 рабочих дней.
:::
### Зарегистрируйтесь \{#enroll\}
1. Перейдите на [страницу регистрации Apple Developer Program](https://developer.apple.com/programs/enroll/).
2. Войдите с помощью Apple ID. Если у вас его нет — сначала создайте.
3. Следуйте инструкциям для вашего типа регистрации (физическое лицо или организация).
4. Оплатите ежегодный взнос.
После того как Apple обработает вашу заявку, вы получите доступ к [App Store Connect](https://appstoreconnect.apple.com). Обычно регистрация занимает до 48 часов. Для организаций процесс может быть дольше, если требуется верификация D-U-N-S номера.
## Шаг 2. Настройте приложение в App Store Connect \{#step-2-set-up-your-app-in-app-store-connect\}
Прежде чем продавать встроенные покупки, завершите первоначальную настройку в App Store Connect: подпишите соглашения, добавьте платёжные данные и зарегистрируйте приложение.
### Подпишите соглашение о платных приложениях \{#sign-the-paid-applications-agreement\}
Apple требует подписания соглашения Paid Applications Agreement, прежде чем вы сможете продавать в App Store. Это касается как платных приложений, так и встроенных покупок в бесплатных.
1. Перейдите на страницу **Business** в [App Store Connect](https://appstoreconnect.apple.com/business).
2. Найдите соглашение **Paid Apps** и нажмите **Review and Agree**.
3. Заполните необходимую информацию:
- **Banking information**: добавьте банковский счёт, на который Apple будет перечислять ваши доходы.
- **Tax information**: заполните налоговые формы для стран, в которых хотите продавать.
- **Contact information**: укажите контактные данные.
:::important
Необходимо заполнить все три раздела (банковские данные, налоги, контакты), чтобы соглашение вступило в силу. Пока соглашение неактивно, продавать встроенные покупки невозможно.
:::
### Создайте Bundle ID \{#create-a-bundle-id\}
Bundle ID уникально идентифицирует ваше приложение в экосистеме Apple. Он нужен для регистрации приложения в App Store Connect и настройки интеграции с Adapty.
1. Откройте [портал Apple Developer](https://developer.apple.com/account).
2. Перейдите в **Certificates, Identifiers & Profiles** → **Identifiers**.
3. Нажмите **+**, чтобы зарегистрировать новый идентификатор.
4. Выберите **App IDs** и нажмите **Continue**.
5. Выберите тип **App** и нажмите **Continue**.
6. Заполните поля:
- **Description**: название, которое поможет вам идентифицировать этот Bundle ID (например, «My Subscription App»).
- **Bundle ID**: выберите **Explicit** и введите уникальный идентификатор в формате обратного домена (например, `com.yourcompany.yourapp`).
7. В разделе **Capabilities** прокрутите вниз и отметьте **In-App Purchase**.
8. Нажмите **Continue**, затем **Register**.
### Зарегистрируйте приложение в App Store Connect \{#register-your-app-in-app-store-connect\}
1. Перейдите на страницу **Apps** в [App Store Connect](https://appstoreconnect.apple.com/apps).
2. Нажмите **+** → **New App**.
3. Заполните обязательные поля:
- **Platforms**: выберите **iOS**.
- **Name**: название приложения, которое будет отображаться в App Store.
- **Primary language**: язык по умолчанию для метаданных вашего приложения.
- **Bundle ID**: выберите Bundle ID, созданный на предыдущем шаге.
- **SKU**: уникальный идентификатор приложения (не виден пользователям). Например, `my_subscription_app_2025`.
4. Нажмите **Create**.
Ваше приложение зарегистрировано в App Store Connect и готово к интеграции с Adapty.
## Что дальше \{#whats-next\}
- [Первоначальная интеграция с App Store](initial_ios): подключите приложение из App Store к Adapty
- [Интеграция SDK](quickstart-sdk): встройте Adapty SDK в код вашего приложения
- [Тестирование в песочнице](test-purchases-in-sandbox): протестируйте встроенные покупки перед релизом
- [Отправка iOS-приложения в App Store](submit-app-to-app-store): загрузите сборку и отправьте на проверку Apple
- [Программа Apple для малого бизнеса](app-store-small-business-program): снизьте комиссию App Store с 30% до 15%
---
# File: app-store-products
---
---
title: "Продукт в App Store"
description: "Эффективно управляйте продуктами App Store с помощью инструментов подписок Adapty."
---
На этой странице описано, как создать продукт в App Store Connect. Эта информация может не иметь прямого отношения к функциональности Adapty, но будет полезна, если у вас возникнут трудности при создании продуктов в вашем аккаунте App Store Connect.
Чтобы создать продукт, который будет привязан к Adapty:
1. Откройте **App Store Connect**. Перейдите в раздел [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) в меню слева.
2. Если вы ещё не создали группу подписок, нажмите кнопку **Create** под заголовком **Subscription Groups**, чтобы начать. [Группы подписок](https://developer.apple.com/help/app-store-connect/manage-subscriptions/offer-auto-renewable-subscriptions) в App Store Connect помогают категоризировать продукты и управлять ими, позволяя пользователям без проблем переключаться между разными предложениями. Обратите внимание: создать подписку вне группы невозможно.
3. В открывшемся окне **Create Subscription Group** введите название новой группы подписок в поле **Reference Name**. Это внутренний идентификатор, который помогает вам различать группы подписок в вашем приложении.
Название группы не видно пользователям — оно используется исключительно для внутренней организации. Оно позволяет легко находить нужные группы подписок при работе в интерфейсе App Store Connect. Это особенно удобно, если у вас несколько предложений подписок или вы хотите структурировать их в соответствии с логикой вашего приложения.
4. Нажмите кнопку **Create**, чтобы подтвердить создание группы подписок.
5. Группа подписок создана и открыта. Теперь можно создавать подписки внутри неё. Нажмите кнопку **Create** под заголовком **Subscriptions**. Если вы добавляете новую подписку в существующую группу, нажмите кнопку **Plus** рядом с заголовком **Subscriptions**.
6. В открывшемся окне **Create Subscription** введите название подписки в поле **Reference Name** и уникальный код подписки в поле **Product ID**.
Reference Name — это уникальный идентификатор встроенной подписки в App Store Connect, не отображаемый пользователям в App Store. Рекомендуем использовать понятное, читаемое описание, точно отражающее суть создаваемой подписки. Длина названия не должна превышать 64 символа.
Product ID — уникальный буквенно-цифровой идентификатор, необходимый для обращения к продукту на этапе разработки и его синхронизации с Adapty. В Product ID допускаются только буквенно-цифровые символы, точки и символы подчёркивания.
7. Нажмите кнопку **Create**, чтобы подтвердить создание подписки.
8. Подписка создана и открыта. Теперь выберите длительность подписки в списке **Subscription Duration**. Даже если длительность уже указана в названии подписки, не забудьте заполнить поле **Subscription Duration**.
9. Теперь нужно настроить цену подписки. Нажмите кнопку **Add Subscription Price** под заголовком Subscription Prices. Возможно, для этого придётся прокрутить страницу вниз.
10. В открывшемся окне **Subscription Price** выберите базовую страну в списке **Country or Region** и базовую валюту в списке **Price**. Позднее Apple автоматически рассчитает цены для всех 175 стран и регионов на основе этой базовой цены и актуальных обменных курсов.
11. Нажмите кнопку **Next**. В открывшемся окне **Price by Country or Region** вы увидите автоматически пересчитанные цены для всех стран. При необходимости их можно изменить.
12. После обновления региональных цен нажмите кнопку **Next** в нижней части окна.
13. В открывшемся окне **Confirm Subscription Price?** внимательно проверьте итоговые цены. Чтобы внести изменения, нажмите кнопку **Back** и вернитесь в окно **Price by Country or Region**. Если цены вас устраивают, нажмите кнопку **Confirm**.
14. После закрытия окна **Confirm Subscription Price?** не забудьте нажать кнопку **Save** в окне подписки. Без этого подписка не будет создана, и все введённые данные будут потеряны.
Обратите внимание: описанные выше шаги касаются настройки автовозобновляемой подписки. Если вы хотите настроить другие типы встроенных покупок, в боковой панели нажмите вкладку **In-App Purchases** вместо **Subscriptions**. Это откроет раздел для управления и создания различных типов встроенных покупок.
### Добавление продуктов в Adapty \{#add-products-to-adapty\}
После того как вы завершили добавление встроенных покупок, подписок и предложений в App Store Connect, следующий шаг — [добавить эти продукты в Adapty](create-product).
---
# File: apple-app-privacy
---
---
title: "Apple App Privacy"
description: "Узнайте о политиках конфиденциальности Apple App Privacy и их влиянии на ваше приложение с подписками."
---
Apple требует раскрытия информации о конфиденциальности для всех новых приложений и обновлений — как в разделе **App Privacy** в App Store Connect, так и в виде файла манифеста приложения. Adapty является сторонней зависимостью вашего приложения, поэтому вам необходимо указать, как вы используете Adapty в отношении данных пользователей.
## Манифест конфиденциальности Apple \{#apple-app-privacy-manifest\}
[Файл манифеста конфиденциальности](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests), называемый `PrivacyInfo.xcprivacy`, описывает, какие персональные данные использует ваше приложение и с какой целью. Каждый владелец приложения обязан создать такой файл. Кроме того, если вы подключаете сторонние SDK, убедитесь, что файлы манифеста для тех из них, которые входят в список [SDK, требующих манифеста конфиденциальности и подписи](https://developer.apple.com/support/third-party-SDK-requirements/), включены в сборку. При компиляции Xcode объединит все эти файлы в один.
Несмотря на то что Adapty не входит в список [SDK, требующих манифеста конфиденциальности и подписи](https://developer.apple.com/support/third-party-SDK-requirements/), версии Adapty SDK 2.10.2 и выше включают его для вашего удобства. Обновите SDK, чтобы получить манифест.
Хотя Adapty не требует включения каких-либо данных в файл манифеста (известный также как отчёт о конфиденциальности приложения), если вы используете `customerUserId` Adapty для отслеживания, необходимо указать это в файле манифеста следующим образом:
1. Добавьте словарь в массив `NSPrivacyCollectedDataTypes` в файле информации о конфиденциальности.
2. Добавьте ключи `NSPrivacyCollectedDataType`, `NSPrivacyCollectedDataTypeLinked` и `NSPrivacyCollectedDataTypeTracking` в этот словарь.
3. Укажите строку `NSPrivacyCollectedDataTypeUserID` (идентификатор типа данных `UserID` в [списке категорий и типов данных, подлежащих указанию в файле манифеста](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests#Describe-the-data-your-app-or-third-party-SDK-collects)) для ключа `NSPrivacyCollectedDataType` в словаре `NSPrivacyCollectedDataTypes`.
4. Укажите значение `true` для ключей `NSPrivacyCollectedDataTypeTracking` и `NSPrivacyCollectedDataTypeLinked` в словаре `NSPrivacyCollectedDataTypes`.
5. Используйте строку `NSPrivacyCollectedDataTypePurposeProductPersonalization` в качестве значения ключа `NSPrivacyCollectedDataTypePurposes` в словаре `NSPrivacyCollectedDataTypes`.
Если вы таргетируете пейволы на аудитории с пользовательскими атрибутами, тщательно проверьте, соответствуют ли используемые атрибуты [категориям и типам данных, подлежащим указанию в файле манифеста](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests). Если да — повторите шаги выше для каждого типа данных.
После того как вы укажете все собираемые типы и категории данных, создайте отчёт о конфиденциальности вашего приложения, как описано в [документации Apple](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests#Create-your-apps-privacy-report).
## Раскрытие информации об Apple App Privacy в App Store Connect \{#apple-app-privacy-disclosure-in-app-store-connect\}
1. В [App Store Connect](https://appstoreconnect.apple.com/) откройте своё приложение и перейдите в раздел **App Privacy**. Нажмите **Get Started**.
2. Выберите **Yes, we collect data from this app** и нажмите **Next**.
### Типы данных \{#data-types\}
В таблице ниже перечислены типы данных, которые Apple обязывает раскрывать, с указанием тех, которые требуются Adapty. **Это относится только к Adapty.** Если ваше приложение собирает дополнительные данные через другие SDK или собственный код, также выберите соответствующие типы данных.
✅ = Требуется Adapty
👀 = Может потребоваться (подробнее см. ниже)
❌ = Не требуется Adapty — выберите, если ваше приложение собирает эти данные другими средствами
| Тип данных | Требуется | Примечание |
|--------------------------------------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------|
| Identifiers | ✅ | Если вы идентифицируете пользователей с помощью customerUserId, выберите 'User ID'.
Adapty собирает IDFA, поэтому необходимо выбрать 'Device ID'.
| | Purchases | ✅ | Adapty собирает историю покупок пользователей. | | Contact Info, в том числе имя, номер телефона или адрес электронной почты | 👀 | Требуется, если вы передаёте персональные данные, такие как имя, номер телефона или адрес электронной почты, с помощью метода **`updateProfile`**. | | Usage Data | 👀 | Может потребоваться, если вы используете аналитические SDK, такие как Amplitude, Mixpanel, AppMetrica или Firebase. | | Location | ❌ | Adapty не собирает точные данные о местоположении. Выберите, если ваше приложение их собирает. | | Health & Fitness | ❌ | Adapty не собирает данные о здоровье или физической активности. Выберите, если ваше приложение их собирает. | | Sensitive Info | ❌ | Adapty не собирает конфиденциальную информацию. Выберите, если ваше приложение её собирает. | | User Content | ❌ | Adapty не собирает пользовательский контент. Выберите, если ваше приложение его собирает. | | Diagnostics | ❌ | Adapty не собирает диагностические данные. Выберите, если ваше приложение их собирает. | | Browsing History | ❌ | Adapty не собирает историю браузера. Выберите, если ваше приложение её собирает. | | Search History | ❌ | Adapty не собирает историю поиска. Выберите, если ваше приложение её собирает. | | Contacts | ❌ | Adapty не собирает списки контактов. Выберите, если ваше приложение их собирает. | | Financial Info | ❌ | Adapty не собирает финансовую информацию. Выберите, если ваше приложение её собирает. | ### Обязательные типы данных \{#required-data-types\} #### Покупки \{#purchases\} При использовании Adapty необходимо раскрыть, что ваше приложение собирает **Purchase History**.
#### Идентификаторы \{#identifiers\}
При использовании Adapty необходимо раскрыть следующие идентификаторы:
- **Device ID** — Adapty собирает IDFA.
- **User ID** — требуется, если вы идентифицируете пользователей с помощью **`customerUserId`**.
### Использование данных \{#data-usage\}
После сохранения **Data types** необходимо указать, как используются данные:
1. Нажмите **Set up purchase history** в блоке **Purchases**.
2. Когда Apple спросит, как используются данные истории покупок, выберите следующее для Adapty:
- **Analytics** — Adapty использует историю покупок для аналитики дохода, когорт и метрик.
- **Product Personalization** — Adapty использует данные о покупках для сегментации аудитории и таргетинга пейволов.
- **App Functionality** — Adapty проверяет покупки, управляет уровнями доступа и отслеживает статус подписки.
Выберите дополнительные цели, если ваше приложение использует данные о покупках другими способами (например, если вы отправляете события покупок на рекламные платформы через интеграции Adapty).
3. Нажмите **Next**.
4. Для **Device ID** и **User ID** (если используется):
1. Нажмите **Set up user/device ID** в блоке **User/Device ID**.
2. Когда Apple спросит, как используются данные идентификатора, выберите следующее для Adapty:
- **App Functionality** — Adapty использует идентификаторы для управления профилями пользователей, связывания покупок и отслеживания уровней доступа.
Если вы отправляете данные атрибуции на сторонние платформы через интеграции Adapty (например, AppsFlyer или Adjust), также выберите **Third-Party Advertising**. Выберите дополнительные цели, если ваше приложение использует идентификаторы другими способами.
5. Нажмите **Next**.
---
# File: apple-family-sharing
---
---
title: "Apple Family Sharing"
description: "Включите Apple Family Sharing в Adapty для поддержки совместных подписок."
---
Функция семейного доступа Apple позволяет распределять встроенные покупки между членами семьи — это удобный способ для пользователей групповых приложений (например, стриминговых сервисов и детских приложений) пользоваться одной подпиской без необходимости делиться Apple ID. Позволяя до пяти членов семьи пользоваться подпиской, [Family Sharing](https://developer.apple.com/documentation/storekit/supporting-family-sharing-in-your-app) способен повысить вовлечённость и удержание пользователей вашего приложения.
В этом гайде мы расскажем, как подключить подписки к Family Sharing и как Adapty управляет покупками, которые используются в рамках семейного доступа.
Чтобы включить Family Sharing для конкретного продукта, перейдите в [App Store Connect](https://appstoreconnect.apple.com/). По умолчанию Family Sharing отключён как для новых, так и для существующих встроенных покупок, поэтому его нужно включать отдельно для каждой встроенной покупки. Сделать это просто: откройте **страницу приложения**, перейдите на страницу нужной встроенной покупки и выберите опцию **Turn On** в разделе Family Sharing.
Имейте в виду: после включения Family Sharing для продукта **его нельзя отключить**, так как это нарушит работу для пользователей, уже поделившихся подпиской с членами семьи.
Также учтите, что совместное использование доступно только для некостребуемых покупок и подписок.
В появившемся модальном окне нажмите кнопку **Confirm**, чтобы завершить настройку. После этого раздел Family Sharing обновится и отобразит сообщение: «This subscription can be shared by everyone in a family group.» Это подтверждает, что подписка теперь доступна для Family Sharing и может использоваться совместно до пяти членами семьи.
Adapty упрощает поддержку Family Sharing — дополнительных усилий не потребуется. Просто [настройте продукты](app-store-products) в App Store, и как только вы **включите** Family Sharing в App Store Connect, оно автоматически заработает в **Adapty** и будет передаваться как событие в вебхук.
:::note
Обратите внимание, что Family Sharing не поддерживается в песочнице.
:::
Следует учитывать, что когда пользователь покупает подписку и открывает к ней доступ членам семьи, до момента, когда подписка становится доступна им, может пройти **до одного часа**. Apple намеренно ввела эту задержку, чтобы дать пользователю время передумать и отменить совместный доступ. Однако при продлении подписки никакой задержки для членов семьи нет.
Когда пользователь приобретает продукт с поддержкой Family Sharing, транзакция появится в его чеке в обычном виде, но с добавлением нового поля `in_app_ownership_type` со значением `PURCHASED.` Кроме того, для всех членов семьи будет создана отдельная транзакция с другими значениями `web_order_line_item_id` и `original_transaction_id` по сравнению с исходной покупкой, а также с полем `in_app_ownership_type` со значением `FAMILY_SHARED.`
Чтобы расчёт выручки был точным, в аналитику Adapty включаются только транзакции с `in_app_ownership_type` равным `PURCHASED`. Транзакции с типом `FAMILY_SHARED` исключаются из метрик выручки и конверсии.
**События для транзакций Family Sharing.**
Для транзакций `FAMILY_SHARED` отправляется только событие **Access level updated**. События подписки для конкретных продуктов для участников семейного доступа не отправляются.
| Событие | `FAMILY_SHARED` | `PURCHASED` |
| --- | --- | --- |
| **Access level updated** | Да | Да |
| **Subscription started** | Нет | Да |
| **Trial started** | Нет | Да |
| **Subscription renewed** | Нет | Да |
| **Subscription expired** | Нет | Да |
| **Subscription refunded** | Нет | Да |
| **Billing issue detected** | Нет | Да |
Если ваша аналитика ориентируется на **Subscription started**, участники семейной подписки там не появятся. Используйте **Access level updated**, чтобы отслеживать активных участников семейного доступа.
Чтобы найти других участников семейной подписки в Adapty, нужно открыть детали события. Сначала найдите оригинальную транзакцию семейной покупки, затем в деталях события найдите другие транзакции с тем же продуктом, датой покупки и датой истечения срока. Так вы определите все семейные транзакции, связанные с исходной покупкой.
---
# File: app-store-small-business-program
---
---
title: "Программа App Store для малого бизнеса"
description: "Узнайте о программе Apple для малого бизнеса, её влиянии на выручку и аналитику Adapty"
---
:::link
Об аналогичной программе в Play Store читайте в разделе [Сниженная комиссия Google](google-reduced-service-fee).
:::
Организации, получающие до 1 миллиона долларов в год от App Store, имеют право участвовать в [программе Apple Small Business](https://developer.apple.com/app-store/small-business-program/). При регистрации стандартная комиссия стора в 30% снижается до **15%**.
Участники программы обязаны **изменить настройки в Adapty**, чтобы обеспечить корректный расчёт выручки и правильную обработку событий интеграций.
---
title: "Программа Small Business Program"
description: "Настройте Adapty для работы с App Store Small Business Program и Google Play Reduced Service Fee, чтобы корректно учитывать сниженную комиссию стора."
metadataTitle: "Программа Small Business Program | Документация Adapty"
---
В этой статье описано:
* [Как настроить Adapty](#configure-adapty), если ваше приложение участвует в программе Small Business Program
* [Как вступить в программу](#apply-for-the-program), если вы хотите снизить комиссию стора
## Настройка Adapty \{#configure-adapty\}
Adapty может учитывать сниженную ставку комиссии в ваших [аналитике](analytics) и [событиях интеграций](analytics-integration). Чтобы включить это, укажите статус участника программы Small Business Program для каждого приложения отдельно.
:::warning
Укажите статус SBP в Adapty **сразу после получения подтверждения**. Изменения, внесённые с опозданием, не перезапишут уже доставленные события вебхуков ([подробнее](#retroactive-setting-changes)).
:::
1. Откройте [**App Settings** → **General**](https://app.adapty.io/account)
2. Найдите раздел **Small Business Program**.
3. Нажмите **Add period**.
4. Выберите дату начала участия в программе.
5. Выберите дату окончания или включите флажок **At the current moment**, чтобы продлить этот статус на неопределённый срок. Если в будущем вы [потеряете право на участие](#losing-eligibility), дату окончания можно будет изменить.
6. Нажмите **Apply**.
Если ваша организация по-прежнему соответствует требованиям программы, членство автоматически переносится на следующий календарный год. Однако статус членства применяется **только к указанному диапазону дат**.
* Нажмите **Add period**, чтобы добавить новый период членства.
* Чтобы сделать этот статус бессрочным, включите флажок **At the current moment**.
Чтобы проверить настройку, откройте [график Revenue](revenue) и выберите **Proceeds after store commission**. Убедитесь, что отображаемая выручка отражает сниженную ставку комиссии.
## Подайте заявку на участие в программе \{#apply-for-the-program\}
### Требования для участия \{#eligibility-requirements\}
Apple определяет право на участие в SBP на основе вашего **годового дохода** — продаж за предыдущий календарный год **после** вычета комиссии стора и налогов.
Чтобы получить право на участие, суммарный годовой доход вашей организации и её
2. Нажмите кнопку **Create subscription**.
3. В открывшемся окне **Create subscription** введите идентификатор подписки в поле **Product ID** и название подписки в поле **Name**.
Product ID должен быть уникальным, начинаться с цифры или строчной буквы, а также может содержать символы подчёркивания (\_) и точки (.). Он используется для доступа к продукту в процессе разработки и его синхронизации с Adapty. После того как Product ID назначен продукту в Google Play Console, его нельзя использовать повторно для других приложений, даже если продукт удалён.
При выборе Product ID рекомендуется придерживаться стандартизированного формата. Мы советуем использовать более лаконичный подход и называть продукт по схеме `<название подписки>.<уровень доступа>`. Длительность и периодичность выставления счетов можно регулировать с помощью базовых планов: еженедельного, ежемесячного и т. д.
Название используется только для вашего удобства — оно будет отображаться в листинге Google Play Store, поэтому можно использовать любое понятное вам название. Максимальная длина — 55 символов.
4. Нажмите кнопку **Create**, чтобы подтвердить создание подписки.
:::note
Продукты подписок Google Play в Adapty
Продукты Adapty соответствуют базовым планам подписок Google Play, поскольку именно их покупают пользователи. Adapty автоматически обрабатывает перенос существующих подписок Google Play вместе с соответствующими базовыми планами в продуктах — никаких дополнительных действий с вашей стороны не требуется. Однако при добавлении нового продукта в Adapty вам нужно будет указать как идентификатор базового плана, так и идентификатор продукта.
:::
### Создание базового плана \{#create-a-base-plan\}
Для продуктов-подписок необходимо добавить базовый план. Базовые планы определяют период выставления счетов, цену и тип возобновления, по которым пользователи приобретают подписку. Обратите внимание, что пользователи не покупают продукт-подписку напрямую — они всегда приобретают базовый план в рамках подписки.
Чтобы создать базовый план:
1. Откройте раздел [**Monetize** -> **Subscriptions**](https://console.cloud.google.com/iam-admin/serviceaccounts) в левом меню Google Play Console и найдите подписку, к которой хотите добавить базовый план.
2. Нажмите кнопку **View subscription** рядом с нужной подпиской.
3. После открытия сведений о подписке нажмите кнопку **Add base plan** под заголовком **Base plans and offers**. Возможно, потребуется прокрутить страницу вниз.
4. В открывшемся окне **Add base plan** введите уникальный идентификатор базового плана в поле **Plan ID**. Он должен начинаться с цифры или строчной буквы и может содержать цифры (0–9), строчные буквы (a–z) и дефисы (-). Заполните остальные обязательные поля.
5. Укажите цены по регионам.
6. Нажмите кнопку **Save**, чтобы завершить настройку.
7. Нажмите кнопку **Activate**, чтобы активировать базовый план.
Обратите внимание, что в Adapty у продуктов-подписок может быть только один базовый план с фиксированной длительностью и типом возобновления.
### Резервные продукты \{#fallback-products\}
:::warning
Поддержка базовых планов без обратной совместимости
Старые версии Adapty SDK не поддерживают возможности Google Billing Library v5+, а именно несколько базовых планов на один продукт-подписку и предложения. С этими версиями SDK доступны только базовые планы, помеченные как **[backwards compatible](https://support.google.com/googleplay/android-developer/answer/12124625?hl=en#backwards_compatible)** в Google Play Console. Обратите внимание, что только один базовый план на подписку может быть помечен как обратно совместимый.
:::
Чтобы в полной мере воспользоваться расширенными конфигурациями и возможностями подписок Google в Adapty, мы предоставляем возможность настройки резервного продукта с обратной совместимостью. Этот резервный продукт используется исключительно для приложений, работающих на старых версиях Adapty SDK. При создании продуктов Google Play теперь можно указать, следует ли пометить продукт как обратно совместимый в Play Console. Adapty использует эту информацию, чтобы определить, может ли продукт быть куплен старыми версиями SDK (версии 2.5 и ниже).
Предположим, у вас есть подписка `subscription.premium` с двумя базовыми планами: еженедельным (обратно совместимым) и ежемесячным. Если вы добавляете продукт `subscription.premium:weekly` в Adapty, указывать обратно совместимый продукт не нужно. Однако для продукта `subscription.premium:monthly` потребуется указать обратно совместимый продукт. Если этого не сделать, в Google Billing Library 4-й версии может произойти непреднамеренная покупка продукта `subscription.premium:weekly`. Чтобы избежать этого, следует создать отдельный продукт, у которого базовый план также является ежемесячным и помечен как обратно совместимый. Это гарантирует, что пользователи, выбравшие вариант `subscription.premium:monthly`, будут корректно тарифицироваться с нужной периодичностью.
## Добавление продуктов в Adapty \{#add-products-to-adapty\}
После того как вы добавили встроенные покупки, подписки и предложения в App Store Connect, следующий шаг — [добавить эти продукты в Adapty](create-product).
---
# File: google-play-data-safety
---
---
title: "Политика безопасности данных Google Play"
description: "Обеспечьте соответствие требованиям политики безопасности данных Google Play в Adapty."
---
Раздел «Безопасность данных» в Google Play предоставляет разработчикам приложений простой способ информировать пользователей о том, какие данные собирает или передаёт их приложение, а также рассказать о ключевых мерах конфиденциальности и безопасности. Эта информация помогает пользователям принимать более взвешенные решения при выборе приложений для загрузки и использования.
Ниже — краткий гайд по данным, которые собирает Adapty, чтобы вы могли предоставить необходимую информацию в Google Play.
## Сбор и безопасность данных \{#data-collection-and-security\}
**Собирает ли ваше приложение или передаёт ли оно какие-либо из обязательных типов пользовательских данных?**
Выберите «Да», так как Adapty собирает историю покупок пользователя.
**Шифруются ли все пользовательские данные, собираемые вашим приложением, при передаче?**
Выберите «Да», так как Adapty шифрует данные при передаче.
**Предоставляете ли вы пользователям возможность запросить удаление их данных?**
Если выбираете «Да», убедитесь, что у ваших пользователей есть способ связаться с вашей службой поддержки для запроса удаления данных. Вы сможете удалить пользователя напрямую из дашборда Adapty или через REST API.
## Типы данных \{#data-types\}
Ниже приведён список типов данных, которые требует Google для отчётности, с указанием того, собирает ли Adapty каждый из них.
| Тип данных | Подробности |
| :-------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Местоположение | Не собирается Adapty |
| Здоровье и фитнес | Не собирается Adapty |
| Фото и видео | Не собирается Adapty |
| Файлы и документы | Не собирается Adapty |
| Календарь | Не собирается Adapty |
| Контакты | Не собирается Adapty |
| Пользовательский контент | Не собирается Adapty |
| История браузера | Не собирается Adapty |
| История поиска | Не собирается Adapty |
| Информация о приложении и производительность | Не собирается Adapty |
| Веб-браузинг | Не собирается Adapty |
| Контактная информация | Не собирается Adapty |
| Финансовая информация | Adapty собирает историю покупок пользователей |
| Личная информация и идентификаторы | Adapty собирает User ID и другие идентифицирующие данные, включая имя, адрес электронной почты, номер телефона и т. д., если вы явно передаёте их в Adapty SDK. |
| Идентификаторы устройств и другие | Adapty собирает данные об идентификаторе устройства. |
## Использование и обработка данных \{#data-usage-and-handling\}
### Идентификаторы пользователей \{#user-ids\}
**1. Эти данные собираются, передаются или и то, и другое?**
Эти данные собираются Adapty. Если вы используете интеграции между Adapty и третьими сторонами, которые не являются поставщиками услуг, вам может потребоваться также указать «Передаются».
**2. Обрабатываются ли эти данные эфемерно?**
Выберите «Нет».
**3. Сбор этих данных обязателен для работы приложения, или пользователи могут отказаться?**
Сбор этих данных обязателен и не может быть отключён.
**4. С какой целью собираются эти пользовательские данные? / С какой целью передаются эти пользовательские данные?**
Отметьте чекбоксы «Функциональность приложения» и «Аналитика».
### Финансовая информация \{#financial-info\}
Если вы используете Adapty, необходимо раскрыть, что ваше приложение собирает информацию «История покупок» из раздела типов данных в Google Play Console.
### Идентификаторы устройств и другие \{#device-or-other-ids\}
## Следующие шаги \{#next-steps\}
После того как вы сделаете выбор в разделе безопасности данных, Google отобразит предварительный просмотр раздела конфиденциальности вашего приложения. Если вы выбрали «Финансовая информация» и «Идентификаторы устройств и другие», как описано выше, информация о конфиденциальности должна выглядеть примерно так:
Если вы готовы отправить приложение на проверку, обратитесь к нашему документу [Чеклист перед релизом](release-checklist) для получения дальнейших инструкций по подготовке приложения к публикации.
---
# File: google-reduced-service-fee
---
---
title: "Сниженная комиссия Google"
description: "Узнайте о сниженной комиссии Google, её влиянии на вашу выручку и аналитику Adapty"
---
:::link
Аналогичная программа для App Store описана в разделе [Программа App Store Small Business Program](app-store-small-business-program).
:::
Программа Google Play [Reduced Service Fee](https://support.google.com/googleplay/android-developer/answer/112622?hl=en) снижает комиссию с первого миллиона USD годового дохода с 30% до **15%**. Доход свыше миллиона USD в том же календарном году облагается стандартной ставкой 30%.
:::note
С 1 января 2022 года Google взимает 15% со всех автообновляемых подписок вне зависимости от этой программы. Reduced Service Fee в первую очередь выгодна для разовых встроенных покупок и платных приложений.
:::
Участники программы должны **изменить настройки Adapty**, чтобы корректно рассчитывать доходы и обрабатывать события интеграций.
В этой статье описано:
* [Как настроить Adapty](#configure-adapty), если ваше приложение участвует в программе Reduced Service Fee
* [Как вступить в программу](#enroll-in-the-program), если вы хотите снизить комиссию стора
## Настройка Adapty \{#configure-adapty\}
Adapty может учитывать сниженную ставку комиссии в ваших [аналитических данных](analytics) и [событиях интеграций](analytics-integration). Чтобы это заработало, укажите статус Reduced Service Fee для каждого приложения отдельно.
:::warning
Настройте статус Reduced Service Fee в Adapty **сразу после подключения к программе**. Изменения не применяются задним числом к уже доставленным событиям вебхуков ([подробнее](#retroactive-setting-changes)).
:::
1. Откройте [**App Settings** → **General**](https://app.adapty.io/account).
2. Найдите раздел **Reduced Service Fee**.
3. Нажмите **Add period**.
4. Выберите дату начала участия в программе.
5. Выберите дату окончания или включите чекбокс **At the current moment**, чтобы продлить этот статус на неопределённый срок. Если ваш [годовой доход превысит 1 миллион USD](#exceeding-the-threshold), вы сможете изменить дату окончания.
6. Нажмите **Apply**.
Статус участника применяется **только к указанному вами диапазону дат**. Программа сбрасывается каждый календарный год.
* Нажмите **Add period**, чтобы добавить новый период участия.
* Чтобы сделать статус бессрочным, включите флажок **At the current moment**.
Чтобы проверить настройку, откройте [график Revenue](revenue) и выберите **Proceeds after store commission**. Убедитесь, что отображаемая выручка отражает сниженную ставку комиссии.
## Запись в программу \{#enroll-in-the-program\}
### Требования к участию \{#eligibility-requirements\}
Google определяет право на участие на основе вашего **годового дохода** по всем аккаунтам в вашей | Опция | Описание | | ------- | ------------------------------------------------------------ | | Opt-out | (по умолчанию) Если Adapty не знает статус согласия пользователя, предполагается, что согласие **было дано**, и Refund Saver **передаст** данные о возвратах в Apple. | | Opt-in | Если Adapty не знает статус согласия пользователя, предполагается, что согласие **не было дано**, и Refund Saver **не передаст** никакие данные в Apple. Это рекомендованный Apple подход. | ## Обновление согласия пользователя в SDK \{#update-user-consent-in-the-sdk\} Чтобы сообщить Adapty, дал ли конкретный пользователь согласие, используйте метод `updateCollectingRefundDataConsent`. Значение сохраняется на сервере для каждого профиля, поэтому вызывать его нужно только при изменении согласия.
:::note Для отслеживания событий подписки используйте интеграцию [Webhook](webhook) в Adapty или интегрируйтесь напрямую с вашим существующим сервисом. ::: ::: ## Случай 1: синхронизация подписчиков между вебом и мобильным приложением \{#case-1-sync-subscribers-between-web-and-mobile\} Если вы используете веб-провайдеры платежей, например Stripe, ChargeBee или другие, вы можете легко синхронизировать своих подписчиков. Вот как это сделать: 1.
2. Введите понятное название онбординга и нажмите **Proceed to build onboarding**.
3. Вы будете перенаправлены в конструктор онбординга.
Он содержит демо-шаблон по умолчанию, на котором можно изучить, как онбординги собирают данные и как их можно персонализировать с помощью переменных и квизов. Удаляйте ненужные экраны и [создавайте собственный онбординг](design-onboarding) на своё усмотрение.
4. Когда будете готовы, нажмите кнопку **Preview** в правом верхнем углу. Пройдите онбординг самостоятельно, чтобы убедиться, что всё работает как ожидается.
5. Если всё работает корректно, нажмите **Publish** в правом верхнем углу. Дождитесь завершения публикации, прежде чем возвращаться в Adapty. Иначе ваши изменения будут потеряны.
:::danger
Если вы не нажмёте **Publish**, SDK не сможет получить созданный онбординг.
:::
После публикации онбординга нажмите **Back to Adapty**. Онбординг создан — теперь вы можете добавить его в плейсмент и начать использовать.
## Шаг 2. Создайте плейсмент для онбординга \{#step-2-create-a-placement-for-your-onboarding\}
1. Перейдите в **Placements** из главного меню и откройте вкладку **Onboardings**. Нажмите **Create placement**.
2. Введите название и ID плейсмента. Затем нажмите **Run onboarding** и выберите онбординг, который будет показан всем пользователям.
3. Если у вас есть отдельный онбординг для определённой группы пользователей, [добавьте дополнительные аудитории](audience) и выберите для них другой онбординг.
## Шаг 3. Интегрируйте онбординг в своё приложение \{#step-3-integrate-the-onboarding-into-your-app\}
:::important
Онбординги доступны для приложений, использующих Adapty SDK v3.8.0+ (iOS, Android, React Native, Flutter), v3.14.0+ (Unity) или v3.15.0+ (Kotlin Multiplatform, Capacitor).
:::
Чтобы начать показывать онбординги в своём приложении, интегрируйте их с помощью Adapty SDK:
- [iOS](ios-onboardings)
- [Android](android-onboardings)
- [React Native](react-native-onboardings)
- [Flutter](flutter-onboardings)
- [Unity](unity-onboardings)
- [Kotlin Multiplatform](kmp-onboardings)
- [Capacitor](capacitor-onboardings)
Чтобы понять, какой онбординг работает лучше, вы также можете запустить [A/B-тесты](ab-tests).
---
# File: design-onboarding
---
---
title: "Дизайн онбордингов"
description: "Создавайте полноценные онбординги."
---
No-code конструктор онбордингов для мобильных приложений — мощный и гибкий инструмент, который поможет вам создать лучший опыт онбординга для ваших пользователей. Быть разработчиком или дизайнером для этого не нужно.
## Экраны онбординга \{#onboarding-screens\}
Онбординг состоит из нескольких экранов, которые вы добавляете и оформляете.
Пользователи будут переходить между ними, нажимая кнопку.
:::tip
Если часть ваших пользователей нуждается в немного другом флоу (например, в фитнес-приложении вы хотите показывать разные изображения «цели» в зависимости от пола пользователя), создавать отдельные онбординги не нужно.
Вместо этого можно сделать некоторые экраны скрытыми по умолчанию и отображать их только в определённых сценариях.
:::
## Элементы онбординга \{#onboarding-elements\}
Элементы онбординга отображаются слева в том порядке, в котором они показываются. Нажмите **Add** в правом верхнем углу, чтобы добавить новый элемент.
Доступны следующие группы элементов:
- **Containers**: Контейнеры позволяют настроить гибкую раскладку. Например, если вы хотите добавить текст в две колонки, добавьте **Columns**, а затем перетащите два текстовых блока в **Columns** на левой панели. Или, если вы добавляете карусель, нужно добавить изображения в элементы **Media** внутри неё.
- **Typography**: Добавляйте предварительно отформатированные текстовые блоки и настраивайте их внешний вид по мере необходимости.
- **Media & Display**: Помимо изображений и видео, можно добавлять анимированные графики, демонстрирующие ценность вашего приложения и мотивирующие пользователей.
**Поддерживаемые форматы видео**: MP4 и WebM. **Максимальный размер медиафайла** — 15 МБ.
Если вы хотите добавить неподдерживаемый анимированный элемент (например, Lottie), можно конвертировать его в видео (например, с помощью [этого инструмента](https://www.lottielab.com/lottie/lottie-to-video)) и вставить как видео.
- **Quiz**: Создавайте короткие опросы с текстовыми и графическими вариантами ответов, чтобы персонализировать онбординг и лучше узнать своих пользователей.
- **Inputs**: Собирайте данные от пользователей.
- **Buttons**: Кнопки позволяют пользователям переходить между экранами, закрывать онбординг или переходить к пейволу. Можно также добавлять глянцевые или анимированные кнопки, чтобы привлечь внимание пользователей и повысить конверсию из установки в покупку.
- **Loaders**: Анимированные лоадеры удерживают внимание пользователей в процессе ожидания.
- **User engagement**: Добавляйте отзывы, списки email-адресов пользователей и обратные отсчёты.
:::note
В рамках группы **Media & Display** можно также добавить пользовательский HTML-код, если встроенных возможностей кастомизации недостаточно.
Однако пользовательские HTML-элементы не предзагружаются и не кешируются, поэтому **Raw HTML** рекомендуется использовать только для небольших и лёгких элементов.
:::
### ID элемента и ID действия \{#element-id-and-action-id\}
Если вы хотите использовать кнопку для пользовательских действий, назначьте ей **action ID** и используйте его в исходном коде. Action ID позволяет одинаково обрабатывать разные кнопки с одним и тем же action ID.
Если вы хотите обрабатывать пользовательский ввод в конкретном поле (например, сохранять возраст или email), назначьте ему **element ID** и используйте его в исходном коде для связывания вопросов с ответами. Element ID можно использовать в онбординге только один раз.
## Параметры кастомизации \{#customization-options\}
В конструкторе доступны следующие параметры кастомизации:
- Вкладка **Styles**: Настройте внешний вид элемента.
- Вкладка **Element**: Задайте атрибуты элемента: видимость, действия при нажатии кнопок и другие свойства, не связанные с внешним видом элемента.
- Вкладка **Screen**: Настройте общую конфигурацию экрана: заголовок или отображение счётчика экранов.
## Копирование экранов и элементов \{#copy-screens-and-elements\}
Если вы создали онбординг и хотите повторно использовать его части, или хотите внести небольшие изменения и запустить A/B-тесты, можно скопировать один или несколько экранов из одного онбординга в другой.
Чтобы скопировать экраны, откройте конструктор онбордингов и выполните одно из следующих действий:
- Кликните правой кнопкой мыши по отдельному экрану и выберите **Copy**
- Выберите нужный экран и нажмите `Ctrl+C` (Windows) или `⌘+C` (Mac)
Также можно копировать отдельные элементы или текстовые блоки — как в рамках одного онбординга, так и между разными онбордингами.
## Копирование экранов из web-to-app воронок \{#copy-screens-from-web-to-app-funnels\}
Если вы используете web-to-app воронки, созданные в [FunnelFox](https://funnelfox.com/), и хотите использовать экраны из воронок в онбордингах, это можно быстро сделать, скопировав экраны в конструкторе воронок и вставив их в конструктор онбордингов:
1. В конструкторе воронок FunnelFox кликните правой кнопкой мыши по экрану и выберите **Copy**, или выберите экран и нажмите `Ctrl+C`/`⌘+C`.
2. Откройте конструктор онбордингов.
3. Кликните правой кнопкой мыши по экрану, ниже которого хотите вставить скопированный экран, и выберите **Paste**, или выберите его и нажмите `Ctrl+V`/`⌘+V`. Скопированный экран будет вставлен ниже выбранного.
---
# File: adapty-paywall-builder
---
---
title: "Adapty Paywall Builder (Legacy)"
description: "Создавайте пейволы и онбординги с помощью визуального редактора без кода."
---
:::warning
Paywall Builder полностью функционален, но Adapty больше не добавляет новые функции и не выпускает обновления для него. Для новых проектов рекомендуем рассмотреть [Adapty Flow Builder](adapty-flow-builder) — визуальный no-code редактор для одноэкранных пейволов и многоэкранных онбординг-флоу, которые рендерятся нативно на устройстве:
- **Любой тип флоу**: создавайте одноэкранные пейволы, многошаговые онбординги с пейволом и всё, что между ними.
- **Нативный рендеринг**: флоу отображаются через SDK Adapty, без веб-вью.
- **Обновление без релиза**: меняйте тексты, дизайн или логику в любой момент — обновления доходят до пользователей без выпуска новой версии приложения.
:::
**Paywall Builder** в Adapty — это визуальный no-code инструмент для создания кастомных пейволов. Вы можете начать с готового шаблона, настроить макет и добавить такие элементы, как карусели, карточки, списки продуктов и футеры. Также поддерживаются кастомные шрифты, теги продуктов и локализация.
Paywall Builder требует Adapty SDK версии 3.0 или выше. После того как пейвол готов, [добавьте его в плейсмент](add-audience-paywall-ab-test) и отобразите в приложении:
- [iOS](ios-quickstart-paywalls)
- [Android](android-quickstart-paywalls)
- [React Native](react-native-quickstart-paywalls)
- [Flutter](flutter-quickstart-paywalls)
- [Unity](unity-quickstart-paywalls)
- [Capacitor](capacitor-quickstart-paywalls)
- [Kotlin Multiplatform](kmp-quickstart-paywalls)
---
# File: flutterflow
---
---
title: "Плагин Adapty для FlutterFlow"
description: "Интегрируйте FlutterFlow с Adapty для расширенного управления подписками."
---
Adapty — универсальная платформа, созданная для роста мобильных приложений. Независимо от того, только ли вы начинаете или у вас уже тысячи пользователей, Adapty позволяет сэкономить месяцы на интеграции встроенных покупок и удвоить доход от подписок с помощью управления пейволами.
Плагин Adapty для FlutterFlow позволяет использовать все возможности Adapty без написания кода. Вы можете проектировать страницы пейволов во FlutterFlow, подключать для них покупки, а затем удалённо управлять тем, какие продукты на них отображаются, — в том числе с таргетингом на конкретные группы пользователей или с помощью A/B-тестов. После выпуска приложения вы сразу получите доступ к подробной аналитике покупок ваших клиентов прямо в нашем дашборде.
Хотите обновить продукты, доступные на вашем пейволе? Всё просто! Внесите изменения в несколько кликов в дашборде Adapty, и ваши клиенты сразу увидят новые продукты — без необходимости выпускать новую версию приложения!
Что ещё предлагает Adapty:
- **Подписки и встроенные покупки**: Adapty берёт на себя серверную валидацию чеков и синхронизирует ваших клиентов на всех платформах, включая веб.
- **A/B-тесты для пейволов**: Тестируйте разные цены, длительности, пробные периоды и визуальные элементы, чтобы оптимизировать предложения по подпискам и разовым покупкам.
- **Мощная аналитика**: Получайте подробные метрики, чтобы лучше понимать монетизацию приложения и улучшать её.
- **Интеграции**: Adapty легко подключается к сторонним аналитическим инструментам — Amplitude, AppsFlyer, Adjust, Branch, Mixpanel, Facebook Ads, AppMetrica, пользовательским вебхукам и другим сервисам.
---
# File: ff-getting-started
---
---
title: "Начало работы"
description: "Начните работу с Feature Flags в Adapty для персонализации подписочных потоков."
---
С помощью Adapty вы можете создавать и запускать пейволы и A/B-тесты в разных точках пользовательского пути в мобильном приложении: например, в онбординге, настройках и так далее. Такие точки называются [плейсментами](placements). Один плейсмент может управлять несколькими пейволами или [A/B-тестами](ab-tests) одновременно — каждый из них предназначен для определённой группы пользователей, которую мы называем [аудиторией](audience). Кроме того, вы можете экспериментировать с пейволами, заменяя один на другой без выпуска новой версии приложения. Единственное, что жёстко прописывается в мобильном приложении — это идентификатор плейсмента.
Библиотека Adapty поддерживает актуальность вашего пейвола, синхронизируя его с последними продуктами из дашборда Adapty. Она [получает данные о продуктах](ff-action-flow) и [отображает их на пейволе](ff-add-variables-to-paywalls), [обрабатывает покупки](ff-make-purchase) и [проверяет уровень доступа пользователя](ff-check-subscription-status), чтобы определить, следует ли открыть ему платный контент.
Для начала работы [добавьте библиотеку Adapty](ff-getting-started#add-the-adapty-library-as-a-dependency) в свой проект FlutterFlow и [инициализируйте её](ff-getting-started#initiate-adapty-plugin), как показано ниже.
:::warning
Перед началом работы обратите внимание на следующие ограничения:
- Библиотека Adapty для FlutterFlow не поддерживает веб-приложения. Не компилируйте веб-приложения с её использованием.
- Библиотека Adapty для FlutterFlow не поддерживает пейволы, созданные с помощью Paywall Builder. Вам нужно самостоятельно разработать пейвол во FlutterFlow, прежде чем подключать покупки через Adapty.
:::
## Добавление библиотеки Adapty как зависимости \{#add-the-adapty-library-as-a-dependency\}
1. В [FlutterFlow Dashboard](https://app.flutterflow.io/dashboard) откройте свой проект и нажмите **Settings and Integrations** в левом меню. В разделе **Project setup** слева выберите **Project dependencies**.
2. В разделе **FlutterFlow Libraries** нажмите **Add Library** и введите `adapty-xtuel0`. Нажмите **Add**.
3. Теперь нужно привязать ваш SDK-ключ к библиотеке. Нажмите **View details** рядом с библиотекой.
4. Скопируйте **Public SDK key** со вкладки [**App Settings** -> **General**](https://app.adapty.io/settings/general) в дашборде Adapty.
5. Вставьте ключ в поле **AdaptyApiKey** во FlutterFlow.
Библиотека Adapty FF будет добавлена в ваш проект как зависимость. В окне библиотеки **Adapty** FF вы найдёте все ресурсы Adapty, импортированные в проект.
## Вызов действия активации при запуске приложения \{#call-the-new-activation-action-at-application-launch\}
1. Перейдите в раздел **Custom Code** в левом меню и откройте `main.dart`.
2. Нажмите **+** и выберите `activate (Adapty)`.
3. Нажмите **Save**.
## Инициализация плагина Adapty \{#initiate-adapty-plugin\}
Чтобы дашборд Adapty распознал ваше приложение, нужно указать специальный ключ во FlutterFlow.
1. В своём проекте FlutterFlow перейдите в **Settings and Integrations > Permissions** через левое меню.
2. В открывшемся окне **Permissions** нажмите кнопку **Add Permission**.
3. В полях **iOS Permission Key** и **Android Permission Key** введите `AdaptyPublicSdkKey`.
4. В поле **Permission Message** вставьте **Public SDK key** со вкладки [**App Settings** -> **General**](https://app.adapty.io/settings/general) в дашборде Adapty. У каждого приложения свой SDK-ключ, поэтому если у вас несколько приложений, убедитесь, что выбрали нужный.
После выполнения этих шагов вы сможете вызвать пейвол в своём FlutterFlow-приложении и настроить покупки через него.
## Что дальше? \{#whats-next\}
1. [Создайте action flow](ff-action-flow) для обработки продуктов пейвола Adapty и их данных во FlutterFlow.
2. [Привяжите полученные данные к пейволу](ff-add-variables-to-paywalls), который вы разработали во FlutterFlow.
3. [Настройте кнопку покупки](ff-make-purchase) на пейволе, чтобы транзакции обрабатывались через Adapty при нажатии.
4. Наконец, [добавьте проверку статуса подписки](ff-check-subscription-status), чтобы определять, нужно ли показывать пользователю платный контент.
---
# File: ff-action-flow
---
---
title: "Шаг 1. Создание флоу для отображения данных пейвола"
description: "Настройте флоу действий для feature flag в Adapty, чтобы персонализировать подписки пользователей."
---
:::important
При использовании плагина FlutterFlow нельзя использовать пейволы, созданные в Adapty Paywall Builder. Необходимо реализовать собственную страницу пейвола в FlutterFlow и подключить её к Adapty.
:::
После добавления библиотеки Adapty в качестве зависимости в ваш проект FlutterFlow, пора создать флоу, который **получает данные пейвола и продуктов Adapty и отображает их на пейволе, разработанном в FlutterFlow**.
Сначала нужно получить данные пейвола от Adapty. Начнём с запроса пейвола Adapty, затем связанных с ним продуктов и проверки успешности получения данных. Если всё прошло успешно — отобразим название продукта и цену на странице пейвола. В противном случае покажем сообщение об ошибке.
Прежде чем продолжить, убедитесь, что вы выполнили следующее:
1. [Создали хотя бы один пейвол и добавили в него хотя бы один продукт](create-paywall) в дашборде Adapty.
2. [Создали хотя бы один плейсмент](create-placement) и [добавили в него свой пейвол](add-audience-paywall-ab-test) в дашборде Adapty.
Приступим!
## Шаг 1.1. Запрос пейвола Adapty \{#step-11-request-adapty-paywall\}
Как уже упоминалось, для отображения данных на пейволе FlutterFlow сначала нужно получить их от Adapty. Первый шаг — получить сам пейвол Adapty. Вот как это сделать:
1. Откройте экран пейвола и перейдите в раздел **Actions** на правой панели. Там откройте **Action Flow Editor**.
2. В окне **Select Action Trigger** выберите **On Page Load**.
3. Нажмите **Add Action**. Затем найдите кастомное действие `getPaywall` и выберите его.
4. В разделе **Set Actions Arguments** введите реальный ID [плейсмента, который вы создали](create-placement) в дашборде Adapty и который включает нужный пейвол. В примере это `monthly`. Обязательно используйте свой реальный ID плейсмента!
5. Если вы [локализовали](localizations-and-locale-codes) свой пейвол в дашборде Adapty, вы также можете задать аргумент **locale**.
6. В поле **Action Output Variable Name** создайте новую переменную и назовите её `getPaywallResult`. Она понадобится на следующем шаге для обращения к пейволу Adapty и запроса его продуктов.
## Шаг 1.2. Запрос продуктов пейвола Adapty \{#step-12-request-adapty-paywall-products\}
Отлично! Мы получили пейвол Adapty. Теперь запросим продукты, связанные с ним:
1. Нажмите **+** под созданным действием и выберите **Add Action**. Это действие получит продукты пейвола Adapty. Для этого найдите и выберите `getPaywallProducts`.
2. В разделе **Set Actions Arguments** выберите созданную ранее переменную `getPaywallResult`.
3. Заполните остальные поля следующим образом:
- **Available Options**: Data Structured Field
- **Select Field**: value
- **Available Options**: без изменений
4. Нажмите **Confirm**.
5. В поле **Action Output Variable Name** создайте новую переменную и назовите её `getPaywallProductsResult`. С её помощью мы свяжем разработанный в FlutterFlow пейвол с данными пейвола Adapty.
## Шаг 1.3. Добавление проверки успешной загрузки пейвола \{#step-13-add-check-if-the-paywall-uploaded-successfully\}
Прежде чем двигаться дальше, проверим, что пейвол Adapty был получен успешно. Если да — обновим пейвол данными продуктов. Если нет — обработаем ошибку. Вот как добавить эту проверку:
1. Нажмите **+** и выберите **Add Conditional**.
2. В разделе **Action Output** выберите созданную ранее переменную результата действия (`getPaywallResult` в нашем примере).
3. Чтобы проверить, что пейвол Adapty получен, убедитесь в наличии поля со значением. Заполните поля следующим образом:
- **Available Options**: Has Field
- **Field (AdaptyGetPaywallResult)**: value
4. Нажмите **Confirm**, чтобы завершить создание условия.
## Шаг 1.4. Логирование просмотра пейвола \{#step-14-log-the-paywall-review\}
Чтобы аналитика Adapty фиксировала просмотры пейвола, нужно залогировать это событие. Без этого шага просмотр не будет учтён в аналитике. Вот как это сделать:
1. Нажмите **+** под меткой **TRUE** и выберите **Add Action**.
2. В поле **Select Action** найдите и выберите **logShowPaywall**.
3. Нажмите **Value** в области **Set Action Arguments** и выберите созданную переменную `getPaywallResult`. Эта переменная содержит данные пейвола.
4. Заполните поля следующим образом:
- **Available Options**: Data Structured Field
- **Select Field**: value
5. Нажмите **Confirm**.
## Шаг 1.5. Отображение ошибки при неполучении пейвола \{#step-15-show-error-if-paywall-not-received\}
Если пейвол Adapty не получен, необходимо [обработать ошибку](error-handling-on-flutter-react-native-unity#system-storekit-codes). В этом примере мы просто покажем диалоговое окно с сообщением.
1. Добавьте действие **Informational Dialog** к метке **FALSE**.
2. В поле **Title** введите текст, который хотите видеть в качестве заголовка диалога. В этом примере — **Error**.
3. Нажмите **Value** в поле **Message**.
4. Заполните поля следующим образом:
- **Set Variable**: переменная `getPaywallProductResult`, которую мы создали
- **Available Options**: Data Structure Field
- **Select Field**: error
- **Available Options**: Data Structure Field
- **Select Field**: errorMessage
5. Нажмите **Confirm**.
6. Добавьте действие **Terminate action** во флоу **FALSE**.
7. Нажмите **Close** в правом верхнем углу.
Поздравляем! Вы успешно получили данные продуктов. Теперь давайте [свяжем их с пейволом, разработанным в FlutterFlow](ff-add-variables-to-paywalls).
---
# File: ff-add-variables-to-paywalls
---
---
title: "Шаг 2. Добавление данных на страницу пейвола"
description: "Добавьте переменные Feature Flag на пейволы в Adapty."
---
После того как вы [получили все необходимые данные о продукте](ff-action-flow), самое время привязать их к красивому пейволу, который вы оформили в FlutterFlow. В этом примере мы привяжем название продукта и его цену.
## Шаг 2.1. Добавление названия продукта на страницу пейвола \{#step-21-add-product-title-to-paywall-page\}
1. Дважды кликните по тексту продукта на странице пейвола. В окне **Set from Variable** найдите переменную `getPaywallProductResult` и выберите её.
2. Заполните поля следующим образом:
- **Available Options**: Data Structured Field
- **Select Field**: value
- **Available Options**: Item at Index
- **List Index Options**: First
- **Available Options**: Data Structured Field
- **Select Field**: localizedTitle
- **Default Variable Value**: null
- **UI Builder Display Value**: Любое значение, в примере это `product.title`
3. Нажмите **Confirm**, чтобы сохранить изменения.
## Шаг 2.2. Добавление текста с ценой на страницу пейвола \{#step-22-add-price-text-to-paywall-page\}
Повторите шаги из раздела 2.1 для текста с ценой, как показано ниже:
1. Дважды кликните по тексту цены на странице пейвола. В окне **Set from Variable** найдите переменную `getPaywallProductResult` и выберите её.
2. Заполните поля следующим образом:
- **Available Options**: Data Structured Field
- **Select Field**: value
- **Available Options**: Item at Index
- **List Index Options**: First
- **Available Options**: Data Structured Field
- **Select Field**: price
- **Default Variable Value**: null
- **UI Builder Display Value**: Любое значение, в примере это `product.price`
3. Нажмите кнопку **Confirm**, чтобы сохранить изменения.
### Добавление цены в местной валюте на страницу пейвола \{#add-price-in-local-currency-to-paywall-page\}
1. Дважды кликните по цене на странице пейвола. В окне **Set from Variable** найдите переменную `getPaywallProductResult` и выберите её.
2. Заполните поля следующим образом:
- **Available Options**: Data Structured Field
- **Select Field**: value
- **Available Options**: Item at Index
- **List Index Options**: First
- **Available Options**: Data Structured Field
- **Select Field**: price
- **Available Options**: Data Structured Field
- **Select Field**: amount
- **Available Options**: Decimal
- **Decimal Type**: Automatic
- **Default Variable Value**: null
- **UI Builder Display Value**: Любое значение, в примере это `price.amount`
3. Нажмите **Confirm**, чтобы сохранить изменения.
Вуаля! Теперь при запуске приложения данные продукта из пейвола Adapty будут отображаться прямо на странице вашего пейвола!
Пора [дать пользователям возможность купить этот продукт](ff-make-purchase).
---
# File: ff-make-purchase
---
---
title: "Шаг 3. Включение покупки"
description: "Узнайте, как совершать покупки с помощью системы Feature Flags."
---
Поздравляем! Вы успешно [настроили пейвол для отображения данных о продуктах из Adapty](ff-add-variables-to-paywalls), включая название и цену продукта.
Теперь перейдём к финальному шагу — дадим пользователям возможность совершить покупку через пейвол.
## Шаг 3.1. Включите возможность покупки для пользователей \{#step-31-enable-users-to-make-purchases\}
1. Дважды кликните кнопку покупки на странице пейвола. В правой панели откройте раздел **Actions**, если он ещё не открыт.
2. Откройте **Action Flow Editor**.
3. В окне **Select Action Trigger** выберите **On Tap**.
4. В окне **No Actions Created** нажмите **Add Action**. Найдите действие `makePurchase` и выберите его.
5. В разделе **Set Actions Arguments** выберите переменную `getPaywallProductsResult`, созданную ранее.
6. Заполните поля следующим образом:
- **Available Options**: Data Structure Field
- **Select Field**: value
- **Available Options**: Item at Index
- **List Index Options**: First
7. Нажмите `subscriptionUpdateParameters`, найдите `AdaptySubscriptionUpdateParameters` и выберите его. Нажмите **Confirm**.
:::info
По умолчанию все поля объекта можно оставить пустыми. Их нужно заполнять только при замене одной подписки другой в Android-приложениях. Подробнее читайте [здесь](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/).
:::
8. Нажмите **Confirm**.
9. В поле **Action Output Variable Name** создайте новую переменную и назовите её `makePurchaseResult` — она понадобится позже для подтверждения успешной покупки.
## Шаг 3.2. Проверьте, прошла ли покупка успешно \{#step-32-check-if-the-purchase-was-successful\}
Теперь настроим проверку того, что покупка была выполнена.
1. Нажмите **+** и выберите **Add Conditional**.
2. В разделе **Set Condition for Action** выберите переменную `makePurchaseResult`.
3. В окне **Set Variable** заполните поля следующим образом:
- **Available Options**: Has Field
- **Select Field**: profile
4. Нажмите **Confirm**.
## Шаг 3.3. Откройте платный контент \{#step-33-open-paid-content\}
Если покупка прошла успешно, можно открыть доступ к платному контенту. Вот как это настроить:
1. Нажмите **+** под меткой **TRUE** и выберите **Add Action**.
2. В поле **Define Action** найдите и выберите страницу, которую хотите открыть, из списка **Navigate To**. В данном примере это страница **Questions**.
## Шаг 3.4. Показ сообщения об ошибке при неудачной покупке \{#step-34-show-error-message-if-purchase-failed\}
Если покупка не прошла, покажем пользователю соответствующее уведомление.
1. Добавьте действие **Informational Dialog** к метке **FALSE**.
2. В поле **Title** введите текст заголовка диалога, например **Purchase Failed**.
3. Нажмите **Value** в поле **Message**. В окне **Set from Variable** найдите `makePurchaseResult` и выберите его. Заполните поля следующим образом:
- **Available Options**: Data Structure Field
- **Select Field**: error
- **Available Options**: Data Structure Field
- **Select Field**: errorMessage
4. Нажмите **Confirm**.
5. Добавьте действие **Terminate** в ветку **FALSE**.
6. Наконец, нажмите **Close** в правом верхнем углу.
Поздравляем! Теперь пользователи могут приобретать ваши продукты. В качестве дополнительного шага [настройте проверку доступа пользователей к платному контенту](ff-check-subscription-status) в других местах приложения, чтобы решить — показывать им платный контент или пейвол.
---
# File: ff-check-subscription-status
---
---
title: "Шаг 4. Проверка доступа к платному контенту"
description: "Узнайте, как проверять статус подписки с помощью флагов функций Adapty для более точной сегментации пользователей."
---
Чтобы определить, есть ли у пользователя доступ к определённому платному контенту, нужно проверить его уровень доступа. Это означает, что у пользователя должен быть хотя бы один уровень доступа, и он должен быть нужным.
Это можно сделать, проверив профиль пользователя, который содержит все доступные уровни доступа.
Теперь давайте разрешим пользователям покупать ваш продукт:
1. Дважды щёлкните по кнопке, которая должна открывать платный контент, и откройте раздел **Actions** на правой панели, если он ещё не открыт.
2. Откройте **Action Flow Editor**.
3. В окне **Select Action Trigger** выберите **On Tap**.
4. В окне **No Actions Created** нажмите кнопку **Add Conditional Action**.
5. Нажмите **UNSET**, чтобы задать аргументы действия, и выберите переменную `currentProfile`. Это переменная Adapty, которая хранит данные о профиле текущего пользователя.
6. Заполните поля следующим образом:
- **Available Options**: Data Structure Field
- **Select Field**: accessLevels
- **Available Options**: Filter List Items
- **Filter Conditions**:
1. Выберите **Conditions -> Single Condition** и нажмите **UNSET**.
2. В поле **First value** выберите **Item in list** в качестве **Source** и заполните поля следующим образом:
- **Available Options**: Data Structure Field
- **Select Field**: accessLevelIdentifier
3. Установите оператор фильтра **Equal to**.
4. Нажмите **UNSET** рядом с **Second value** и в поле **Value** введите ID вашего уровня доступа; в нашем примере используется `premium`.
5. Нажмите **Confirm** и продолжите заполнять остальные поля ниже.
- **Available Options**: Item at Index
- **List Index Options**: First
- **Available Options**: Data Structure Field
- **Select Field**: accessLevel
- **Available Options**: Data Structure Field
- **Select Field**: isActive
7. Нажмите **Confirm**.
Теперь добавьте действия для дальнейших сценариев — есть ли у пользователя нужная подписка или нет. Либо перенаправьте его на страницу, доступную подписчикам премиум-уровня, либо откройте страницу с пейволом, чтобы он мог купить доступ.
---
# File: ff-resources
---
---
title: "Действия и типы данных плагина Adapty для FlutterFlow"
description: "Используйте ресурсы функциональных флагов Adapty для упрощения работы с функциями на основе подписки."
---
## Кастомные действия \{#custom-actions\}
Ниже перечислены методы Adapty, доступные во FlutterFlow через плагин Adapty. Их можно использовать как кастомные действия во FlutterFlow.
| Пользовательское действие | Описание | Аргументы действия | Типы данных Adapty — переменная вывода действия |
|---|----|--------|----|
| activate | Инициализирует SDK Adapty | Нет ||
| getPaywall
| Получает пейвол. Не возвращает продукты пейвола. Используйте действие `getPaywallProducts`, чтобы получить актуальные продукты |getPaywallProducts
| Возвращает список актуальных продуктов пейвола | [AdaptyPaywall](ff-resources#adaptypaywall) | [AdaptyGetProductsResult](ff-resources#adaptygetproductsresult) | |getProductsIntroductoryOfferEligibility
| Проверяет, имеет ли пользователь право на introductory offer для iOS-подписки | [AdaptyPaywallProduct](product) | [AdaptyGetIntroEligibilitiesResult](ff-resources#adaptygetintroeligibilitiesresult) | |makePurchase
| Завершает покупку и открывает доступ к контенту. Если у пейвола есть promotional offer, Adapty автоматически применяет его при оформлении покупки |getProfile
|Получает профиль текущего пользователя приложения. Позволяет задавать уровни доступа и другие параметры
Если запрос завершается ошибкой (например, из-за отсутствия интернета), возвращаются кешированные данные. Adapty регулярно обновляет кеш профиля, чтобы информация оставалась как можно более актуальной
| Нет | [AdaptyGetProfileResult](ff-resources#adaptygetprofileresult) | | updateProfile | Изменяет необязательные атрибуты профиля текущего пользователя: email, номер телефона и т. д. Атрибуты можно использовать для создания [сегментов](segments) пользователей или просматривать их в CRM | ID и любые параметры, которые нужно обновить для [AdaptyProfile](ff-resources#adaptyprofile) | [AdaptyError](ff-resources#adaptyerror) (необязательно) | | restorePurchases | Восстанавливает все покупки пользователя | Нет | [AdaptyGetProfileResult](ff-resources#adaptygetprofileresult) | | logShowPaywall | Фиксирует показ конкретного пейвола пользователю | [AdaptyPaywall](ff-resources#adaptypaywall) | [AdaptyError](ff-resources#adaptyerror) (необязательно) | | identify | Идентифицирует пользователя с помощью `customerUserId` из вашей системы | customerUserId | [AdaptyError](ff-resources#adaptyerror) (необязательно) | | logout | Выполняет выход текущего пользователя из приложения | Нет | [AdaptyError](ff-resources#adaptyerror) (необязательно) | | presentCodeRedemptionSheet | Отображает окно для активации промокодов (только iOS) | Нет | Нет | ## Типы данных \{#data-types\} Типы данных Adapty (наборы значений данных), передаваемые в FlutterFlow через плагин Adapty. ### AdaptyAccessLevel Информация об [уровне доступа](access-level) пользователя. | Название поля | Тип | Описание | |--------------------------|----------|-------------| | activatedAt | DateTime | Время активации данного уровня доступа | | activeIntroductoryOfferType | String | Тип активного introductory offer. Если задано, значит в текущем расчётном периоде подписки применялось предложение | | activePromotionalOfferId | String | ID активного promotional offer (приобретённого через iOS) | | activePromotionalOfferType | String | Тип активного promotional offer (приобретённого через iOS). Если задано, значит в текущем расчётном периоде подписки применялось предложение | | billingIssueDetectedAt | DateTime | Время обнаружения проблемы с оплатой. Подписка при этом может оставаться активной. Устанавливается в null при успешной обработке платежа | | cancellationReason | String | Причина отмены подписки | | expiresAt | DateTime | Время истечения уровня доступа (может быть в прошлом или не задано для пожизненного доступа) | | id | String | Идентификатор уровня доступа | | isActive | Boolean | True, если данный уровень доступа активен. Как правило, именно это свойство используется для проверки наличия у пользователя доступа к премиум-функциям | | isInGracePeriod | Boolean | True, если данная автовозобновляемая подписка находится в [льготном периоде](https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions) | | isLifetime | Boolean | True, если данный уровень доступа активен на всё время (без даты истечения) | | isRefund | Boolean | True, если данная покупка была возвращена | | offerId | String | ID активного promotional offer (приобретённого через Android) | | renewedAt | DateTime | Время последнего продления уровня доступа | | startsAt | DateTime | Время начала действия данного уровня доступа (может быть в будущем) | | store | String | Стор, в котором была совершена покупка | | unsubscribedAt | DateTime | Время отключения автопродления подписки. Подписка при этом может оставаться активной. Если не задано, пользователь повторно активировал подписку | | vendorProductId | String | ID продукта в сторе, открывшего данный уровень доступа | | willRenew | Boolean | True, если данная автовозобновляемая подписка настроена на продление | ### AdaptyAccessLevelIdentifiers Эта структура предназначена для замены пары ключ-значение в `Map
Adapty использует пространство имён `AdaptySDK`. В начале файлов скриптов, использующих Adapty SDK, можно добавить:
```csharp showLineNumbers title="C#"
using AdaptySDK;
```
Подпишитесь на события Adapty:
```csharp showLineNumbers title="C#"
using UnityEngine;
using AdaptySDK;
public class AdaptyListener : MonoBehaviour, AdaptyEventListener {
public void OnLoadLatestProfile(AdaptyProfile profile) {
// handle updated profile data
}
public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { }
public void OnInstallationDetailsFail(AdaptyError error) { }
}
```
Мы рекомендуем настроить Script Execution Order так, чтобы AdaptyListener выполнялся раньше Default Time. Это обеспечит инициализацию Adapty как можно раньше.
Теперь настройте пейволы в своём приложении:
- Если вы используете [Adapty Paywall Builder](adapty-paywall-builder), сначала [активируйте модуль AdaptyUI](#activate-adaptyui-module-of-adapty-sdk) ниже, затем следуйте [быстрому старту с Paywall Builder](unity-quickstart-paywalls).
- Если вы создаёте собственный интерфейс пейвола, смотрите [быстрый старт для кастомных пейволов](unity-quickstart-manual).
## Активация модуля AdaptyUI в Adapty SDK \{#activate-adaptyui-module-of-adapty-sdk\}
Если вы планируете использовать [Paywall Builder](adapty-paywall-builder) и установили модуль AdaptyUI, его необходимо активировать. Это можно сделать при конфигурации:
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetActivateUI(true);
```
## Дополнительная настройка \{#optional-setup\}
### Логирование \{#logging\}
#### Настройка системы логирования \{#set-up-the-logging-system\}
Adapty логирует ошибки и другую важную информацию, чтобы помочь вам разобраться в происходящем. Доступны следующие уровни логирования:
| Level | Description |
| ---------- | ------------------------------------------------------------ |
| `error` | Будут записываться только ошибки |
| `warn` | Будут записываться ошибки и сообщения от SDK, которые не вызывают критических ошибок, но заслуживают внимания |
| `info` | Будут записываться ошибки, предупреждения и различные информационные сообщения |
| `verbose` | Будет записываться любая дополнительная информация, которая может быть полезна при отладке: вызовы функций, запросы к API и т. д. |
Уровень логирования можно задать при настройке Adapty в вашем приложении:
```csharp showLineNumbers title="C#"
// 'verbose' is recommended for development and the first production release
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY");
builder.LogLevel = AdaptyLogLevel.Verbose;
```
Уровень логирования также можно изменить во время работы приложения:
```csharp showLineNumbers title="C#"
Adapty.SetLogLevel(AdaptyLogLevel.Verbose, (error) => {
// handle result
});
```
### Политики обработки данных \{#data-policies\}
Adapty не хранит персональные данные ваших пользователей, если вы явно их не передаёте. При этом вы можете настроить дополнительные политики безопасности данных в соответствии с требованиями стора или законодательства конкретной страны.
#### Отключение сбора и передачи IP-адресов \{#disable-ip-address-collection-and-sharing\}
При активации модуля Adapty установите `SetIPAddressCollectionDisabled` в значение `true`, чтобы отключить сбор и передачу IP-адресов пользователей. Значение по умолчанию — `false`.
Используйте этот параметр для защиты конфиденциальности пользователей, соблюдения региональных требований по защите данных (например, GDPR или CCPA) или для сокращения избыточного сбора данных в случаях, когда функции на основе IP-адреса не нужны вашему приложению.
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetIPAddressCollectionDisabled(true);
```
#### Отключение сбора и передачи рекламного идентификатора \{#disable-advertising-id-collection-and-sharing\}
При активации модуля Adapty установите `SetAppleIDFACollectionDisabled` и/или `SetGoogleAdvertisingIdCollectionDisabled` в значение `true`, чтобы отключить сбор рекламных идентификаторов. Значение по умолчанию — `false`.
Используйте этот параметр для соблюдения политик App Store/Google Play, чтобы не вызывать запрос App Tracking Transparency, или если ваше приложение не требует рекламной атрибуции или аналитики на основе рекламных идентификаторов.
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetAppleIDFACollectionDisabled(true)
.SetGoogleAdvertisingIdCollectionDisabled(true);
```
#### Настройка конфигурации медиакеша для AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\}
По умолчанию AdaptyUI кеширует медиафайлы (изображения и видео) для повышения производительности и снижения потребления трафика. Вы можете настроить параметры кеша, передав собственную конфигурацию.
Используйте `SetAdaptyUIMediaCache`, чтобы переопределить настройки кеша по умолчанию:
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetAdaptyUIMediaCache(
100 * 1024 * 1024, // MemoryStorageTotalCostLimit 100MB
null, // MemoryStorageCountLimit
100 * 1024 * 1024 // DiskStorageSizeLimit 100MB
);
```
Параметры:
| Параметр | Обязательный | Описание |
|-----------------------------|----------|----------------------------------------------------------------------------------------|
| memoryStorageTotalCostLimit | optional | Общий размер кэша в памяти в байтах. По умолчанию используется платформозависимое значение. |
| memoryStorageCountLimit | optional | Максимальное количество элементов в памяти. По умолчанию используется платформозависимое значение. |
| diskStorageSizeLimit | optional | Максимальный размер файлов на диске в байтах. По умолчанию используется платформозависимое значение. |
### Включение локальных уровней доступа (Android) \{#enable-local-access-levels-android\}
По умолчанию [локальные уровни доступа](local-access-levels) включены на iOS и отключены на Android. Чтобы включить их и на Android, установите `SetGoogleLocalAccessLevelAllowed` в `true`:
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetGoogleLocalAccessLevelAllowed(true);
```
### Очистка данных при восстановлении из резервной копии \{#clear-data-on-backup-restore\}
Когда `SetAppleClearDataOnBackup` установлен в `true`, SDK обнаруживает восстановление приложения из резервной копии iCloud и удаляет все локально сохранённые данные SDK, включая кешированную информацию о профиле, данные о продуктах и пейволы. После этого SDK инициализируется с чистым состоянием. Значение по умолчанию — `false`.
:::note
Удаляется только локальный кеш SDK. История транзакций с Apple и пользовательские данные на серверах Adapty остаются неизменными.
:::
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetAppleClearDataOnBackup(true);
```
## Устранение неполадок \{#troubleshooting\}
#### Правила резервного копирования Android (настройка Auto Backup) \{#android-backup-rules-auto-backup-configuration\}
Некоторые SDK (включая Adapty) поставляются с собственной конфигурацией Android Auto Backup. Если вы используете несколько SDK, каждый из которых определяет правила резервного копирования, слияние манифестов Android может завершиться ошибкой, связанной с `android:fullBackupContent`, `android:dataExtractionRules` или `android:allowBackup`.
Типичные симптомы ошибки: `Manifest merger failed: Attribute application@dataExtractionRules value=(@xml/your_data_extraction_rules)
is also present at [com.other.sdk:library:1.0.0] value=(@xml/other_sdk_data_extraction_rules)`
:::note
Эти изменения нужно вносить в директорию Android-платформы (обычно находится в папке `android/` вашего проекта).
:::
Чтобы решить проблему, необходимо:
- Указать механизму слияния манифестов использовать значения вашего приложения для атрибутов, связанных с резервным копированием.
- Создать файлы правил резервного копирования, объединяющие правила Adapty с правилами других SDK.
#### 1. Добавьте пространство имён `tools` в манифест
В файле `AndroidManifest.xml` убедитесь, что корневой тег `
2. Добавьте следующую строку в `/Assets/Plugins/Android/launcherTemplate.gradle`:
```groovy showLineNumbers
apply plugin: 'com.android.application'
// highlight-next-line
apply plugin: 'kotlin-android'
apply from: 'setupSymbols.gradle'
apply from: '../shared/keepUnitySymbols.gradle'
```
3. Добавьте следующую строку в `/Assets/Plugins/Android/baseProjectTemplate.gradle`:
```groovy showLineNumbers
plugins {
// If you are changing the Android Gradle Plugin version, make sure it is compatible with the Gradle version preinstalled with Unity
// See which Gradle version is preinstalled with Unity here https://docs.unity3d.com/Manual/android-gradle-overview.html
// See official Gradle and Android Gradle Plugin compatibility table here https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
// To specify a custom Gradle version in Unity, go do "Preferences > External Tools", uncheck "Gradle Installed with Unity (recommended)" and specify a path to a custom Gradle version
id 'com.android.application' version '8.3.0' apply false
id 'com.android.library' version '8.3.0' apply false
// highlight-next-line
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
**BUILD_SCRIPT_DEPS**
}
```
---
# File: unity-quickstart-paywalls
---
---
title: "Включение покупок с помощью пейволов в Unity SDK"
description: "Узнайте, как отображать пейволы в вашем приложении на Unity с помощью Adapty SDK."
---
Чтобы включить встроенные покупки, нужно понять три ключевых концепции:
- [**Продукты**](product) — всё, что пользователи могут купить (подписки, расходуемые покупки, пожизненный доступ)
- [**Пейволы**](paywalls) — конфигурации, определяющие, какие продукты предлагать. В Adapty пейволы — единственный способ получить продукты, но благодаря этому вы можете менять предложения, цены и наборы продуктов, не трогая код приложения.
- [**Плейсменты**](placements) — где и когда показывать пейволы в приложении (например, `main`, `onboarding`, `settings`). Вы настраиваете пейволы для плейсментов в дашборде, а затем запрашиваете их по ID плейсмента в коде. Это упрощает проведение A/B-тестов и показ разных пейволов разным пользователям.
Adapty предлагает три способа включить покупки в приложении. Выберите подходящий в зависимости от требований вашего приложения:
| Реализация | Сложность | Когда использовать |
|---------------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Adapty Paywall Builder | ✅ Просто | Вы [создаёте готовый к покупкам пейвол в no-code конструкторе](quickstart-paywalls). Adapty автоматически его отображает и берёт на себя весь сложный процесс покупки, валидацию чеков и управление подписками. |
| Пейволы, созданные вручную | 🟡 Средне | Вы реализуете UI пейвола в коде приложения, но всё равно получаете объект пейвола из Adapty для гибкости в управлении предложениями. Смотрите [гайд](unity-quickstart-manual). |
| Observer mode | 🔴 Сложно | У вас уже есть собственная инфраструктура обработки покупок, и вы хотите её использовать. Учтите, что observer mode имеет ограничения в Adapty. Смотрите [статью](observer-vs-full-mode). |
:::important
**Описанные ниже шаги показывают, как реализовать пейвол, созданный в Adapty Paywall Builder.**
Если вы не хотите использовать Paywall Builder, смотрите [гайд по обработке покупок в пейволах, созданных вручную](unity-making-purchases).
:::
Чтобы отобразить пейвол, созданный в Adapty Paywall Builder, в коде приложения вам нужно только:
1. **Получить пейвол**: Получите пейвол из Adapty.
2. **Отобразить пейвол — Adapty возьмёт на себя покупки**: Покажите контейнер пейвола в вашем приложении.
3. **Обработать действия кнопок**: Свяжите взаимодействия пользователя с пейволом с реакцией приложения на них. Например, открывайте ссылки или закрывайте пейвол при нажатии кнопок.
## Прежде чем начать \{#before-you-start\}
Перед началом выполните следующие шаги:
1. Подключите приложение к [App Store](initial_ios) и/или [Google Play](initial-android) в дашборде Adapty.
2. [Создайте продукты](create-product) в Adapty.
3. [Создайте пейвол и добавьте в него продукты](create-paywall).
4. [Создайте плейсмент и добавьте в него пейвол](create-placement).
5. [Установите и активируйте Adapty SDK](sdk-installation-unity) в коде приложения.
:::tip
Самый быстрый способ выполнить эти шаги — следовать [quickstart-гайду](quickstart) или создать пейволы и плейсменты с помощью [Developer CLI](developer-cli-quickstart).
:::
## 1. Получите пейвол \{#1-get-the-paywall\}
Ваши пейволы привязаны к плейсментам, настроенным в дашборде. Плейсменты позволяют запускать разные пейволы для разных аудиторий или проводить [A/B-тесты](ab-tests).
Чтобы получить пейвол, созданный в Adapty Paywall Builder, необходимо:
1. Получить объект `paywall` по ID [плейсмента](placements) с помощью метода `GetPaywall` и проверить, является ли это пейволом, созданным в конструкторе, с помощью свойства `HasViewConfiguration`.
2. Создать представление пейвола с помощью метода `CreatePaywallView`. Представление содержит элементы UI и стили, необходимые для отображения пейвола.
:::important
Чтобы получить конфигурацию представления, необходимо включить переключатель **Show on device** в Paywall Builder. В противном случае вы получите пустую конфигурацию представления, и пейвол не будет отображён.
:::
```csharp showLineNumbers
Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => {
if(error != null) {
// handle the error
return;
}
// Create paywall view parameters
var parameters = new AdaptyUICreatePaywallViewParameters();
// Create the paywall view
AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => {
if(error != null) {
// handle the error
return;
}
// view - the paywall view ready to be presented
});
});
```
:::info
Этот quickstart содержит минимальную конфигурацию, необходимую для отображения пейвола. Подробнее о расширенных настройках смотрите в [гайде по получению пейволов](unity-get-pb-paywalls).
:::
## 2. Отобразите пейвол \{#2-display-the-paywall\}
Теперь, когда у вас есть конфигурация пейвола, достаточно добавить несколько строк для его отображения.
Чтобы показать пейвол, используйте метод `view.Present()` на объекте `view`, созданном методом `CreatePaywallView`. Каждый объект `view` можно использовать только один раз. Если нужно показать пейвол снова, вызовите `CreatePaywallView` ещё раз, чтобы создать новый экземпляр `view`.
```csharp showLineNumbers title="Unity"
view.Present((error) => {
// handle the error
});
```
:::info
Подробнее об отображении пейвола смотрите в нашем [гайде](unity-present-paywalls).
:::
## 3. Обработайте действия кнопок \{#3-handle-button-actions\}
Когда пользователи нажимают кнопки в пейволе, Unity SDK автоматически обрабатывает покупки и восстановление. Однако другие кнопки имеют пользовательские или предопределённые идентификаторы и требуют обработки действий в вашем коде.
Например, в вашем пейволе, скорее всего, есть кнопка закрытия и ссылки для открытия (например, условия использования и политика конфиденциальности). Чтобы обработать эти действия, ваш класс должен реализовывать интерфейс `AdaptyPaywallsEventsListener` и зарегистрироваться как слушатель.
:::tip
Читайте наши гайды о том, как обрабатывать [действия](unity-handle-paywall-actions) кнопок и [события](unity-handling-events).
:::
```csharp showLineNumbers title="Unity"
public class YourClass : MonoBehaviour, AdaptyPaywallsEventsListener
{
void Start()
{
// Register this class as the paywall events listener
Adapty.SetPaywallsEventsListener(this);
}
// AdaptyPaywallsEventsListener method - handles button actions
public void PaywallViewDidPerformAction(
AdaptyUIPaywallView view,
AdaptyUIUserAction action
) {
switch (action.Type) {
case AdaptyUIUserActionType.Close:
view.Dismiss(null);
break;
case AdaptyUIUserActionType.OpenUrl:
Application.OpenURL(action.Value);
break;
default:
break;
}
}
}
```
## Следующие шаги \{#next-steps\}
:::tip
Есть вопросы или возникли проблемы? Загляните на наш [форум поддержки](https://adapty.featurebase.app/), где можно найти ответы на распространённые вопросы или задать свой. Наша команда и сообщество всегда готовы помочь!
:::
Ваш пейвол готов к отображению в приложении. Протестируйте покупки в [песочнице App Store](test-purchases-in-sandbox) или в [Google Play Store](testing-on-android), чтобы убедиться, что тестовая покупка через пейвол проходит успешно.
Теперь вам нужно [проверить уровень доступа пользователей](unity-check-subscription-status), чтобы убедиться, что вы показываете пейвол или открываете доступ к платным функциям нужным пользователям.
## Полный пример \{#full-example\}
Вот как все эти шаги можно интегрировать в приложение вместе.
```csharp showLineNumbers
using System;
using UnityEngine;
using AdaptySDK;
public class PaywallManager : MonoBehaviour, AdaptyPaywallsEventsListener
{
[SerializeField] private string placementId = "YOUR_PLACEMENT_ID";
private AdaptyUIPaywallView currentPaywallView;
void Start()
{
// Register for paywall events
Adapty.SetPaywallsEventsListener(this);
GetAndDisplayPaywall();
}
private void GetAndDisplayPaywall()
{
Adapty.GetPaywall(placementId, (paywall, error) => {
if (error != null) {
Debug.LogError("Error getting paywall: " + error.Message);
return;
}
if (paywall.HasViewConfiguration) {
CreateAndPresentPaywallView(paywall);
} else {
Debug.LogWarning("Paywall was not created using the builder");
}
});
}
private void CreateAndPresentPaywallView(AdaptyPaywall paywall)
{
var parameters = new AdaptyUICreatePaywallViewParameters();
AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => {
if (error != null) {
Debug.LogError("Error creating paywall view: " + error.Message);
return;
}
currentPaywallView = view;
view.Present((presentError) => {
if (presentError != null) {
Debug.LogError("Error presenting paywall: " + presentError.Message);
return;
}
Debug.Log("Paywall presented successfully");
});
});
}
// AdaptyPaywallsEventsListener implementation
public void PaywallViewDidPerformAction(
AdaptyUIPaywallView view,
AdaptyUIUserAction action
) {
switch (action.Type) {
case AdaptyUIUserActionType.Close:
Debug.Log("Close button pressed");
view.Dismiss(null);
break;
case AdaptyUIUserActionType.OpenUrl:
Application.OpenURL(action.Value);
break;
default:
break;
}
}
// Required interface methods (implement as needed)
public void PaywallViewDidAppear(AdaptyUIPaywallView view) { }
public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { }
public void PaywallViewDidSelectProduct(AdaptyUIPaywallView view, string productId) { }
public void PaywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) { }
public void PaywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult) { }
public void PaywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { }
public void PaywallViewDidStartRestore(AdaptyUIPaywallView view) { }
public void PaywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) { }
public void PaywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) { }
public void PaywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) { }
public void PaywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) { }
public void PaywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { }
public void ShowPaywall()
{
GetAndDisplayPaywall();
}
void OnDestroy()
{
if (currentPaywallView != null) {
currentPaywallView.Dismiss(null);
}
}
}
```
---
# File: unity-check-subscription-status
---
---
title: "Проверка статуса подписки в Unity SDK"
description: "Узнайте, как проверить статус подписки в приложении Unity с помощью Adapty."
---
Чтобы решить, может ли пользователь получить доступ к платному контенту или нужно показать ему пейвол, проверьте его [уровень доступа](access-level) в профиле.
В этой статье рассказывается, как обращаться к состоянию профиля, чтобы понимать, что показывать пользователю — пейвол или платный контент.
## Получение статуса подписки \{#get-subscription-status\}
Когда нужно решить, показать пользователю пейвол или платный контент, проверьте его [уровень доступа](access-level) в профиле. Есть два способа:
- Вызвать `GetProfile`, если нужны актуальные данные профиля прямо сейчас (например, при запуске приложения) или требуется принудительное обновление.
- Настроить **автоматические обновления профиля**, чтобы хранить локальную копию, которая автоматически обновляется при изменении статуса подписки.
### Получение профиля \{#get-profile\}
Самый простой способ узнать статус подписки — использовать метод `GetProfile`:
```csharp showLineNumbers
Adapty.GetProfile((profile, error) => {
if (error != null) {
// handle the error
return;
}
// check the access
});
```
### Отслеживание обновлений подписки \{#listen-to-subscription-updates\}
Чтобы автоматически получать обновления профиля в приложении:
1. Унаследуйте `AdaptyEventListener` и реализуйте метод `OnLoadLatestProfile` — Adapty будет автоматически вызывать его при каждом изменении статуса подписки пользователя.
2. Сохраняйте обновлённые данные профиля при вызове этого метода, чтобы использовать их в приложении без дополнительных сетевых запросов.
```csharp
public class SubscriptionManager : MonoBehaviour, AdaptyEventListener {
private AdaptyProfile currentProfile;
void Start() {
// Register this object as an Adapty event listener
Adapty.SetEventListener(this);
}
// Store the profile when it updates
public void OnLoadLatestProfile(AdaptyProfile profile) {
currentProfile = profile;
// Update UI, unlock content, etc.
}
public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { }
public void OnInstallationDetailsFail(AdaptyError error) { }
// Use stored profile instead of calling getProfile()
public bool HasAccess() {
if (currentProfile?.AccessLevels != null &&
currentProfile.AccessLevels.ContainsKey("premium")) {
return currentProfile.AccessLevels["premium"].IsActive;
}
return false;
}
}
```
:::note
Adapty автоматически вызывает `OnLoadLatestProfile` при запуске приложения, предоставляя кешированные данные о подписке даже при отсутствии интернета.
:::
## Связь профиля с логикой пейвола \{#connect-profile-with-paywall-logic\}
Когда нужно мгновенно решить, показывать пейвол или открывать доступ к платным функциям, можно проверить профиль пользователя напрямую. Это удобно при запуске приложения, входе в премиальные разделы или перед показом определённого контента.
```csharp
private void CheckAccessLevel()
{
Adapty.GetProfile((profile, error) => {
if (error != null) {
Debug.LogError("Error checking access level: " + error.Message);
// Show paywall if access check fails
return;
}
var accessLevel = profile.AccessLevels["YOUR_ACCESS_LEVEL"];
if (accessLevel == null || !accessLevel.IsActive) {
// Show paywall if no access
}
});
}
private void InitializePaywall()
{
LoadPaywall();
CheckAccessLevel();
}
```
## Дальнейшие шаги \{#next-steps\}
Теперь, когда вы знаете, как отслеживать статус подписки, узнайте, как [работать с профилями пользователей](unity-quickstart-identify), чтобы они получали доступ к тому, за что заплатили.
---
# File: unity-quickstart-identify
---
---
title: "Идентификация пользователей в Unity SDK"
description: "Быстрый старт по настройке Adapty для управления встроенными подписками в Unity."
---
:::important
Этот гайд для вас, если у вас есть собственная система аутентификации. Здесь вы узнаете, как работать с профилями пользователей в Adapty, чтобы они корректно интегрировались с вашей существующей системой аутентификации.
:::
То, как вы управляете покупками пользователей, зависит от модели аутентификации в вашем приложении:
- Если ваше приложение не использует серверную аутентификацию и не хранит данные пользователей, см. [раздел об анонимных пользователях](#anonymous-users).
- Если в вашем приложении есть (или будет) серверная аутентификация, см. [раздел об идентифицированных пользователях](#identified-users).
**Ключевые понятия**:
- **Профили** — это сущности, необходимые для работы SDK. Adapty создаёт их автоматически.
- Они могут быть анонимными **(без customer user ID)** или идентифицированными **(с customer user ID)**.
- Вы передаёте **customer user ID**, чтобы связать профили в Adapty с вашей внутренней системой авторизации.
Вот чем отличаются анонимные и идентифицированные пользователи:
| | Анонимные пользователи | Идентифицированные пользователи |
|-------------------------|---------------------------------------------------------------|-------------------------------------------------------------------------------------------------------|
| **Управление покупками** | Восстановление покупок на уровне стора | История покупок сохраняется на всех устройствах через customer user ID |
| **Управление профилем** | Новый профиль при каждой переустановке | Один и тот же профиль во всех сессиях и на всех устройствах |
| **Сохранность данных** | Данные анонимных пользователей привязаны к установке приложения | Данные идентифицированных пользователей сохраняются между установками приложения |
## Анонимные пользователи \{#anonymous-users\}
Если у вас нет серверной аутентификации, **вам не нужно реализовывать аутентификацию в коде приложения**:
1. Когда SDK активируется при первом запуске приложения, Adapty **создаёт новый профиль для пользователя**.
2. Когда пользователь совершает покупку в приложении, она **привязывается к его профилю Adapty и аккаунту в сторе**.
3. Когда пользователь **переустанавливает** приложение или устанавливает его на **новое устройство**, Adapty **создаёт новый анонимный профиль при активации**.
4. Если пользователь ранее совершал покупки в вашем приложении, по умолчанию они автоматически синхронизируются из App Store при активации SDK.
Таким образом, для анонимных пользователей при каждой установке будет создаваться новый профиль — но это не проблема, так как в аналитике Adapty можно [настроить, что считать новой установкой](general#4-installs-definition-for-analytics).
Для анонимных пользователей нужно считать установки по **device ID**. В этом случае каждая установка приложения на устройство считается отдельной установкой, включая переустановки.
## Идентификация пользователей \{#identified-users\}
Есть два способа идентифицировать пользователей в приложении:
- [**При входе/регистрации:**](#during-loginsignup) Если пользователи входят в систему после запуска приложения, вызовите `identify()` с customer user ID в момент аутентификации.
- [**При активации SDK:**](#during-the-sdk-activation) Если customer user ID уже сохранён на момент запуска приложения, передайте его при вызове `activate()`.
:::important
По умолчанию, когда Adapty получает покупку от Customer User ID, который уже связан с другим Customer User ID, уровень доступа становится общим — оба профиля получают платный доступ. Вы можете настроить это поведение так, чтобы платный доступ переносился с одного профиля на другой, или полностью отключить общий доступ. Подробнее см. в [статье](general#6-sharing-paid-access-between-user-accounts).
:::
### При входе или регистрации \{#during-loginsignup\}
Если вы идентифицируете пользователей после запуска приложения (например, после входа или регистрации), используйте метод `identify`, чтобы задать их customer user ID.
- Если вы **ещё не использовали этот customer user ID**, Adapty автоматически привяжет его к текущему профилю.
- Если вы **уже использовали этот customer user ID для идентификации пользователя**, Adapty переключится на работу с профилем, связанным с этим customer user ID.
:::important
ID пользователя должен быть уникальным для каждого пользователя. Если вы укажете фиксированное значение параметра, все пользователи будут считаться одним.
:::
Дождитесь выполнения коллбэка `Identify` перед вызовом других методов SDK. Параллельные вызовы приводят к ошибке `#3006 profileWasChanged` или попаданию в анонимный профиль. См. [Порядок вызовов в Unity SDK](unity-sdk-call-order).
```csharp showLineNumbers
Adapty.Identify("YOUR_USER_ID", (error) => { // Уникальный для каждого пользователя
if(error == null) {
// successful identify
}
});
```
### Во время активации SDK \{#during-the-sdk-activation\}
Если вы уже знаете customer user ID в момент активации SDK, можно передать его прямо в метод `activate` — вместо того чтобы вызывать `identify` отдельно.
Если вы знаете customer user ID, но задаёте его только после активации, то при активации Adapty создаст новый анонимный профиль и переключится на существующий лишь после вызова `identify`.
Вы можете передать как существующий customer user ID (тот, что использовали раньше), так и новый. Если передать новый — профиль, созданный при активации, будет автоматически привязан к этому customer user ID.
:::note
По умолчанию создание анонимных профилей не влияет на аналитические дашборды, поскольку установки считаются по идентификаторам устройств.
Идентификатор устройства соответствует одной установке приложения из стора на устройстве и пересоздаётся только при переустановке приложения.
Он не зависит от того, первая это установка или повторная, и от того, используется ли существующий пользовательский ID.
Создание профиля (при активации SDK или выходе из аккаунта), вход в систему или обновление приложения без переустановки не генерируют дополнительных событий установки.
Если вы хотите считать установки на основе уникальных пользователей, а не устройств, перейдите в **App settings** и настройте параметр [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```csharp showLineNumbers
using UnityEngine;
using AdaptySDK;
var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY")
.SetCustomerUserId("YOUR_USER_ID"); // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one.
Adapty.Activate(builder.Build(), (error) => {
if (error != null) {
// handle the error
return;
}
});
```
### Выход пользователей из системы \{#log-users-out\}
Если у вас есть кнопка для выхода из аккаунта, используйте метод `logout`.
:::important
При выходе из аккаунта для пользователя создаётся новый анонимный профиль.
:::
```csharp showLineNumbers
Adapty.Logout((error) => {
if(error == null) {
// successful logout
}
});
```
:::info
Чтобы снова войти в приложение, используйте метод `identify`.
:::
### Разрешите покупки без входа в систему \{#allow-purchases-without-login\}
Если пользователи могут совершать покупки как до, так и после входа в приложение, нужно убедиться, что после авторизации они сохранят доступ к купленным возможностям:
1. Когда неавторизованный пользователь совершает покупку, Adapty привязывает её к анонимному идентификатору профиля.
2. Когда пользователь входит в аккаунт, Adapty переключается на работу с идентифицированным профилем.
- Если это новый customer user ID (например, покупка была совершена до регистрации), Adapty присваивает customer user ID текущему профилю, сохраняя всю историю покупок.
- Если это существующий customer user ID (customer user ID уже привязан к профилю), нужно получить актуальный уровень доступа после переключения профиля. Можно вызвать [`getProfile`](unity-check-subscription-status) сразу после идентификации или [подписаться на обновления профиля](unity-check-subscription-status), чтобы данные синхронизировались автоматически.
## Следующие шаги \{#next-steps\}
Поздравляем! Вы реализовали логику встроенных покупок в своём приложении! Желаем вам успехов в монетизации!
Чтобы получить от Adapty ещё больше, изучите эти темы:
- [**Тестирование**](troubleshooting-test-purchases): Убедитесь, что всё работает как ожидается
- [**Онбординги**](onboardings): Вовлекайте пользователей с помощью онбордингов и повышайте удержание
- [**Интеграции**](configuration): Интегрируйтесь с сервисами маркетинговой атрибуции и аналитики буквально в одну строку кода
- [**Установка пользовательских атрибутов профиля**](unity-setting-user-attributes): Добавляйте пользовательские атрибуты к профилям и создавайте сегменты, чтобы запускать A/B-тесты или показывать разные пейволы разным пользователям
---
# File: adapty-sdk-integration-skill-unity
---
---
title: "Интеграция Adapty в приложение Unity с помощью навыка SDK integration"
description: "Используйте навык adapty-sdk-integration для сквозной интеграции Adapty SDK в приложение Unity с помощью AI-инструмента для написания кода."
---
опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-paywall-locale-in-adapty-paywall-builder). Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` означает английский, `pt-br` — португальский (Бразилия).
Подробнее о кодах локалей и рекомендациях по их использованию — в разделе [Локализации и коды локалей](localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают самые актуальные данные.
Однако если ваши пользователи часто сталкиваются с нестабильным интернетом, рассмотрите вариант `.returnCacheDataElseLoad` — он возвращает кешированные данные, если они есть. В этом случае пользователи могут получить не самые свежие данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или ручной очистке.
Adapty SDK хранит пейволы локально в двух слоях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](fallback-paywalls). Для ускорения загрузки пейволов мы также используем CDN и отдельный резервный сервер на случай недоступности CDN. Эта система гарантирует, что вы всегда получаете актуальную версию пейволов, сохраняя надёжность даже при слабом интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Ограничивает таймаут этого метода. При достижении таймаута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой относительно значения, указанного в `loadTimeout`, так как операция может включать несколько запросов под капотом.
| Параметры ответа: | Параметр | Описание | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Объект [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) со списком ID продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение конфигурации отображения пейвола, созданного в Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Убедитесь, что в Paywall Builder включён переключатель **Show on device**. Если этот параметр не активирован, конфигурация отображения не будет доступна для получения. ::: После загрузки пейвола проверьте, содержит ли он `ViewConfiguration` — это признак того, что пейвол создан в Paywall Builder. Это поможет вам понять, как отображать пейвол. Если `ViewConfiguration` присутствует, обрабатывайте его как пейвол Paywall Builder; если нет — [обработайте его как пейвол с Remote Config](present-remote-config-paywalls-unity). В Unity SDK напрямую вызывайте метод `CreatePaywallView`, не запрашивая конфигурацию вью вручную. :::warning Результат метода `CreatePaywallView` можно использовать только один раз. Если нужно использовать его повторно, вызовите `CreatePaywallView` заново. Повторный вызов без пересоздания может привести к ошибке `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers var parameters = new AdaptyUICreatePaywallViewParameters() .SetPreloadProducts(preloadProducts) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` Параметры: | Параметр | Наличие | Описание | | :------------------ | :------------------ | :----------------------------------------------------------- | | **paywall** | обязательный | Объект `AdaptyPaywall` для получения контроллера нужного пейвола. | | **loadTimeout** | по умолчанию: 5 сек | Ограничивает таймаут для этого метода. Если таймаут истёк, будут возвращены кешированные данные или локальный резервный пейвол. Обратите внимание, что в редких случаях метод может завершиться с небольшой задержкой сверх значения `loadTimeout`, поскольку операция может включать несколько запросов под капотом. | | **PreloadProducts** | опциональный | Передайте массив `AdaptyPaywallProducts` для оптимизации времени отображения продуктов на экране. Если передать `nil`, AdaptyUI автоматически загрузит необходимые продукты. | | **CustomTags** | опциональный | Задайте словарь пользовательских тегов и их значений. Пользовательские теги служат плейсхолдерами в контенте пейвола и динамически заменяются конкретными строками для персонализации. Подробнее см. в разделе о пользовательских тегах в Paywall Builder. | | **CustomTimers** | опциональный | Задайте словарь пользовательских таймеров и дат их окончания. Пользовательские таймеры позволяют отображать обратный отсчёт на пейволе. | :::note Если вы используете несколько языков, узнайте, как добавить [локализацию Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) и как правильно использовать коды локалей [здесь](localizations-and-locale-codes). ::: Как только у вас есть представление, [покажите пейвол](unity-present-paywalls). ## Настройка ассетов \{#customize-assets\} Чтобы настроить изображения и видео на пейволе, используйте кастомные ассеты. Hero-изображения и видео имеют предопределённые идентификаторы: `hero_image` и `hero_video`. В бандле кастомных ассетов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение. Для остальных изображений и видео нужно [задать кастомный идентификатор](custom-media) в дашборде Adapty. Например, вы можете: - Показывать разные изображения или видео разным пользователям. - Показывать локальное превью-изображение, пока загружается основное удалённое. - Показывать превью-изображение перед запуском видео. :::important Чтобы использовать эту функцию, обновите Adapty Unity SDK до версии 3.8.0 или выше. ::: Вот пример того, как можно передавать пользовательские ресурсы через простой словарь: ```csharp showLineNumbers var customAssets = new Dictionaryопциональный
по умолчанию: `en`
|Идентификатор локализации пейвола. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минуса (**-**). Первый подтег — язык, второй — регион.
Пример: `en` означает английский, `pt-br` — бразильский португальский.
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае ошибки. Мы рекомендуем этот вариант: он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad` — этот режим возвращает кешированные данные, если они есть. В таком случае данные могут быть не самыми свежими, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или принудительной очистке.
Adapty SDK хранит пейволы локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные пейволы. Для более быстрой загрузки пейволов также используется CDN, а на случай его недоступности — отдельный резервный сервер. Такая система гарантирует, что вы всегда получаете актуальную версию пейволов, обеспечивая надёжность даже при плохом интернет-соединении.
| --- # File: unity-present-paywalls --- --- title: "Отображение пейволов" description: "Узнайте, как отображать пейволы в приложении Unity с помощью Adapty SDK." --- Если вы настроили пейвол с помощью Paywall Builder, вам не нужно беспокоиться о его рендеринге в коде мобильного приложения для отображения пользователю. Такой пейвол содержит как то, что должно быть показано, так и то, как именно это должно быть показано. :::warning Этот гайд охватывает **новый Paywall Builder**, который требует Adapty SDK версии 3.3.0 или выше. Чтобы отображать пейволы на Remote Config, см. [Рендеринг пейволов, созданных с помощью Remote Config](present-remote-config-paywalls). ::: Чтобы отобразить пейвол, используйте метод `view.Present()` для объекта `view`, созданного методом [`CreatePaywallView`](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Каждый объект `view` можно использовать только один раз. Если нужно показать пейвол снова, вызовите `CreatePaywallView` ещё раз, чтобы создать новый экземпляр `view`. :::warning Повторное использование одного и того же `view` без его пересоздания может привести к ошибке `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers title="Unity" view.Present((error) => { // handle the error }); ``` :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ## Показ диалога \{#show-dialog\} Используйте этот метод вместо стандартных диалоговых окон, когда на Android отображается пейвол. На Android обычные алерты появляются позади пейвола и становятся невидимы для пользователей. Этот метод гарантирует корректное отображение диалога поверх пейвола на всех платформах. ```csharp showLineNumbers title="Unity" var dialog = new AdaptyUIDialogConfiguration() .SetTitle("Close paywall?") .SetContent("You will lose access to exclusive offers.") .SetDefaultActionTitle("Stay") .SetSecondaryActionTitle("Close"); AdaptyUI.ShowDialog(view, dialog, (action, error) => { if (error == null) { if (action == AdaptyUIDialogActionType.Secondary) { // User confirmed - close the paywall view.Dismiss(); } // If primary - do nothing, user stays } }); ``` ## Настройка стиля презентации на iOS \{#configure-ios-presentation-style\} Настройте способ отображения пейвола на iOS, передав параметр `iosPresentationStyle` в метод `Present()`. Параметр принимает значения `AdaptyUIIOSPresentationStyle.FullScreen` (по умолчанию) или `AdaptyUIIOSPresentationStyle.PageSheet`. ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` --- # File: unity-handle-paywall-actions --- --- title: "Реагирование на действия кнопок в Unity SDK" description: "Обрабатывайте действия кнопок пейвола в Unity с помощью Adapty для лучшей монетизации приложения." --- Если вы создаёте пейволы с помощью Paywall Builder, важно правильно настроить кнопки: 1. Добавьте [кнопку в Paywall Builder](paywall-buttons) и назначьте ей готовое действие или создайте собственный ID действия. 2. Напишите код в приложении для обработки каждого назначенного действия. В этом гайде показано, как обрабатывать пользовательские и стандартные действия в коде. :::warning **Только покупки и восстановления обрабатываются автоматически.** Все остальные действия кнопок — закрытие пейволов, открытие ссылок и т. д. — требуют реализации обработчиков в коде приложения. ::: ## Закрытие пейволов \{#close-paywalls\} Чтобы добавить кнопку, закрывающую пейвол: 1. В Paywall Builder добавьте кнопку и назначьте ей действие **Close**. 2. В коде приложения реализуйте обработчик действия `close`, который скрывает пейвол. ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: view.Dismiss(null); break; default: // handle other events break; } } ``` ## Открытие URL из пейволов \{#open-urls-from-paywalls\} :::tip Если вы хотите добавить группу ссылок (например, пользовательское соглашение и восстановление покупок), добавьте элемент **Link** в Paywall Builder и обработайте его так же, как кнопки с действием **Open URL**. ::: Чтобы добавить кнопку, открывающую ссылку из пейвола (например, **Terms of use** или **Privacy policy**): 1. В Paywall Builder добавьте кнопку, назначьте ей действие **Open URL** и введите нужный URL. 2. В коде приложения реализуйте обработчик действия `openUrl`, который открывает полученный URL в браузере. ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.OpenUrl: var urlString = action.Value; if(!string.IsNullOrWhiteSpace(urlString)) { Application.OpenURL(urlString); } break; default: // handle other events break; } } ``` ## Вход в приложение \{#log-into-the-app\} Чтобы добавить кнопку, которая выполняет вход пользователя в приложение: 1. В Paywall Builder добавьте кнопку и назначьте ей действие **Custom** с ID `login`. 2. В коде приложения реализуйте обработчик пользовательского действия `login`, который идентифицирует пользователя. ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Custom: if (action.Value == "login") { // Navigate to login scene SceneManager.LoadScene("LoginScene"); } break; default: // handle other events break; } } ``` ## Обработка пользовательских действий \{#handle-custom-actions\} Чтобы добавить кнопку для обработки любых других действий: 1. В Paywall Builder добавьте кнопку, назначьте ей действие **Custom** и задайте ID. 2. В коде приложения реализуйте обработчик созданного ID действия. Например, если у вас есть другой набор предложений по подпискам или разовых покупок, можно добавить кнопку, которая будет отображать другой пейвол: ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Custom: if (action.Value == "openNewPaywall") { // Display another paywall ShowAlternativePaywall(); } break; default: // handle other events break; } } private void ShowAlternativePaywall() { // Implement your logic to show alternative paywall } ``` --- # File: unity-handling-events --- --- title: "Обработка событий пейвола" description: "Узнайте, как обрабатывать события пейвола в Unity-приложении с помощью Adapty SDK." --- :::important Этот гайд охватывает обработку событий для покупок, восстановлений, выбора продуктов и отрисовки пейвола. Также необходимо реализовать обработку кнопок (закрытие пейвола, открытие ссылок и т. д.). Подробнее см. в нашем [гайде по обработке действий с кнопками](unity-handle-paywall-actions). ::: Пейволы, настроенные с помощью [Paywall Builder](adapty-paywall-builder), не требуют дополнительного кода для совершения и восстановления покупок. Однако они генерируют ряд событий, на которые ваше приложение может реагировать. Это нажатия кнопок (кнопки закрытия, URL-адреса, выбор продуктов и т. д.), а также уведомления о действиях, связанных с покупками на пейволе. Узнайте, как реагировать на эти события, ниже. :::warning Этот гайд предназначен **только для пейволов нового Paywall Builder**, которые требуют Adapty SDK версии 3.3.0 или выше. ::: :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ## Обработка событий \{#handling-events\} Чтобы контролировать или отслеживать процессы, происходящие на экране пейвола в вашем мобильном приложении, реализуйте интерфейс `AdaptyPaywallsEventsListener`: ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; public class PaywallEventsHandler : MonoBehaviour, AdaptyPaywallsEventsListener { void Start() { Adapty.SetPaywallsEventsListener(this); } // Implement all required interface methods below } ``` ### События, инициируемые пользователем \{#user-generated-events\} #### Пейвол появился \{#paywall-appeared\} Вызывается, когда экран пейвола отображается на экране. :::note На iOS также вызывается, когда пользователь нажимает [кнопку веб-пейвола](web-paywall#step-2a-add-a-web-purchase-button) внутри пейвола и веб-пейвол открывается во встроенном браузере. ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidAppear(AdaptyUIPaywallView view) { } ``` #### Пейвол исчез \{#paywall-disappeared\} Вызывается, когда экран пейвола закрывается. :::note На iOS также вызывается, когда [веб-пейвол](web-paywall#step-2a-add-a-web-purchase-button), открытый из пейвола во встроенном браузере, исчезает с экрана. ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { } ``` #### Выбор продукта \{#product-selection\} Вызывается, когда продукт выбран для покупки (пользователем или системой). ```csharp showLineNumbers title="Unity" public void PaywallViewDidSelectProduct( AdaptyUIPaywallView view, string productId ) { } ```
## Слишком большое число просмотров пейвола \{#the-paywall-view-number-is-too-big\}
**Проблема**: Счётчик просмотров пейвола показывает вдвое больше ожидаемого значения.
**Причина**: Возможно, в вашем коде вызывается `LogShowPaywall`, что дублирует счётчик просмотров при использовании Paywall Builder. Для пейволов, созданных в Paywall Builder, аналитика отслеживается автоматически, поэтому использовать этот метод не нужно.
**Решение**: Убедитесь, что в вашем коде не вызывается `LogShowPaywall`, если вы используете Paywall Builder.
## Другие проблемы \{#other-issues\}
**Проблема**: Вы столкнулись с другими проблемами, связанными с Paywall Builder, которые не описаны выше.
**Решение**: При необходимости обновите SDK до последней версии с помощью [гайдов по миграции](unity-sdk-migration-guides). Многие проблемы устраняются в новых версиях SDK.
---
# File: unity-quickstart-manual
---
---
title: "Включение покупок в вашем кастомном пейволе в Unity SDK"
description: "Интегрируйте Adapty SDK в ваши кастомные пейволы Unity для включения встроенных покупок."
---
Этот гайд описывает, как интегрировать Adapty в ваши кастомные пейволы. Вы сохраняете полный контроль над реализацией пейвола, а SDK Adapty получает продукты, обрабатывает новые покупки и восстанавливает предыдущие.
:::important
**Этот гайд предназначен для разработчиков, которые реализуют кастомные пейволы.** Если вы хотите самый простой способ включить покупки, используйте [Adapty Paywall Builder](unity-quickstart-paywalls). С Paywall Builder вы создаёте пейволы в визуальном редакторе без написания кода, Adapty автоматически обрабатывает всю логику покупок, и вы можете тестировать разные дизайны без повторной публикации приложения.
:::
## Прежде чем начать \{#before-you-start\}
### Настройте продукты \{#set-up-products\}
Для включения встроенных покупок вам нужно понять три ключевых концепции:
- [**Продукты**](product) — всё, что пользователи могут купить (подписки, расходуемые покупки, пожизненный доступ)
- [**Пейволы**](paywalls) — конфигурации, определяющие, какие продукты предлагать. В Adapty пейволы — единственный способ получить продукты, но такой подход позволяет изменять продукты, цены и офферы без изменения кода приложения.
- [**Плейсменты**](placements) — где и когда вы показываете пейволы в приложении (например, `main`, `onboarding`, `settings`). Вы настраиваете пейволы для плейсментов в дашборде, затем запрашиваете их по ID плейсмента в коде. Это упрощает проведение A/B-тестов и показ разных пейволов разным пользователям.
Убедитесь, что вы понимаете эти концепции, даже если работаете с кастомным пейволом. По сути, это просто способ управлять продуктами, которые вы продаёте в приложении.
Для реализации кастомного пейвола вам нужно создать **пейвол** и добавить его в **плейсмент**. Эта настройка позволяет получать ваши продукты. Чтобы понять, что нужно сделать в дашборде, следуйте [быстрому старту здесь](quickstart).
### Управление пользователями \{#manage-users\}
Вы можете работать как с бэкенд-аутентификацией, так и без неё.
SDK Adapty по-разному обрабатывает анонимных и идентифицированных пользователей. Прочитайте [гайд по идентификации](unity-quickstart-identify), чтобы разобраться в особенностях и убедиться, что вы правильно работаете с пользователями.
## Шаг 1. Получите продукты \{#step-1-get-products\}
Чтобы получить продукты для вашего кастомного пейвола, необходимо:
1. Получить объект `paywall`, передав ID [плейсмента](placements) в метод `getPaywall`.
2. Получить массив продуктов для этого пейвола с помощью метода `getPaywallProducts`.
```csharp showLineNumbers
using AdaptySDK;
void LoadPaywall() {
Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => {
if (error != null) {
// Handle the error
return;
}
Adapty.GetPaywallProducts(paywall, (products, productsError) => {
if (productsError != null) {
// Handle the error
return;
}
// Use products to build your custom paywall UI
});
});
}
```
## Шаг 2. Принимайте покупки \{#step-2-accept-purchases\}
Когда пользователь нажимает на продукт в вашем кастомном пейволе, вызовите метод `makePurchase` с выбранным продуктом. Это запустит процесс покупки и вернёт обновлённый профиль.
```csharp showLineNumbers
using AdaptySDK;
void PurchaseProduct(AdaptyPaywallProduct product) {
Adapty.MakePurchase(product, (result, error) => {
if (error != null) {
// Handle the error
return;
}
switch (result.Type) {
case AdaptyPurchaseResultType.Success:
var profile = result.Profile;
// Purchase successful, profile updated
break;
case AdaptyPurchaseResultType.UserCancelled:
// User canceled the purchase
break;
case AdaptyPurchaseResultType.Pending:
// Purchase is pending (e.g., user will pay offline with cash)
break;
}
});
}
```
## Шаг 3. Восстановите покупки \{#step-3-restore-purchases\}
Сторы требуют, чтобы все приложения с подписками предоставляли пользователям возможность восстановить покупки.
Вызовите метод `restorePurchases`, когда пользователь нажимает кнопку восстановления. Это синхронизирует историю покупок с Adapty и вернёт обновлённый профиль.
```csharp showLineNumbers
using AdaptySDK;
void RestorePurchases() {
Adapty.RestorePurchases((profile, error) => {
if (error != null) {
// Handle the error
return;
}
// Restore successful, profile updated
});
}
```
## Следующие шаги \{#next-steps\}
:::tip
Есть вопросы или возникли проблемы? Загляните на наш [форум поддержки](https://adapty.featurebase.app/), где можно найти ответы на распространённые вопросы или задать свой. Наша команда и сообщество всегда готовы помочь!
:::
Ваш пейвол готов к отображению в приложении. Протестируйте покупки в [песочнице App Store](test-purchases-in-sandbox) или в [Google Play Store](testing-on-android), чтобы убедиться, что вы можете совершить тестовую покупку через пейвол.
Далее [проверьте, завершили ли пользователи покупку](unity-check-subscription-status), чтобы решить, показывать ли пейвол или предоставить доступ к платным функциям.
---
# File: fetch-paywalls-and-products-unity
---
---
title: "Получение пейволов и продуктов для пейволов с Remote Config в Unity SDK"
description: "Получайте пейволы и продукты в Adapty Unity SDK для улучшения монетизации пользователей."
---
Прежде чем отображать Remote Config и кастомные пейволы, нужно получить информацию о них. Обратите внимание, что этот раздел посвящён Remote Config и кастомным пейволам. Для получения пейволов, настроенных в Paywall Builder, смотрите [Получение пейволов Paywall Builder и их конфигурации](unity-get-pb-paywalls).
:::tip
Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции.
:::
опциональный
по умолчанию: `en`
|Идентификатор [локализации пейвола](add-remote-config-locale). Ожидается код языка, состоящий из одного или нескольких подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Например: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендуемых подходах к их использованию — в разделе [Локализации и коды локалей](unity-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кешированные данные в случае сбоя. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.
Однако если ваши пользователи часто сталкиваются с нестабильным интернет-соединением, рассмотрите использование `.returnCacheDataElseLoad` — этот режим возвращает кешированные данные, если они есть. В таком сценарии пользователи могут получать не самые свежие данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в рамках сессии для снижения количества сетевых запросов.
Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит пейволы на двух уровнях: регулярно обновляемый кеш, описанный выше, и [резервные пейволы](unity-use-fallback-paywalls). Также используется CDN для более быстрой загрузки пейволов и отдельный резервный сервер на случай недоступности CDN. Такая система гарантирует, что вы всегда получаете актуальную версию пейволов, обеспечивая надёжность даже при слабом интернете.
| | **loadTimeout** | по умолчанию: 5 сек |Ограничивает время ожидания для данного метода. По истечении таймаута будут возвращены кешированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может завершиться с небольшой задержкой сверх значения, указанного в `loadTimeout`, так как операция может включать несколько запросов под капотом.
| Не задавайте ID продуктов жёстко в коде! Поскольку пейволы настраиваются удалённо, набор доступных продуктов, их количество и специальные предложения (например, бесплатные пробные периоды) могут меняться со временем. Убедитесь, что ваш код учитывает эти сценарии. Например, если изначально вы получаете 2 продукта, приложение должно отображать именно 2 продукта. Но если позднее вы получите 3 продукта, приложение должно показать все 3 без каких-либо изменений в коде. Единственное, что нужно задать жёстко, — это ID плейсмента. Параметры ответа: | Параметр | Описание | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Объект [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) со списком идентификаторов продуктов, идентификатором пейвола, Remote Config и рядом других свойств. | ## Получение продуктов \{#fetch-products\} Получив пейвол, вы можете запросить массив продуктов, соответствующих ему: ```csharp showLineNumbers Adapty.GetPaywallProducts(paywall, (products, error) => { if(error != null) { // handle the error return; } // products - the requested products array }); ``` Параметры ответа: | Параметр | Описание | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Список объектов [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) с: идентификатором продукта, названием продукта, ценой, валютой, длительностью подписки и рядом других свойств. | При реализации собственного дизайна пейвола вам, скорее всего, понадобятся свойства объекта [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html). Ниже приведены наиболее часто используемые из них, полный список доступных свойств смотрите в документации по ссылке. | Свойство | Описание | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Чтобы отобразить название продукта, используйте `product.LocalizedTitle`. Обратите внимание: локализация зависит от выбранной пользователем страны стора, а не от локали устройства. | | **Price** | Чтобы отобразить цену в локализованном формате, используйте `product.Price.LocalizedString`. Локализация основана на локали устройства. Цену в числовом виде можно получить через `product.Price.Amount` — значение будет в местной валюте. Символ валюты доступен через `product.Price.CurrencySymbol`. | | **Subscription Period** | Чтобы отобразить период подписки (например, неделя, месяц, год и т. д.), используйте `product.Subscription?.LocalizedPeriod`. Локализация основана на локали устройства. Для программного получения периода подписки используйте `product.Subscription?.Period`. Через это свойство доступен enum `Unit` со значениями `AdaptySubscriptionPeriodUnit.Day`, `AdaptySubscriptionPeriodUnit.Week`, `AdaptySubscriptionPeriodUnit.Month`, `AdaptySubscriptionPeriodUnit.Year` и `AdaptySubscriptionPeriodUnit.Unknown`. Значение `NumberOfUnits` содержит количество единиц периода. Например, для квартальной подписки в свойстве `Unit` будет `AdaptySubscriptionPeriodUnit.Month`, а в `NumberOfUnits` — `3`. | | **Introductory Offer** | Чтобы отобразить бейдж или другой индикатор наличия introductory offer в подписке, проверьте свойство `product.Subscription?.Offer?.Phases`. Это список, который может содержать до двух фаз скидки: фазу бесплатного пробного периода и фазу вводной цены. Каждый объект фазы содержит следующие полезные свойства:необязательный
по умолчанию: `en`
|Идентификатор локализации пейвола. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег обозначает язык, второй — регион.
Например: `en` — английский, `pt-br` — бразильский португальский.
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае сбоя. Мы рекомендуем этот вариант — он гарантирует, что пользователи всегда получают актуальные данные.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите использование `.returnCacheDataElseLoad`: оно возвращает кэшированные данные, если они есть. В этом случае пользователи могут не получить самые последние данные, но загрузка будет быстрее независимо от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.
Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.
Adapty SDK хранит пейволы локально на двух уровнях: регулярно обновляемый кэш, описанный выше, и резервные пейволы. Для более быстрой загрузки пейволов мы также используем CDN и отдельный резервный сервер на случай недоступности CDN. Такая система гарантирует, что вы всегда получаете последнюю версию пейволов, обеспечивая надёжность даже при нестабильном интернет-соединении.
| --- # File: present-remote-config-paywalls-unity --- --- title: "Отображение пейвола, настроенного через Remote Config, в Unity SDK" description: "Узнайте, как отображать пейволы на основе Remote Config в Adapty Unity SDK для персонализации пользовательского опыта." --- Если вы настроили пейвол с помощью Remote Config, вам потребуется реализовать его отображение в коде мобильного приложения. Поскольку Remote Config гибко адаптируется под ваши нужды, вы сами решаете, что включать в пейвол и как он будет выглядеть. Мы предоставляем метод для получения Remote Config, а дальнейшее отображение пейвола остаётся за вами. ## Получение Remote Config пейвола и его отображение \{#get-paywall-remote-config-and-present-it\} Чтобы получить Remote Config пейвола, обратитесь к свойству `remoteConfig` и извлеките нужные значения. ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if (error != null) { // handle the error return; } // Access remote config dictionary var dictionary = paywall.RemoteConfig?.Dictionary; var headerText = dictionary?["header_text"] as string; // Or access raw JSON data var jsonData = paywall.RemoteConfig?.Data; }); ``` Получив все необходимые значения, приступайте к отрисовке и сборке пейвола. Убедитесь, что дизайн адаптируется под разные экраны и ориентации устройств — это обеспечит удобный пользовательский опыт на любом устройстве. :::warning Не забудьте [зафиксировать событие просмотра пейвола](present-remote-config-paywalls-unity#track-paywall-view-events), как описано ниже — это позволит аналитике Adapty собирать данные для воронок и A/B-тестов. ::: После отображения пейвола настройте процесс покупки. Когда пользователь совершает покупку, вызовите `.MakePurchase()` с продуктом из вашего пейвола. Подробнее о методе `.MakePurchase()` читайте в разделе [Совершение покупок](unity-making-purchases). Рекомендуем также [создать резервный пейвол (fallback paywall)](unity-use-fallback-paywalls). Он будет отображаться пользователю при отсутствии интернета или кеша, обеспечивая бесперебойную работу приложения в таких ситуациях. ## Отслеживание событий просмотра пейвола \{#track-paywall-view-events\} Adapty помогает измерять эффективность ваших пейволов. Данные о покупках мы собираем автоматически, а вот просмотры пейволов нужно логировать вручную — только вы знаете, когда пользователь видит пейвол. Чтобы зафиксировать событие просмотра, вызовите `.LogShowPaywall(paywall)` — это отразится в метриках пейвола в воронках и A/B-тестах. :::important Вызов `.LogShowPaywall(paywall)` не требуется, если вы отображаете пейволы, созданные в [Paywall Builder](adapty-paywall-builder). ::: ```csharp showLineNumbers Adapty.LogShowPaywall(paywall, (error) => { // handle the error }); ``` Параметры запроса: | Параметр | Обязательный | Описание | | :---------- | :----------- |:------------------------------------------------------------------| | **paywall** | да | Объект [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). | --- # File: unity-making-purchases --- --- title: "Совершение покупок в мобильном приложении с Unity SDK" description: "Гайд по обработке встроенных покупок и подписок с помощью Adapty." --- Отображение пейволов в мобильном приложении — обязательный шаг для предоставления пользователям доступа к премиум-контенту или сервисам. Однако просто показать пейвол достаточно для поддержки покупок только в том случае, если вы используете [Paywall Builder](adapty-paywall-builder) для его настройки. Если вы не используете Paywall Builder, для совершения покупки и открытия нужного контента необходимо вызвать отдельный метод `.makePurchase()`. Именно через него пользователи взаимодействуют с пейволами и выполняют нужные транзакции. Если на вашем пейволе настроен активный promotional offer для продукта, который пользователь хочет купить, Adapty автоматически применит его в момент покупки. :::warning Обратите внимание: introductory offer применяется автоматически только при использовании пейволов, созданных с помощью Paywall Builder. В других случаях вам потребуется [проверить право пользователя на introductory offer в iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Пропуск этого шага может привести к отклонению приложения при релизе. Кроме того, пользователям, которым положен introductory offer, может быть выставлена полная цена. ::: Убедитесь, что вы [выполнили начальную настройку](quickstart), не пропустив ни одного шага. Без неё мы не сможем валидировать покупки. ## Совершение покупки \{#make-purchase\} :::note **Используете [Paywall Builder](adapty-paywall-builder)?** Покупки обрабатываются автоматически — этот шаг можно пропустить. **Нужна пошаговая инструкция?** Ознакомьтесь с [гайдом по быстрому старту](unity-implement-paywalls-manually) — там есть полное руководство по реализации с подробным контекстом. ::: ```csharp showLineNumbers using AdaptySDK; void MakePurchase(AdaptyPaywallProduct product) { Adapty.MakePurchase(product, (result, error) => { switch (result.Type) { case AdaptyPurchaseResultType.Pending: // handle pending purchase break; case AdaptyPurchaseResultType.UserCancelled: // handle purchase cancellation break; case AdaptyPurchaseResultType.Success: var profile = result.Profile; // handle successfull purchase break; default: break; } }); } ``` Параметры запроса: | Параметр | Наличие | Описание | | :---------- | :------- |:------------------------------------------------------------------------------------------------------| | **Product** | обязательный | Объект [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html), полученный из пейвола. | Параметры ответа: | Параметр | Описание | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |При успешном запросе ответ содержит этот объект. Объект [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html) предоставляет исчерпывающую информацию об уровнях доступа пользователя, подписках и разовых покупках в приложении.
Проверьте статус уровня доступа, чтобы убедиться, что у пользователя есть необходимый доступ к приложению.
| :::warning **Примечание:** если вы используете Apple StoreKit версии ниже 2.0 и Adapty SDK версии ниже v2.9.0, вам необходимо указать [общий секрет App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret). Этот метод в настоящее время устарел и не рекомендован Apple. ::: ## Смена подписки при покупке \{#change-subscription-when-making-a-purchase\} Когда пользователь выбирает новую подписку вместо продления текущей, поведение зависит от стора: - В App Store подписка обновляется автоматически в рамках группы подписок. Если пользователь покупает подписку из одной группы, уже имея активную из другой, обе подписки будут действовать одновременно. - В Google Play подписка не обновляется автоматически. Переключение нужно реализовать в коде приложения, как описано ниже. Чтобы заменить подписку на другую в Android, вызовите метод `.makePurchase()` с дополнительным параметром: ```csharp showLineNumbers // Create subscription update parameters var subscriptionUpdateParams = new AdaptySubscriptionUpdateParameters( "old_product_id", // Product ID of the current subscription AdaptySubscriptionUpdateReplacementMode.WithTimeProration ); Adapty.MakePurchase(product, subscriptionUpdateParams, (profile, error) => { if(error != null) { // Handle the error return; } // successful cross-grade }); ``` Дополнительный параметр запроса: | Параметр | Наличие | Описание | | :--------------------------- | :------- |:-------------------------------------------------------------------------------------------------------| | **subscriptionUpdateParams** | обязателен | объект [`AdaptySubscriptionUpdateParameters`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_subscription_update_parameters.html). | Подробнее о подписках и режимах замены читайте в документации Google Developer: - [О режимах замены](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Рекомендации Google по режимам замены](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Режим замены [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Примечание: этот метод доступен только для апгрейда подписки. Даунгрейд не поддерживается. - Режим замены [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Примечание: фактическая смена подписки произойдёт только по окончании текущего расчётного периода. ## Активация промокодов в iOS \{#redeem-offer-codes-in-ios\}Объект [`AdaptyProfile`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). Модель содержит информацию об уровнях доступа, подписках и разовых покупках.
Проверьте **статус уровня доступа**, чтобы определить, есть ли у пользователя доступ к приложению.
| :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: --- # File: implement-observer-mode-unity --- --- title: "Реализация режима Observer в Unity SDK" description: "Реализуйте режим Observer в Adapty для отслеживания событий подписки пользователей в Unity SDK." --- Если у вас уже есть собственная инфраструктура покупок и вы не готовы полностью переходить на Adapty, вы можете воспользоваться [режимом Observer](observer-vs-full-mode). В базовом варианте режим Observer обеспечивает расширенную аналитику и бесшовную интеграцию с системами атрибуции и аналитики. Если это соответствует вашим потребностям, вам нужно только: 1. Включить его при настройке Adapty SDK, установив параметр `observerMode` в значение `true`. Следуйте инструкциям по настройке для [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 2. [Передавать транзакции](report-transactions-observer-mode-unity) из вашей существующей инфраструктуры покупок в Adapty. ### Настройка режима Observer \{#observer-mode-setup\} Включите режим Observer, если вы самостоятельно обрабатываете покупки и управляете статусом подписки, а Adapty используете для отправки событий подписки и аналитики. :::important В режиме Observer Adapty SDK не закрывает транзакции, поэтому убедитесь, что вы обрабатываете их самостоятельно. ::: ```csharp showLineNumbers title="C#" using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, AdaptyEventListener { void Start() { DontDestroyOnLoad(this.gameObject); Adapty.SetEventListener(this); var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetObserverMode(true); // Enable observer mode Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); } public void OnLoadLatestProfile(AdaptyProfile profile) { } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } } ``` Параметры: | Параметр | Описание | |--------------|---------------------------------------------------------------------------------------------------------------| | observerMode | Булево значение, управляющее [режимом Observer](observer-vs-full-mode). Значение по умолчанию — `false`. | ## Использование пейволов Adapty в режиме Observer \{#using-adapty-paywalls-in-observer-mode\} Если вы также хотите использовать пейволы и функции A/B-тестирования Adapty — это возможно, но потребует дополнительной настройки в режиме Observer. Помимо шагов выше, вам нужно будет: 1. Отображать пейволы как обычно для [пейволов на Remote Config](present-remote-config-paywalls-unity). 3. [Связать пейволы](report-transactions-observer-mode-unity) с транзакциями покупок. --- # File: report-transactions-observer-mode-unity --- --- title: "Отчёт о транзакциях в Observer Mode в Unity SDK" description: "Сообщайте о транзакциях покупок в Observer Mode Adapty для отслеживания пользовательских данных и дохода в Unity SDK." ---Для iOS, StoreKit 1: объект [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Для iOS, StoreKit 2: объект [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Для Android: строковый идентификатор (purchase.getOrderId покупки, где покупка — экземпляр класса [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) из библиотеки биллинга.
| | variationId | обязательный | Строковый идентификатор варианта. Его можно получить через свойство `variationId` объекта [AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). |phoneNumber
firstName
lastName
| String | | gender | Enum, допустимые значения: `female`, `male`, `other` | | birthday | Date | ### Пользовательские атрибуты \{#custom-user-attributes\} Вы можете задавать собственные атрибуты, связанные с использованием приложения. Например, для фитнес-приложений это может быть количество тренировок в неделю, для приложений по изучению языков — уровень знаний пользователя и т. д. Атрибуты можно применять в сегментах для создания персонализированных пейволов и предложений, а также в аналитике — чтобы понять, какие продуктовые метрики сильнее всего влияют на выручку. ```csharp showLineNumbers try { builder = builder.SetCustomStringAttribute("string_key", "string_value"); builder = builder.SetCustomDoubleAttribute("double_key", 123.0f); } catch (Exception e) { // handle the exception } ``` Чтобы удалить существующий ключ, используйте метод `.withRemoved(customAttributeForKey:)`: ```csharp showLineNumbers try { builder = builder.RemoveCustomAttribute("key_to_remove"); } catch (Exception e) { // handle the exception } ``` Иногда нужно узнать, какие пользовательские атрибуты уже установлены. Для этого используйте поле `customAttributes` объекта `AdaptyProfile`. :::warning Имейте в виду, что значение `customAttributes` может быть устаревшим: атрибуты пользователя могут отправляться с разных устройств в любое время, поэтому данные на сервере могут измениться после последней синхронизации. ::: ### Ограничения \{#limits\} - До 30 пользовательских атрибутов на одного пользователя. - Длина имени ключа — до 30 символов. Допустимые символы: буквы, цифры, а также `_`, `-`, `.`. - Значение может быть строкой или числом с плавающей точкой длиной не более 50 символов. --- # File: unity-listen-subscription-changes --- --- title: "Проверка статуса подписки в Unity SDK" description: "Отслеживайте и управляйте статусом подписки пользователей в Adapty для повышения удержания клиентов в вашем Unity-приложении." --- С Adapty отслеживать статус подписки очень просто. Не нужно вручную прописывать идентификаторы продуктов в коде — достаточно проверить наличие активного [уровня доступа](access-level), чтобы узнать, есть ли у пользователя активная подписка.Объект [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). Как правило, для определения доступа к премиум-функциям достаточно проверить статус уровня доступа профиля.
Метод `.getProfile` всегда пытается обратиться к API и возвращает наиболее актуальные данные. Если по какой-то причине (например, при отсутствии интернета) Adapty SDK не может получить данные с сервера, возвращаются данные из кэша. Важно учитывать, что Adapty SDK регулярно обновляет кэш `AdaptyProfile`, чтобы поддерживать информацию в актуальном состоянии.
| Метод `.getProfile()` возвращает профиль пользователя, из которого можно получить статус уровня доступа. В приложении может быть несколько уровней доступа. Например, в газетном приложении с независимыми подписками на разные темы можно создать уровни доступа «sports» и «science». Но в большинстве случаев достаточно одного уровня доступа — тогда можно просто использовать уровень доступа "premium" по умолчанию. Пример проверки уровня доступа "premium" по умолчанию: ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // "premium" is an identifier of default access level var accessLevel = profile.AccessLevels["premium"]; if (accessLevel != null && accessLevel.IsActive) { // grant access to premium features } }); ``` ### Отслеживание обновлений статуса подписки \{#listening-for-subscription-status-updates\} При каждом изменении подписки пользователя Adapty генерирует событие. Чтобы получать сообщения от Adapty, необходимо выполнить дополнительную настройку: ```csharp showLineNumbers // Extend `AdaptyEventListener ` with `OnLoadLatestProfile ` method: public class AdaptyListener : MonoBehaviour, AdaptyEventListener { public void OnLoadLatestProfile(AdaptyProfile profile) { // handle any changes to subscription state } } ``` Adapty также генерирует событие при запуске приложения. В этом случае передаётся кэшированный статус подписки. ### Кэш статуса подписки \{#subscription-status-cache\} Кэш, реализованный в Adapty SDK, хранит статус подписки профиля. Это означает, что даже при недоступности сервера из кэша можно получить информацию о статусе подписки профиля. Однако важно учитывать, что напрямую запрашивать данные из кэша невозможно. SDK периодически обращается к серверу каждую минуту, чтобы проверить наличие обновлений профиля. При наличии изменений — например, новых транзакций или других обновлений — они записываются в кэш, чтобы он оставался синхронизированным с сервером. --- # File: unity-deal-with-att --- --- title: "Работа с ATT в Unity SDK" description: "Начните работу с Adapty на Unity для удобной настройки и управления подписками." --- Если ваше приложение использует фреймворк AppTrackingTransparency и запрашивает у пользователя разрешение на отслеживание, необходимо передать [статус авторизации](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) в Adapty. ```csharp showLineNumbers var builder = new Adapty.ProfileParameters.Builder() .SetAppTrackingTransparencyStatus(IOSAppTrackingTransparencyStatus.Authorized); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != null) { // handle the error } }); ``` :::warning Настоятельно рекомендуем передавать это значение как можно раньше при каждом его изменении — только тогда данные будут своевременно отправлены в настроенные вами интеграции. ::: --- # File: kids-mode-unity --- --- title: "Режим для детей в Unity SDK" description: "Легко включите режим для детей, чтобы соответствовать политикам Apple и Google. В Unity SDK не собираются IDFA, GAID или рекламные данные." --- Если ваше Unity-приложение предназначено для детей, вы обязаны соблюдать политики [Apple](https://developer.apple.com/kids/) и [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Если вы используете Adapty SDK, несколько простых шагов помогут настроить его в соответствии с этими политиками и пройти проверку в сторах. ## Что нужно сделать? \{#whats-required\} Необходимо настроить Adapty SDK так, чтобы отключить сбор следующих данных: - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS) - [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android) - [IP-адрес](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) Кроме того, рекомендуем осторожно использовать пользовательский ID. Идентификатор в формате `опциональный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе [Локализации и коды локалей](flutter-localizations-and-locale-codes).
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует актуальность данных для пользователей.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите `.returnCacheDataElseLoad` — он возвращает кэш, если он есть. В этом случае данные могут быть не самыми свежими, зато загрузка будет быстрее при любом качестве соединения. Кэш регулярно обновляется, поэтому использовать его в течение сессии для сокращения сетевых запросов безопасно.
Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при переустановке или ручной очистке.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кэш (описан выше) и резервные онбординги. Также используется CDN для ускорения загрузки и отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает актуальность онбордингов и надёжность даже при нестабильном интернет-соединении.
| | **loadTimeout** | по умолчанию: 5 сек |Ограничивает таймаут выполнения метода. По истечении таймаута возвращаются кэшированные данные или локальный резервный вариант.
Обратите внимание: в редких случаях метод может превысить таймаут, указанный в `loadTimeout`, поскольку операция может включать несколько запросов под капотом.
| Параметры ответа: | Параметр | Описание | |:----------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Объект [`AdaptyOnboarding`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_onboarding.html), содержащий: идентификатор и конфигурацию онбординга, Remote Config и ряд других свойств. | После получения онбординга вызовите метод `CreateOnboardingView`. :::warning Результат метода `CreateOnboardingView` можно использовать только один раз. Если нужно использовать его повторно, вызовите `CreateOnboardingView` заново. Повторный вызов без пересоздания может привести к ошибке `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers AdaptyUI.CreateOnboardingView(onboarding, (view, error) => { // handle the result }); ``` Параметры: | Параметр | Обязательность | Описание | |:---------------| :------------- |:-----------------------------------------------------------------------------| | **onboarding** | обязательный | Объект `AdaptyOnboarding` для получения представления нужного онбординга. | | **externalUrlsPresentation** |опциональный
по умолчанию: `InAppBrowser`
|Управляет тем, как открываются ссылки в онбординге. Доступные варианты:
- `AdaptyWebPresentation.InAppBrowser` — открывает ссылки во встроенном браузере (по умолчанию)
- `AdaptyWebPresentation.ExternalBrowser` — открывает ссылки во внешнем браузере устройства
Примеры использования см. в разделе [Настройка открытия ссылок в онбордингах](unity-present-onboardings#customize-how-links-open-in-onboardings).
| После успешной загрузки онбординга и его конфигурации отображения вы можете [показать его в мобильном приложении](unity-present-onboardings). ## Ускорение загрузки онбординга с помощью онбординга для аудитории по умолчанию \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Как правило, онбординги загружаются практически мгновенно, и беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и онбордингов, а у пользователей слабое интернет-соединение, загрузка онбординга может занять больше времени, чем хотелось бы. В таких случаях можно отображать онбординг по умолчанию, чтобы обеспечить плавный пользовательский опыт, а не показывать пустой экран. Для этого используйте метод `GetOnboardingForDefaultAudience`, который загружает онбординг указанного плейсмента для аудитории **All Users**. Важно понимать, что рекомендуемый подход — получать онбординг методом `getOnboarding`, как описано в разделе [Получение онбординга](#fetch-onboarding) выше. :::warning По возможности используйте `GetOnboarding` вместо `GetOnboardingForDefaultAudience`, поскольку у последнего есть существенные ограничения: - **Проблемы совместимости**: могут возникнуть сложности при поддержке нескольких версий приложения — придётся либо делать обратно совместимый дизайн, либо мириться с тем, что старые версии могут отображаться некорректно. - **Отсутствие персонализации**: отображается только контент для аудитории «All Users» без таргетинга по стране, атрибуции или пользовательским атрибутам. Если скорость загрузки важнее этих ограничений для вашего случая, используйте `GetOnboardingForDefaultAudience`, как показано ниже. В остальных случаях используйте `GetOnboarding`, как описано [выше](#fetch-onboarding). ::: ```csharp showLineNumbers Adapty.GetOnboardingForDefaultAudience("YOUR_PLACEMENT_ID", (onboarding, error) => { if (error != null) { // handle the error return; } // the requested onboarding }); ``` Параметры: | Параметр | Обязательность | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указывали при создании плейсмента в дашборде Adapty. | | **locale** |опциональный
по умолчанию: `en`
|Идентификатор локализации онбординга. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых символом минус (**-**). Первый подтег — язык, второй — регион.
Пример: `en` — английский, `pt-br` — бразильский португальский.
| | **fetchPolicy** | по умолчанию: `.reloadRevalidatingCacheData` |По умолчанию SDK пытается загрузить данные с сервера и возвращает кэшированные данные в случае ошибки. Мы рекомендуем этот вариант, так как он гарантирует актуальность данных для пользователей.
Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите `.returnCacheDataElseLoad` — он возвращает кэш, если он есть. В этом случае данные могут быть не самыми свежими, зато загрузка будет быстрее при любом качестве соединения. Кэш регулярно обновляется, поэтому использовать его в течение сессии для сокращения сетевых запросов безопасно.
Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при переустановке или ручной очистке.
Adapty SDK хранит онбординги локально в двух слоях: регулярно обновляемый кэш (описан выше) и резервные онбординги. Также используется CDN для ускорения загрузки и отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает актуальность онбордингов и надёжность даже при нестабильном интернет-соединении.
| --- # File: unity-present-onboardings --- --- title: "Показ онбординга в Unity SDK" description: "Узнайте, как эффективно показывать онбординги для повышения конверсии." --- Если вы настроили онбординг с помощью билдера, вам не нужно беспокоиться о его отрисовке в коде Unity-приложения для показа пользователю. Такой онбординг содержит как то, что должно отображаться внутри него, так и то, как именно это должно отображаться. Прежде чем начать, убедитесь, что: 1. Вы установили [Adapty Unity SDK](sdk-installation-unity) версии 3.14.0 или новее. 2. Вы [создали онбординг](create-onboarding). 3. Вы добавили онбординг в [плейсмент](placements). Чтобы отобразить онбординг, вызовите метод `view.Present()` на объекте `view`, созданном методом `CreateOnboardingView`. Каждый `view` можно использовать только один раз. Если нужно показать пейвол повторно, вызовите `CreateOnboardingView` ещё раз, чтобы создать новый экземпляр `view`. :::warning Повторное использование одного и того же `view` без его пересоздания может привести к ошибке `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers title="Unity" view.Present((presentError) => { if (presentError != null) { // handle the error } }; ``` ## Настройка стиля презентации на iOS \{#configure-ios-presentation-style\} Настройте способ отображения онбординга на iOS, передав параметр `iosPresentationStyle` в метод `Present()`. Параметр принимает значения `AdaptyUIIOSPresentationStyle.FullScreen` (по умолчанию) или `AdaptyUIIOSPresentationStyle.PageSheet`. ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` ## Настройка открытия ссылок в онбординге \{#customize-how-links-open-in-onboardings\} :::important Настройка способа открытия ссылок в онбординге поддерживается начиная с Adapty SDK v3.15. ::: По умолчанию ссылки в онбординге открываются во встроенном браузере — это обеспечивает удобство работы, поскольку веб-страницы отображаются прямо внутри приложения без переключения между приложениями. Чтобы ссылки открывались во внешнем браузере, передайте `AdaptyWebPresentation.ExternalBrowser` в метод `CreateOnboardingView`: ```csharp showLineNumbers title="Unity" AdaptyUI.CreateOnboardingView( onboarding, AdaptyWebPresentation.ExternalBrowser, // default — InAppBrowser (view, error) => { if (error != null) { // handle the error return; } // present the onboarding view view.Present((presentError) => { if (presentError != null) { // handle the error } }); } ); ``` Доступные варианты: - `AdaptyWebPresentation.InAppBrowser` — открывает ссылки во встроенном браузере (по умолчанию) - `AdaptyWebPresentation.ExternalBrowser` — открывает ссылки во внешнем браузере устройства --- # File: unity-handling-onboarding-events --- --- title: "Обработка событий онбординга в Unity SDK" description: "Обрабатывайте события онбординга в Unity с помощью Adapty." --- Прежде чем начать, убедитесь, что: 1. Вы установили [Adapty Unity SDK](sdk-installation-unity) версии 3.14.0 или новее. 2. Вы [создали онбординг](create-onboarding). 3. Вы добавили онбординг в [плейсмент](placements). Онбординги, настроенные с помощью конструктора, генерируют события, на которые может реагировать ваше приложение. Ниже описано, как с ними работать. Чтобы управлять процессами на экране онбординга в Unity-приложении или отслеживать их, реализуйте интерфейс `AdaptyOnboardingsEventsListener`. ## Пользовательские действия \{#custom-actions\} В конструкторе можно добавить к кнопке действие **custom** и назначить ему ID.
Затем вы можете использовать этот ID в своём коде и обрабатывать его как пользовательское действие. Например, если пользователь нажимает на кнопку, такую как **Login** или **Allow notifications**, будет вызван метод `OnboardingViewOnCustomAction` с параметром `actionId`, соответствующим **Action ID** из билдера. Вы можете задавать собственные ID, например "allowNotifications".
Чтобы обрабатывать события онбординга, реализуйте интерфейс `AdaptyOnboardingsEventsListener`:
```csharp showLineNumbers title="Unity"
public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener
{
void Start()
{
Adapty.SetOnboardingsEventsListener(this);
}
public void OnboardingViewOnCustomAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
string actionId
)
{
if (actionId == "allowNotifications") {
// request notification permissions
}
}
public void OnboardingViewDidFailWithError(
AdaptyUIOnboardingView view,
AdaptyError error
)
{
// handle errors
}
// Implement other required interface methods (see examples below)
}
```
:::important
Обратите внимание: вам нужно самостоятельно обработать закрытие онбординга. Например, скрыть экран онбординга.
:::
Реализуйте метод `OnboardingViewOnCloseAction` в своём классе:
```csharp showLineNumbers title="Unity"
public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener
{
public void OnboardingViewOnCloseAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
string actionId
)
{
view.Dismiss((error) => {
if (error != null) {
// handle the error
}
});
}
// ... other interface methods
}
```
2. Нажмите на название группы подписок. Вы увидите продукты в разделе **Subscriptions**.
3. Убедитесь, что тестируемый продукт отмечен как **Ready to Submit**.
4. Сравните идентификатор продукта из таблицы с тем, что указан на вкладке [**Products**](https://app.adapty.io/products) в дашборде Adapty. Если идентификаторы не совпадают, скопируйте идентификатор продукта из таблицы и [создайте продукт](create-product) с ним в дашборде Adapty.
## Шаг 3. Проверьте доступность продуктов \{#step-4-check-product-availability\}
1. Вернитесь в **App Store Connect** и откройте раздел **Subscriptions**.
2. Нажмите на название группы подписок, чтобы посмотреть продукты.
3. Выберите продукт, который хотите протестировать.
4. Прокрутите до раздела **Availability** и убедитесь, что все необходимые страны и регионы указаны.
## Шаг 4. Проверьте цены продуктов \{#step-5-check-product-prices\}
1. Снова перейдите в раздел **Monetization** → **Subscriptions** в **App Store Connect**.
2. Нажмите на название группы подписок.
3. Выберите продукт, который хотите протестировать.
4. Прокрутите вниз до раздела **Subscription Pricing** и разверните секцию **Current Pricing for New Subscribers**.
5. Убедитесь, что все необходимые цены указаны.
## Шаг 5. Убедитесь, что статус приложения, банковский счёт и налоговые формы активны \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. На главной странице [**App Store Connect**](https://appstoreconnect.apple.com/) нажмите **Business**.
2. Выберите название вашей компании.
3. Прокрутите вниз и убедитесь, что **Paid Apps Agreement**, **Bank Account** и **Tax forms** отображаются как **Active**.
Следуя этим шагам, вы сможете устранить предупреждение `InvalidProductIdentifiers` и опубликовать свои продукты в сторе.
## Шаг 6. Пересоздайте продукт, если он завис \{#step-6-recreate-the-product-if-its-stuck\}
Шаги 1–5 могут пройти успешно — статус `Approved`, совпадающий Bundle ID, валидный API-ключ — но SDK всё равно возвращает `1000 noProductIDsFound`. В таком случае продукт может быть завис в реестре Apple. Иногда реестр продуктов Apple переходит в состояние, при котором продукт существует в UI App Store Connect, но недоступен для StoreKit при поиске.
Удалите продукт в App Store Connect и пересоздайте его с тем же идентификатором. После пересоздания подождите до 24 часов — столько может занять распространение изменений.
---
# File: cantMakePayments-unity
---
---
title: "Исправление ошибки Code-1003 cantMakePayment в Unity SDK"
description: "Устранение ошибки при проведении платежей и управлении подписками в Adapty."
---
Ошибка 1003, `cantMakePayments`, означает, что на этом устройстве нельзя совершать встроенные покупки.
Если вы столкнулись с ошибкой `cantMakePayments`, обычно это происходит по одной из следующих причин:
- Ограничения устройства: ошибка не связана с Adapty. Способы решения описаны ниже.
- Настройка Observer mode: метод `makePurchase` и Observer mode нельзя использовать одновременно. Подробнее — в соответствующем разделе ниже.
## Проблема: ограничения устройства \{#issue-device-restrictions\}
| Проблема | Решение |
|---------------------------------|-------------------------------------------------------------------------------------------------------------------|
| Ограничения Screen Time | Отключите ограничения встроенных покупок в [Screen Time](https://support.apple.com/en-us/102470) |
| Аккаунт заблокирован | Обратитесь в службу поддержки Apple для решения проблем с аккаунтом |
| Региональные ограничения | Используйте аккаунт App Store из поддерживаемого региона |
## Проблема: одновременное использование Observer mode и makePurchase \{#issue-using-both-observer-mode-and-makepurchase\}
Если вы используете `makePurchase` для обработки покупок, Observer mode не нужен. [Observer mode](observer-vs-full-mode) требуется только в том случае, если логику покупок вы реализуете самостоятельно.
Таким образом, если вы используете `makePurchase`, можно смело убрать активацию Observer mode из кода инициализации SDK.
---
# File: migration-to-unity-sdk-314
---
---
title: "Миграция Adapty Unity SDK на v3.14"
description: "Перейдите на Adapty Unity SDK v3.14 для повышения производительности и новых функций монетизации."
---
Adapty SDK 3.14.0 — это крупный релиз, который принёс ряд улучшений, однако для перехода на него могут потребоваться дополнительные шаги с вашей стороны:
1. Отдельный обработчик событий пейвола.
2. Переименование `AdaptyUI.CreateView` в `AdaptyUI.CreatePaywallView` и связанных методов.
3. Обновление метода `MakePurchase` для использования `AdaptyPurchaseParameters` вместо отдельных параметров.
4. Замена `SetFallbackPaywalls` на метод `SetFallback`.
5. Обновление доступа к свойствам пейвола через `AdaptyPlacement`.
6. Обновление доступа к Remote Config через объект `AdaptyRemoteConfig`.
7. Замена `VendorProductIds` на `ProductIdentifiers` в модели `AdaptyPaywall`.
8. Обновление политики получения пейвола в `GetPaywall` для использования `AdaptyFetchPolicy`.
## Отдельный слушатель событий для пейвола \{#separate-event-listener-for-paywall-events\}
Если вы отображаете пейволы, созданные с помощью [Paywall Builder](adapty-paywall-builder), события пейвола теперь используют специальный интерфейс `AdaptyPaywallsEventsListener` и метод `SetPaywallsEventsListener`. Основной интерфейс `AdaptyEventListener` по-прежнему используется для обновлений профиля и данных об установке.
```diff showLineNumbers
using UnityEngine;
using AdaptySDK;
public class AdaptyListener : MonoBehaviour,
- AdaptyEventListener {
+ AdaptyEventListener,
+ AdaptyPaywallsEventsListener {
void Start() {
Adapty.SetEventListener(this);
+ Adapty.SetPaywallsEventsListener(this);
}
// AdaptyEventListener methods
public void OnLoadLatestProfile(AdaptyProfile profile) { }
public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { }
public void OnInstallationDetailsFail(AdaptyError error) { }
+ // AdaptyPaywallsEventsListener methods
+ // Implement paywall event handlers here
}
```
[Подробнее об обработке событий пейвола](unity-handling-events).
## Переименование методов создания и отображения представления \{#rename-view-creation-and-presentation-methods\}
Методы создания и отображения представления были переименованы:
```diff showLineNumbers
using AdaptySDK;
- AdaptyUI.CreateView(paywall, parameters, (view, error) => {
+ AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => {
if (error != null) {
// handle the error
return;
}
- AdaptyUI.PresentView(view, (error) => {
+ AdaptyUI.PresentPaywallView(view, (error) => {
// handle the error
});
});
}
```
Аналогично был переименован метод закрытия:
```diff showLineNumbers
- AdaptyUI.DismissView(view, (error) => {
+ AdaptyUI.DismissPaywallView(view, (error) => {
// handle the error
});
```
## Обновление метода MakePurchase \{#update-makepurchase-method\}
Метод `MakePurchase` теперь принимает `AdaptyPurchaseParameters` вместо отдельных аргументов `subscriptionUpdateParams` и `isOfferPersonalized`. Это обеспечивает более строгую типизацию и упрощает добавление новых параметров покупки в будущем.
```diff showLineNumbers
using AdaptySDK;
void MakePurchase(
AdaptyPaywallProduct product,
AdaptySubscriptionUpdateParameters subscriptionUpdate,
bool? isOfferPersonalized
) {
- Adapty.MakePurchase(product, subscriptionUpdate, isOfferPersonalized, (result, error) => {
+ var parameters = new AdaptyPurchaseParametersBuilder()
+ .SetSubscriptionUpdateParams(subscriptionUpdate)
+ .SetIsOfferPersonalized(isOfferPersonalized)
+ .Build();
+
+ Adapty.MakePurchase(product, parameters, (result, error) => {
switch (result.Type) {
case AdaptyPurchaseResultType.Pending:
// handle pending purchase
break;
case AdaptyPurchaseResultType.UserCancelled:
// handle purchase cancellation
break;
case AdaptyPurchaseResultType.Success:
var profile = result.Profile;
// handle successful purchase
break;
default:
break;
}
});
}
```
Если дополнительные параметры не нужны, можно использовать упрощённый вариант:
```csharp showLineNumbers
using AdaptySDK;
void MakePurchase(AdaptyPaywallProduct product) {
Adapty.MakePurchase(product, (result, error) => {
// handle purchase result
});
}
```
## Обновление метода для резервных пейволов \{#update-fallback-method\}
:::important
При обновлении до Unity SDK 3.14 вам потребуется загрузить новые резервные файлы из дашборда Adapty и заменить существующие в вашем проекте.
:::
Метод для настройки резервных пейволов был обновлён. Метод `SetFallbackPaywalls` переименован в `SetFallback`:
```diff showLineNumbers
using AdaptySDK;
void SetFallBackPaywalls() {
#if UNITY_IOS
var assetId = "adapty_fallback_ios.json";
#elif UNITY_ANDROID
var assetId = "adapty_fallback_android.json";
#else
var assetId = "";
#endif
- Adapty.SetFallbackPaywalls(assetId, (error) => {
+ Adapty.SetFallback(assetId, (error) => {
// handle the error
});
}
```
Ознакомьтесь с полным примером кода на странице [Использование резервных пейволов в Unity](unity-use-fallback-paywalls).
## Обновление доступа к свойствам пейвола \{#update-paywall-property-access\}
Следующие свойства перенесены из `AdaptyPaywall` в `AdaptyPlacement`:
```diff showLineNumbers
using AdaptySDK;
void ProcessPaywall(AdaptyPaywall paywall) {
- var abTestName = paywall.ABTestName;
- var audienceName = paywall.AudienceName;
- var revision = paywall.Revision;
- var placementId = paywall.PlacementId;
+ var abTestName = paywall.Placement.ABTestName;
+ var audienceName = paywall.Placement.AudienceName;
+ var revision = paywall.Placement.Revision;
+ var placementId = paywall.Placement.Id;
}
```
## Обновление доступа к Remote Config \{#update-remote-config-access\}
Свойства Remote Config были реструктурированы в объект `AdaptyRemoteConfig` для лучшей организации:
```diff showLineNumbers
using AdaptySDK;
void ProcessRemoteConfig(AdaptyPaywall paywall) {
- var remoteConfigString = paywall.RemoteConfigString;
- var locale = paywall.Locale;
- var remoteConfigDict = paywall.RemoteConfig;
+ var remoteConfigString = paywall.RemoteConfig.Data;
+ var locale = paywall.RemoteConfig.Locale;
+ var remoteConfigDict = paywall.RemoteConfig.Dictionary;
}
```
## Обновление использования модели AdaptyPaywall \{#update-adaptypaywall-model-usage\}
Свойство `VendorProductIds` устарело и заменено на `ProductIdentifiers`. Новое свойство возвращает объекты `AdaptyProductIdentifier` вместо обычных строк, предоставляя более структурированную информацию о продуктах.
```diff showLineNumbers
using AdaptySDK;
void ProcessPaywallProducts(AdaptyPaywall paywall) {
- var productIds = paywall.VendorProductIds;
- foreach (var vendorId in productIds) {
- // use vendorId
- }
+ var productIdentifiers = paywall.ProductIdentifiers;
+ foreach (var productId in productIdentifiers) {
+ var vendorId = productId.VendorProductId;
+ // use vendorId
+ }
}
```
Объект `AdaptyProductIdentifier` предоставляет доступ к идентификатору продукта вендора через свойство `VendorProductId`, сохраняя ту же функциональность и обеспечивая лучшую структуру для будущих улучшений.
## Обновление политики загрузки в GetPaywall \{#update-getpaywall-fetch-policy\}
Тип параметра `fetchPolicy` в методе `GetPaywall` изменён с `AdaptyPaywallFetchPolicy` на `AdaptyPlacementFetchPolicy`. Это изменение унифицирует использование политики загрузки во всём SDK.
```diff showLineNumbers
using AdaptySDK;
void GetPaywall(string placementId) {
- Adapty.GetPaywall(placementId, AdaptyPaywallFetchPolicy.ReloadRevalidatingCacheData, null, (paywall, error) => {
+ Adapty.GetPaywall(placementId, AdaptyPlacementFetchPolicy.ReloadRevalidatingCacheData, null, (paywall, error) => {
// handle the result
});
}
```
---
# File: migration-to-unity-sdk-34
---
---
title: "Migrate Adapty Unity SDK to v. 3.4"
description: "Перейдите на Adapty Unity SDK v3.4 для повышения производительности и доступа к новым функциям монетизации."
---
Adapty SDK 3.4.0 — это мажорный релиз, который включает улучшения, требующие выполнения шагов миграции с вашей стороны.
## Обновите файлы резервного пейвола \{#update-fallback-paywall-files\}
Обновите файлы резервного пейвола, чтобы обеспечить совместимость с новой версией SDK:
1. [Скачайте обновлённые файлы резервного пейвола](fallback-paywalls) из дашборда Adapty.
2. [Замените существующие резервные пейволы в своём мобильном приложении](unity-use-fallback-paywalls) на новые файлы.
## Обновите реализацию Observer Mode \{#update-implementation-of-observer-mode\}
Если вы используете Observer Mode, убедитесь, что его реализация обновлена.
Раньше для передачи транзакций в Adapty использовались разные методы. В новой версии для этого нужно использовать метод `reportTransaction` — он работает одинаково на Android и iOS. Метод явно сообщает Adapty о каждой транзакции, гарантируя её распознавание. Если при покупке использовался пейвол, передайте variation ID, чтобы связать транзакцию с ним.
:::warning
**Не пропускайте отчёт о транзакции!**
Если не вызвать `reportTransaction`, Adapty не распознает транзакцию — она не появится в аналитике и не будет отправлена в интеграции.
:::
```diff showLineNumbers
- #if UNITY_ANDROID && !UNITY_EDITOR
- Adapty.RestorePurchases((profile, error) => {
- // handle the error
- });
- #endif
Adapty.ReportTransaction(
"YOUR_TRANSACTION_ID",
"PAYWALL_VARIATION_ID", // optional
(error) => {
// handle the error
});
```
---
# File: migration-to-unity330
---
---
title: "Миграция Adapty Unity SDK на v3.3"
description: "Выполните миграцию на Adapty Unity SDK v3.3 для повышения производительности и новых функций монетизации."
---
Adapty SDK 3.3.0 — это мажорный релиз, который принёс ряд улучшений, однако для перехода на него может потребоваться выполнить несколько шагов миграции.
1. Обновитесь до Adapty SDK v3.3.x.
2. Переименованы несколько классов, свойств и методов в модулях Adapty и AdaptyUI Adapty SDK.
3. Теперь метод `SetLogLevel` принимает callback в качестве аргумента.
4. Теперь метод `PresentCodeRedemptionSheet` принимает callback в качестве аргумента.
5. Изменён способ создания представления пейвола.
6. Метод `GetProductsIntroductoryOfferEligibility` удалён.
7. Сохраняйте резервные пейволы в отдельные файлы (по одному на платформу) в `Assets/StreamingAssets/` и передавайте имена файлов в метод `SetFallbackPaywalls`.
8. Обновлено выполнение покупки.
9. Обновлена обработка событий Paywall Builder.
10. Обновлена обработка ошибок пейвола Paywall Builder.
11. Обновлены конфигурации интеграций для Adjust, Amplitude, AppMetrica, Appsflyer, Branch, Firebase и Google Analytics, Mixpanel, OneSignal, Pushwoosh.
13. Обновлена реализация режима Observer.
14. Обновлена инициализация плагина Unity с явным вызовом `Activate`.
## Обновление Adapty Unity SDK до версии 3.3.x \{#upgrade-adapty-unity-sdk-to-33x\}
До этой версии Adapty SDK был основным и обязательным SDK для корректной работы Adapty в вашем приложении, а AdaptyUI SDK — опциональным, который требовался только при использовании Adapty Paywall Builder.
Начиная с версии 3.3.0, AdaptyUI SDK объявлен устаревшим, а AdaptyUI объединён с Adapty SDK в виде модуля. В связи с этими изменениями вам нужно удалить AdaptyUI SDK и переустановить Adapty SDK.
1. Удалите зависимости пакетов **AdaptySDK** и **AdaptyUISDK** из вашего проекта.
2. Удалите папки **AdaptySDK** и **AdaptyUISDK**.
3. Повторно импортируйте пакет AdaptySDK, как описано на странице [Установка и настройка Adapty SDK для Unity](sdk-installation-unity).
## Переименования \{#renamings\}
1. Переименования в модуле Adapty:
| Старая версия | Новая версия |
| ------------------------- | ------------------------ |
| Adapty.sdkVersion | Adapty.SDKVersion |
| Adapty.LogLevel | AdaptyLogLevel |
| Adapty.Paywall | AdaptyPaywall |
| Adapty.PaywallFetchPolicy | AdaptyPaywallFetchPolicy |
| PaywallProduct | AdaptyPaywallProduct |
| Adapty.Profile | AdaptyProfile |
| Adapty.ProfileParameters | AdaptyProfileParameters |
| ProfileGender | AdaptyProfileGender |
| Error | AdaptyError |
2. Переименования в модуле AdaptyUI:
| Старая версия | Новая версия |
| ------------------ | ------------------ |
| CreatePaywallView | CreateView |
| PresentPaywallView | PresentView |
| DismissPaywallView | DismissView |
| AdaptyUI.View | AdaptyUIView |
| AdaptyUI.Action | AdaptyUIUserAction |
## Изменение метода SetLogLevel \{#change-the-setloglevel-method\}
Теперь метод `SetLogLevel` принимает callback в качестве аргумента.
```diff showLineNumbers
- Adapty.SetLogLevel(Adapty.LogLevel.Verbose);
+ Adapty.SetLogLevel(Adapty.LogLevel.Verbose, null); // or you can pass the callback to handle the possible error
```
## Изменение метода PresentCodeRedemptionSheet \{#change-the-presentcoderedemptionsheet-method\}
Теперь метод `PresentCodeRedemptionSheet` принимает callback в качестве аргумента.
```diff showLineNumbers
- Adapty.PresentCodeRedemptionSheet();
+ Adapty.PresentCodeRedemptionSheet(null); // or you can pass the callback to handle the possible error
```
## Изменение способа создания вида пейвола \{#change-how-the-paywall-view-is-created\}
Полный пример кода см. в разделе [Получение конфигурации вида пейвола, созданного с помощью Paywall Builder](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder).
```diff showLineNumbers
+ var parameters = new AdaptyUICreateViewParameters()
+ .SetPreloadProducts(true);
- AdaptyUI.CreatePaywallView(
+ AdaptyUI.CreateView(
paywall,
- preloadProducts: true,
+ parameters,
(view, error) => {
// use the view
});
```
## Удаление метода GetProductsIntroductoryOfferEligibility \{#remove-the-getproductsintroductoryoffereligibility-method\}
До Adapty iOS SDK 3.3.0 объект продукта всегда содержал офферы, независимо от того, имел ли пользователь право на их получение. Вам приходилось вручную проверять это право перед использованием оффера.
Теперь объект продукта содержит оффер только в том случае, если пользователь имеет право на его получение. Это означает, что проверка права больше не нужна — если оффер присутствует, пользователь имеет на него право.
## Обновлённый метод передачи резервных пейволов \{#update-method-for-providing-fallback-paywalls\}
До этой версии резервные пейволы передавались в виде сериализованного JSON. Начиная с версии 3.3.0, механизм изменился:
1. Сохраните резервные пейволы в файлы в `/Assets/StreamingAssets/` — один файл для Android и один для iOS.
2. Передайте имена файлов в метод `SetFallbackPaywalls`.
Ваш код изменится следующим образом:
```diff showLineNumbers
using AdaptySDK;
void SetFallBackPaywalls() {
+ #if UNITY_IOS
+ var assetId = "adapty_fallback_ios.json";
+ #elif UNITY_ANDROID
+ var assetId = "adapty_fallback_android.json";
+ #else
+ var assetId = "";
+ #endif
- Adapty.SetFallbackPaywalls("FALLBACK_PAYWALLS_JSON_STRING", (error) => {
+ Adapty.SetFallbackPaywalls(assetId, (error) => {
// handle the error
});
}
```
Полный пример кода смотрите на странице [Использование резервных пейволов в Unity](unity-use-fallback-paywalls).
## Обновление процесса покупки \{#update-making-purchase\}
Ранее отменённые и ожидающие покупки считались ошибками и возвращали коды `PaymentCancelled` и `PendingPurchase` соответственно.
Теперь для обработки отменённых, успешных и ожидающих покупок используется новый класс `AdaptyPurchaseResultType`. Обновите код покупки следующим образом:
```diff showLineNumbers
using AdaptySDK;
void MakePurchase(AdaptyPaywallProduct product) {
- Adapty.MakePurchase(product, (profile, error) => {
- // handle successfull purchase
+ Adapty.MakePurchase(product, (result, error) => {
+ switch (result.Type) {
+ case AdaptyPurchaseResultType.Pending:
+ // handle pending purchase
+ break;
+ case AdaptyPurchaseResultType.UserCancelled:
+ // handle purchase cancellation
+ break;
+ case AdaptyPurchaseResultType.Success:
+ var profile = result.Profile;
+ // handle successful purchase
+ break;
+ default:
+ break;
}
});
}
```
Ознакомьтесь с финальным примером кода на странице [Совершение покупок в мобильном приложении](unity-making-purchases).
## Обновите обработку событий Paywall Builder \{#update-handling-of-paywall-builder-events\}
Отменённые и ожидающие покупки больше не считаются ошибками — все эти случаи обрабатываются методом `PaywallViewDidFinishPurchase`.
1. Удалите обработку события отменённой покупки.
2. Обновите обработку события успешной покупки следующим образом:
```diff showLineNumbers
- public void OnFinishPurchase(
- AdaptyUI.View view,
- Adapty.PaywallProduct product,
- Adapty.Profile profile
- ) { }
+ public void PaywallViewDidFinishPurchase(
+ AdaptyUIView view,
+ AdaptyPaywallProduct product,
+ AdaptyPurchaseResult purchasedResult
+ ) { }
```
3. Обновите обработку действий:
```diff showLineNumbers
- public void OnPerformAction(
- AdaptyUI.View view,
- AdaptyUI.Action action
- ) {
+ public void PaywallViewDidPerformAction(
+ AdaptyUIView view,
+ AdaptyUIUserAction action
+ ) {
switch (action.Type) {
- case AdaptyUI.ActionType.Close:
+ case AdaptyUIUserActionType.Close:
view.Dismiss(null);
break;
- case AdaptyUI.ActionType.OpenUrl:
+ case AdaptyUIUserActionType.OpenUrl:
var urlString = action.Value;
if (urlString != null {
Application.OpenURL(urlString);
}
default:
// handle other events
break;
}
}
```
4. Обновите обработку начала покупки:
```diff showLineNumbers
- public void OnSelectProduct(
- AdaptyUI.View view,
- Adapty.PaywallProduct product
- ) { }
+ public void PaywallViewDidSelectProduct(
+ AdaptyUIView view,
+ string productId
+ ) { }
```
5. Обновите обработку ошибки покупки:
```diff showLineNumbers
- public void OnFailPurchase(
- AdaptyUI.View view,
- Adapty.PaywallProduct product,
- Adapty.Error error
- ) { }
+ public void PaywallViewDidFailPurchase(
+ AdaptyUIView view,
+ AdaptyPaywallProduct product,
+ AdaptyError error
+ ) { }
```
6. Обновите обработку события успешного восстановления покупок:
Ознакомьтесь с финальным примером кода на странице [Обработка событий пейвола](unity-handling-events).
## Обновление обработки ошибок пейвола в Paywall Builder \{#update-handling-of-paywall-builder-paywall-errors\}
Обработка ошибок также изменилась — обновите свой код согласно инструкциям ниже.
1. Обновите обработку ошибок загрузки продуктов:
```diff showLineNumbers
- public void OnFailLoadingProducts(
- AdaptyUI.View view,
- Adapty.Error error
- ) { }
+ public void PaywallViewDidFailLoadingProducts(
+ AdaptyUIView view,
+ AdaptyError error
+ ) { }
```
2. Обновите обработку ошибок рендеринга:
```diff showLineNumbers
- public void OnFailRendering(
- AdaptyUI.View view,
- Adapty.Error error
- ) { }
+ public void PaywallViewDidFailRendering(
+ AdaptyUIView view,
+ AdaptyError error
+ ) { }
```
## Обновление конфигурации SDK сторонних интеграций \{#update-third-party-integration-sdk-configuration\}
Начиная с Adapty Unity SDK 3.3.0, публичный API метода `updateAttribution` обновлён. Ранее он принимал словарь `[AnyHashable: Any]`, позволяя передавать объекты атрибуции напрямую из различных сервисов. Теперь он требует `[String: any Sendable]`, поэтому перед передачей объекты атрибуции необходимо конвертировать.
Чтобы интеграции корректно работали с Adapty Unity SDK 3.3.0 и выше, обновите конфигурации SDK для следующих интеграций, как описано в разделах ниже.
### Adjust
Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Настройка SDK для интеграции с Adjust](adjust#connect-your-app-to-adjust).
```diff showLineNumbers
- using static AdaptySDK.Adapty;
using AdaptySDK;
Adjust.GetAdid((adid) => {
- Adjust.GetAttribution((attribution) => {
- Dictionary