# UNITY - 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.968Z Total files: 41 --- # File: sdk-installation-unity --- --- title: "Установка и настройка Unity SDK" description: "Пошаговое руководство по установке Adapty SDK на Unity для приложений с подписками." --- SDK Adapty включает два ключевых модуля для интеграции в ваше Unity-приложение: - **Core Adapty**: основной SDK, необходимый для работы Adapty в вашем приложении. - **AdaptyUI**: этот модуль нужен, если вы используете [Adapty Paywall Builder](adapty-paywall-builder) — удобный no-code инструмент для создания кроссплатформенных пейволов. :::tip Хотите посмотреть на реальный пример интеграции Adapty SDK в мобильное приложение? Изучите наш [пример приложения](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets) — в нём показана полная настройка: отображение пейволов, совершение покупок и другая базовая функциональность. ::: ## Требования \{#requirements\} Adapty SDK поддерживает iOS 13.0+, однако для работы с пейволами, созданными в Paywall Builder, требуется iOS 15.0+. :::info Adapty совместима с Google Play Billing Library версий до 8.x включительно. По умолчанию Adapty использует Google Play Billing Library v7.0.0. Чтобы использовать более новую версию, [переопределите зависимость Billing](https://developer.android.com/google/play/billing/integrate#dependency) в вашей Android-сборке. ::: :::info Установка SDK — это шаг 5 настройки Adapty. Прежде чем покупки заработают в вашем приложении, вам также нужно подключить приложение к сторам, а затем создать продукты, пейвол и плейсмент в дашборде Adapty. [Гайд по быстрому старту](quickstart) описывает все необходимые шаги. ::: ## Установка Adapty SDK \{#install-adapty-sdk\} [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Unity.svg?style=flat&logo=unity)](https://github.com/adaptyteam/AdaptySDK-Unity/releases) Выберите удобный способ установки: Установите Adapty SDK через Unity Package Manager с помощью Git URL: 1. В Unity откройте **Window → Package Manager**. 2. Нажмите **+** в верхнем левом углу и выберите **Add package from git URL...**. 3. Введите следующий URL и нажмите **Add**: ``` https://github.com/adaptyteam/AdaptySDK-Unity.git?path=Packages/com.adapty.unity-sdk#upm ``` Подробнее см. в руководстве Unity по [установке UPM-пакета из Git URL](https://docs.unity3d.com/Manual/upm-ui-giturl.html). Скачайте [`adapty-unity-plugin-*.unitypackage`](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Releases) с GitHub и импортируйте его в свой проект. После установки SDK выполните следующие шаги: 1. Установите [плагин External Dependency Manager (EDM)](https://github.com/googlesamples/unity-jar-resolver#getting-started). SDK использует его для управления зависимостями iOS Cocoapods и Android gradle. 2. После установки EDM может потребоваться запустить менеджер зависимостей: `Assets -> External Dependency Manager -> Android Resolver -> Force Resolve` и `Assets -> External Dependency Manager -> iOS Resolver -> Install Cocoapods` 3. При сборке Unity-проекта для iOS вы получите файл `Unity-iPhone.xcworkspace`, который необходимо открывать вместо `Unity-iPhone.xcodeproj`, иначе зависимости Cocoapods не будут использоваться. ## Активация модуля Adapty в SDK \{#activate-adapty-module-of-adapty-sdk\} Активируйте Adapty SDK в коде вашего приложения. :::note SDK Adapty нужно активировать только один раз в приложении. ::: Чтобы получить **Public SDK Key**: 1. Откройте дашборд Adapty и перейдите в [**App settings → General**](https://app.adapty.io/settings/general). 2. В разделе **Api keys** скопируйте **Public SDK Key** (НЕ Secret Key). 3. Замените `"YOUR_PUBLIC_SDK_KEY"` в коде. Или получите его программно с помощью [Adapty CLI](developer-cli): ``` npm install -g adapty adapty auth login adapty apps list ``` Или напрямую: ``` npx adapty auth login adapty apps list ``` - Убедитесь, что для инициализации Adapty вы используете **Public SDK key** — **Secret key** предназначен только для [серверного API](getting-started-with-server-side-api). - **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"); 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) { } } ``` :::important Дождитесь коллбэка завершения `Activate` перед вызовом любых других методов SDK. Полная последовательность описана в разделе [Порядок вызовов в Unity SDK](unity-sdk-call-order). ::: ## Настройка прослушивания событий \{#set-up-event-listening\} Создайте скрипт для прослушивания событий Adapty. Назовите его `AdaptyListener` в вашей сцене. Рекомендуем использовать метод `DontDestroyOnLoad` для этого объекта, чтобы он сохранялся на протяжении всего жизненного цикла приложения. 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` убедитесь, что корневой тег `` включает tools: ```xml ... ``` #### 2. Переопределите атрибуты резервного копирования в `` В том же файле `AndroidManifest.xml` обновите тег ``, чтобы ваше приложение предоставляло итоговые значения и указывало механизму слияния манифестов заменять значения библиотек: ```xml ... ``` Если какой-либо SDK также задаёт `android:allowBackup`, включите его в `tools:replace`: ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. Создайте объединённые файлы правил резервного копирования Создайте XML-файлы в директории `res/xml/` вашего Android-проекта, объединяющие правила Adapty с правилами других SDK. Android использует разные форматы правил резервного копирования в зависимости от версии ОС, поэтому создание обоих файлов обеспечивает совместимость со всеми версиями Android, которые поддерживает ваше приложение. :::note В примерах ниже в качестве стороннего SDK используется AppsFlyer. Замените или добавьте правила для других SDK, которые используются в вашем приложении. ::: **Для Android 12 и выше** (используется новый формат правил извлечения данных): ```xml title="sample_data_extraction_rules.xml" ``` **Для Android 11 и ниже** (используется устаревший формат полного резервного копирования): ```xml title="sample_backup_rules.xml" :::important В Unity применяйте эти изменения в `Assets/Plugins/Android/AndroidManifest.xml` и создавайте файлы правил резервного копирования в `Assets/Plugins/Android/res/xml/`. ::: #### Покупки завершаются с ошибкой после возврата из другого приложения в Android \{#purchases-fail-after-returning-from-another-app-in-android\} Если Activity, запускающий флоу покупки, использует нестандартный `launchMode`, Android может пересоздать или повторно использовать его некорректно при возврате пользователя из Google Play, банковского приложения или браузера. В результате результат покупки может быть потерян или расценён как отменённый. Чтобы покупки работали корректно, используйте для Activity, запускающей флоу покупки, только режимы запуска `standard` или `singleTop` — остальные режимы не поддерживаются. В файле `AndroidManifest.xml` убедитесь, что Activity, запускающая флоу покупки, настроена на `standard` или `singleTop`: ```xml ``` #### Приложение падает при отображении пейвола на Android \{#app-crashes-when-a-paywall-is-displayed-on-android\} Если приложение падает на Android при отображении пейвола, возможно, в конфигурации Gradle отсутствует плагин Kotlin. Чтобы добавить его: 1. В разделе **Player Settings** убедитесь, что выбраны опции **Custom Launcher Gradle Template** и **Custom Base Gradle Template**. 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-инструмента для написания кода." --- :::important Навык находится в бета-версии. Если он зависнет или поведёт себя неожиданно, воспользуйтесь [пошаговым руководством по интеграции](adapty-cursor-unity) — в нём описан каждый этап с нужной документацией. ::: [Скилл 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-unity --- --- title: "Интеграция Adapty в приложение Unity с помощью ИИ" description: "Пошаговый гайд по интеграции Adapty в приложение Unity с использованием Cursor, Context7, ChatGPT, Claude и других ИИ-инструментов." --- Этот гайд поможет вам шаг за шагом интегрировать Adapty в ваше Unity-приложение с помощью 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, если ваше Unity-приложение поддерживает обе платформы. Это обязательное условие для работы покупок. [Подключить сторы](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, мой placement 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 автоматически находит нужные доки на основе вашего запроса — никакого ручного копирования URL. 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 Unity SDK ``` :::warning Несмотря на то что Context7 избавляет от необходимости вручную вставлять ссылки на документацию, порядок реализации имеет значение. Следуйте [пошаговому руководству](#implementation-walkthrough) ниже строго по шагам, чтобы всё работало корректно. ::: ### Используйте документацию в формате обычного текста \{#use-plain-text-docs\} Любую статью Adapty можно получить в виде обычного текста Markdown. Для этого добавьте `.md` в конец её URL или нажмите **Copy for LLM** под заголовком статьи. Например: [adapty-cursor-unity.md](https://adapty.io/docs/ru/adapty-cursor-unity.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, созданные вручную**](unity-making-purchases): Вы строите собственный интерфейс пейвола в коде, но используете Adapty для получения продуктов и обработки покупок. - [**Observer mode**](observer-vs-full-mode): Вы сохраняете существующую инфраструктуру покупок и используете Adapty только для аналитики и интеграций. Не знаете, что выбрать? Прочитайте [таблицу сравнения в разделе быстрого старта](unity-quickstart-paywalls). ### Установка и настройка SDK \{#install-and-configure-the-sdk\} Добавьте пакет Adapty SDK через Unity Package Manager и активируйте его с помощью вашего публичного ключа SDK. Это основа — без неё ничего не работает. **Гайд:** [Установка и настройка Adapty SDK](sdk-installation-unity) Отправьте это в ваш LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ru/sdk-installation-unity.md ``` :::tip[Checkpoint] - **Ожидаемый результат:** Проект собирается и запускается. В консоли Unity отображается лог активации Adapty. - **Частая ошибка:** «Public API key is missing» → убедитесь, что вы заменили плейсхолдер на реальный ключ из **App settings**. ::: ### Показ пейволов и обработка покупок \{#show-paywalls-and-handle-purchases\} Получите пейвол по ID плейсмента, отобразите его и обработайте события покупки. Нужные вам гайды зависят от того, как вы обрабатываете покупки. Тестируйте каждую покупку в песочнице по мере работы — не откладывайте на конец. Инструкции по настройке см. в разделе [Тестирование покупок в песочнице](test-purchases-in-sandbox). **Гайды:** - [Включение покупок с помощью пейволов (быстрый старт)](unity-quickstart-paywalls) - [Получение пейволов Paywall Builder и их конфигурации](unity-get-pb-paywalls) - [Отображение пейволов](unity-present-paywalls) - [Обработка событий пейвола](unity-handling-events) - [Реакция на действия кнопок](unity-handle-paywall-actions) Отправьте это своему LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ru/unity-quickstart-paywalls.md - https://adapty.io/docs/ru/unity-get-pb-paywalls.md - https://adapty.io/docs/ru/unity-present-paywalls.md - https://adapty.io/docs/ru/unity-handling-events.md - https://adapty.io/docs/ru/unity-handle-paywall-actions.md ``` :::tip[Checkpoint] - **Ожидается:** Пейвол отображается с вашими настроенными продуктами. Нажатие на продукт запускает диалог покупки в песочнице. - **Проблема:** Пустой пейвол или ошибка `GetPaywall` → проверьте, что ID плейсмента точно совпадает с указанным в дашборде и что плейсменту назначена аудитория. ::: **Гайды:** - [Включите покупки в своём кастомном пейволе (быстрый старт)](unity-quickstart-manual) - [Загрузите пейволы и продукты](fetch-paywalls-and-products-unity) - [Отобразите пейвол, созданный через Remote Config](present-remote-config-paywalls-unity) - [Совершайте покупки](unity-making-purchases) - [Восстановите покупки](unity-restore-purchase) Read these Adapty docs before writing code: - https://adapty.io/docs/ru/unity-quickstart-manual.md - https://adapty.io/docs/ru/fetch-paywalls-and-products-unity.md - https://adapty.io/docs/ru/present-remote-config-paywalls-unity.md - https://adapty.io/docs/ru/unity-making-purchases.md - https://adapty.io/docs/ru/unity-restore-purchase.md :::tip[Checkpoint] - **Ожидаемый результат:** Ваш кастомный пейвол отображает продукты, полученные из Adapty. Нажатие на продукт открывает диалог покупки в песочнице. - **Возможная проблема:** Пустой массив продуктов → убедитесь, что в дашборде пейволу назначены продукты и у плейсмента есть аудитория. ::: **Гайды:** - [Обзор Observer mode](observer-vs-full-mode) - [Реализация Observer mode](implement-observer-mode-unity) - [Отправка транзакций в Observer mode](report-transactions-observer-mode-unity) Отправьте это своей LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ru/observer-vs-full-mode.md - https://adapty.io/docs/ru/implement-observer-mode-unity.md - https://adapty.io/docs/ru/report-transactions-observer-mode-unity.md ``` :::tip[Checkpoint] - **Ожидаемый результат:** После тестовой покупки в песочнице через ваш существующий флоу покупки транзакция появляется в **Event Feed** дашборда Adapty. - **Частая ошибка:** Нет событий → убедитесь, что вы передаёте транзакции в Adapty и серверные уведомления настроены для обоих сторов. ::: ### Проверка статуса подписки \{#check-subscription-status\} После покупки проверьте профиль пользователя на наличие активного уровня доступа, чтобы открыть доступ к премиум-контенту. **Гайд:** [Проверка статуса подписки](unity-check-subscription-status) Отправьте это в свой LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ru/unity-check-subscription-status.md ``` :::tip[Контрольная точка] - **Ожидаемый результат:** После покупки в песочнице `profile.AccessLevels["premium"]?.IsActive` возвращает `true`. - **Частая ошибка:** Пустой `AccessLevels` после покупки → проверьте, что продукту назначен уровень доступа в дашборде. ::: ### Идентификация пользователей \{#identify-users\} Привяжите аккаунты пользователей вашего приложения к профилям Adapty, чтобы покупки сохранялись на всех устройствах. :::important Пропустите этот шаг, если в вашем приложении нет аутентификации. ::: **Гайд:** [Идентификация пользователей](unity-quickstart-identify) Отправьте это в свой LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ru/unity-quickstart-identify.md ``` :::tip[Checkpoint] - **Ожидаемый результат:** После вызова `Adapty.Identify("your-user-id")` в разделе **Profiles** дашборда появится ваш пользовательский ID. - **Важно:** Вызывайте `Identify` после активации, но до загрузки пейволов, чтобы избежать анонимной атрибуции профиля. ::: ### Подготовка к релизу \{#prepare-for-release\} Когда интеграция заработает в песочнице, пройдитесь по чеклисту релиза и убедитесь, что всё готово к продакшену. **Гайд:** [Чеклист релиза](release-checklist) Отправьте это своему LLM: ``` Read these Adapty docs before releasing: - https://adapty.io/docs/ru/release-checklist.md ``` :::tip[Checkpoint] - **Ожидаемый результат:** Все пункты чеклиста подтверждены: подключения к сторам, серверные уведомления, флоу покупки, проверки уровней доступа и требования к конфиденциальности. - **Частая ошибка:** Отсутствие серверных уведомлений → настройте App Store Server Notifications в **App settings → iOS SDK** и Google Play Real-Time Developer Notifications в **App settings → Android SDK**. ::: ## Индексные файлы в виде обычного текста \{#plain-text-doc-index-files\} Если вы хотите дать вашему LLM более широкий контекст, выходящий за рамки отдельных страниц, мы предоставляем индексные файлы, которые перечисляют или объединяют всю документацию Adapty: - [`llms.txt`](https://adapty.io/docs/ru/llms.txt): Список всех страниц со ссылками в формате `.md`. [Формирующийся стандарт](https://llmstxt.org/) для обеспечения доступности сайтов языковым моделям. Обратите внимание: для некоторых AI-агентов (например, ChatGPT) потребуется скачать `llms.txt` и загрузить его в чат как файл. - [`llms-full.txt`](https://adapty.io/docs/ru/llms-full.txt): Вся документация Adapty, объединённая в один файл. Очень большой объём — используйте только тогда, когда нужна полная картина. - Специфичные для Unity файлы [`unity-llms.txt`](https://adapty.io/docs/ru/unity-llms.txt) и [`unity-llms-full.txt`](https://adapty.io/docs/ru/unity-llms-full.txt): Подмножества документации для конкретной платформы, позволяющие сэкономить токены по сравнению с полным сайтом. --- # File: unity-get-pb-paywalls --- --- title: "Получение пейволов Paywall Builder и их конфигурации в Unity SDK" description: "Узнайте, как получать пейволы PB в Adapty для более гибкого управления подписками в вашем приложении на Unity." --- После того как вы [разработали визуальную часть пейвола](adapty-paywall-builder) в новом Paywall Builder на дашборде Adapty, его можно отобразить в мобильном приложении. Первый шаг — получить пейвол, связанный с плейсментом, и его конфигурацию отображения, как описано ниже. :::warning Новый Paywall Builder работает с Unity SDK версии 3.3.0 и выше. ::: Пожалуйста, обратите внимание, что этот раздел относится к пейволам, настроенным через Paywall Builder. Если вы реализуете пейволы вручную, обратитесь к разделу [Получение пейволов и продуктов для пейволов с Remote Config в мобильном приложении](fetch-paywalls-and-products-unity). :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. :::
Прежде чем начать отображать пейволы в мобильном приложении (нажмите, чтобы развернуть) 1. [Создайте продукты](create-product) в дашборде Adapty. 2. [Создайте пейвол и добавьте в него продукты](create-paywall) в дашборде Adapty. 3. [Создайте плейсменты и добавьте в них пейвол](create-placement) в дашборде Adapty. 4. Установите [Adapty SDK](sdk-installation-unity) в своём мобильном приложении.
## Получение пейвола, созданного в Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\} Если вы [создали пейвол в Paywall Builder](adapty-paywall-builder), вам не нужно беспокоиться о его отображении в коде мобильного приложения — пейвол уже содержит всё необходимое: что и как должно быть показано. Тем не менее, вам нужно получить его ID через плейсмент, конфигурацию отображения, а затем показать пейвол в приложении. Для оптимальной производительности важно получать пейвол и его [конфигурацию отображения](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) как можно раньше, чтобы изображения успели загрузиться до того, как пользователь увидит пейвол. Чтобы получить пейвол, используйте метод `GetPaywall`: ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` Параметры: | Параметр | Наличие | Описание | |---------|--------|-----------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **locale** |

опциональный

по умолчанию: `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 { { "custom_image", AdaptyCustomAsset.LocalImageFile("custom_assets/images/custom_image.png") }, { "hero_video", AdaptyCustomAsset.LocalVideoFile("custom_assets/videos/custom_video.mp4") } }; var parameters = new AdaptyUICreatePaywallViewParameters() .SetCustomAssets(customAssets) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` :::note Если ресурс не найден, пейвол вернётся к внешнему виду по умолчанию. ::: ## Настройка таймеров, заданных разработчиком \{#set-up-developer-defined-timers\} Чтобы использовать кастомные таймеры в Unity-приложении, передайте словарь с ID таймеров и датами их окончания напрямую в метод `SetCustomTimers`. Пример: ```csharp showLineNumbers var customTimers = new Dictionary { { "CUSTOM_TIMER_6H", DateTime.Now.AddHours(6) }, { "CUSTOM_TIMER_NY", new DateTime(2025, 1, 1) } }; var parameters = new AdaptyUICreatePaywallViewParameters() .SetCustomTimers(customTimers) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` В этом примере `CUSTOM_TIMER_NY` и `CUSTOM_TIMER_6H` — это **Timer ID** таймеров, заданных разработчиком в дашборде Adapty. Резолвер таймеров обеспечивает динамическое обновление каждого таймера с правильным значением. Например: - `CUSTOM_TIMER_NY`: время, оставшееся до окончания таймера, например до Нового года. - `CUSTOM_TIMER_6H`: время, оставшееся в 6-часовом периоде, который начался, когда пользователь открыл пейвол. ## Ускорьте загрузку пейвола с помощью пейвола аудитории по умолчанию \{#speed-up-paywall-fetching-with-default-audience-paywall\} Как правило, пейволы загружаются почти мгновенно, и беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и пейволов, а пользователи работают в условиях слабого интернет-соединения, загрузка пейвола может занять больше времени, чем хотелось бы. В таких ситуациях стоит показывать пейвол по умолчанию — это обеспечит плавный пользовательский опыт вместо полного отсутствия пейвола. Чтобы решить эту задачу, вы можете использовать метод `GetPaywallForDefaultAudience`, который получает пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать пейвол с помощью метода `getPaywall`, как описано в разделе [Получение пейвола](#fetch-paywall) выше. :::warning Рекомендуем использовать `GetPaywall` вместо `GetPaywallForDefaultAudience`, так как последний имеет важные ограничения: - **Проблемы совместимости**: Могут возникнуть трудности при поддержке нескольких версий приложения — придётся либо делать обратно совместимые дизайны, либо мириться с тем, что старые версии будут отображать пейвол некорректно. - **Без персонализации**: Показывает контент только для аудитории «Все пользователи», исключая таргетинг по стране, атрибуции или кастомным атрибутам. Если более быстрая загрузка перевешивает эти недостатки для вашего случая, используйте `GetPaywallForDefaultAudience`, как показано ниже. В противном случае используйте `GetPaywall`, как описано [выше](#fetch-paywall). ::: ```csharp showLineNumbers Adapty.GetPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` Параметры: | Параметр | Наличие | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указали при создании плейсмента в дашборде Adapty. | | **locale** |

опциональный

по умолчанию: `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 ) { } ```
Пример события (нажмите, чтобы развернуть) ```javascript { "productId": "premium_monthly" } ```
#### Покупка начата \{#started-purchase\} Вызывается, когда пользователь инициирует процесс покупки. ```csharp showLineNumbers title="Unity" public void PaywallViewDidStartPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product ) { } ```
Пример события (нажмите, чтобы развернуть) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
#### Успешная, отменённая или ожидающая покупка \{#successful-canceled-or-pending-purchase\} Этот метод вызывается, если покупка прошла успешно, пользователь отменил покупку или покупка находится в состоянии ожидания. Отмены пользователем и ожидающие платежи (например, требующие родительского одобрения) вызывают этот метод, а не `PaywallViewDidFailPurchase`. ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult ) { } ```
Примеры событий (нажмите, чтобы развернуть) ```javascript // Successful purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } } } // Cancelled purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "UserCancelled" } } // Pending purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Pending" } } ```
В таких случаях рекомендуем закрывать экран. #### Покупка завершилась с ошибкой \{#failed-purchase\} Если покупка завершается с ошибкой, вызывается этот метод. Сюда входят ошибки StoreKit/Google Play Billing (ограничения платежей, недействительные продукты, сбои сети), ошибки проверки транзакций и системные ошибки. Обратите внимание: отмены пользователем вызывают `PaywallViewDidFinishPurchase` с результатом отмены, а ожидающие платежи этот метод не вызывают. ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error ) { } ```
Пример события (нажмите, чтобы развернуть) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } } } ```
#### Восстановление начато \{#started-restore\} Вызывается, когда пользователь инициирует процесс восстановления покупок: ```csharp showLineNumbers title="Unity" public void PaywallViewDidStartRestore(AdaptyUIPaywallView view) { } ``` #### Восстановление выполнено успешно \{#successful-restore\} Вызывается при успешном восстановлении покупок: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishRestore( AdaptyUIPaywallView view, AdaptyProfile profile ) { } ```
Пример события (нажмите, чтобы развернуть) ```javascript { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } ```
Рекомендуем закрывать экран, если у пользователя есть требуемый `accessLevel`. Подробнее о том, как это проверить, см. в разделе [Статус подписки](unity-listen-subscription-changes). #### Восстановление завершилось с ошибкой \{#failed-restore\} Вызывается при ошибке восстановления покупок: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailRestore( AdaptyUIPaywallView view, AdaptyError error ) { } ```
Пример события (нажмите, чтобы развернуть) ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ```
#### Завершена навигация к веб-оплате \{#finished-web-payment-navigation\} После попытки открыть [веб-пейвол](web-paywall) для покупки (успешной или неудачной) будет вызван этот метод: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishWebPaymentNavigation( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error ) { } ``` **Параметры:** - `product`: продукт, для которого был открыт (или предпринята попытка открыть) веб-пейвол - `error`: `null`, если веб-пейвол успешно открылся, или `AdaptyError` при ошибке
Примеры событий (нажмите, чтобы развернуть) ```javascript // Successful navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": null } // Failed navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "wrong_param", "message": "Current method is not available for this product", "details": { "underlyingError": "Product not configured for web purchases" } } } ```
### Загрузка данных и отрисовка \{#data-fetching-and-rendering\} #### Ошибки загрузки продуктов \{#product-loading-errors\} Вызывается при ошибке загрузки продуктов и предоставляет `AdaptyError`. Если при инициализации массив продуктов не был передан, AdaptyUI самостоятельно получит необходимые объекты с сервера. Эта операция может завершиться с ошибкой, о которой AdaptyUI сообщит, вызвав этот метод: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailLoadingProducts( AdaptyUIPaywallView view, AdaptyError error ) { } ```
Пример события (нажмите, чтобы развернуть) ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ```
#### Ошибки отрисовки \{#rendering-errors\} Вызывается при возникновении ошибки в процессе отрисовки интерфейса и предоставляет `AdaptyError`: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailRendering( AdaptyUIPaywallView view, AdaptyError error ) { } ```
Пример события (нажмите, чтобы развернуть) ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ```
В нормальных условиях такие ошибки не должны возникать, поэтому если вы с ними столкнётесь — пожалуйста, сообщите нам. --- # File: unity-web-paywalls --- --- title: "Реализация веб-пейволов в Unity SDK" description: "Настройте веб-пейвол, чтобы принимать платежи без комиссий и проверок App Store." --- :::important Прежде чем начать, убедитесь, что вы [настроили веб-пейвол в дашборде](web-paywall) и установили Adapty SDK версии 3.14 или выше. ::: ## Открытие веб-пейволов \{#open-web-paywalls\} Если вы работаете с пейволом, разработанным самостоятельно, для работы с веб-пейволами необходимо использовать метод SDK. Метод `Adapty.OpenWebPaywall`: 1. Генерирует уникальный URL, позволяющий Adapty связать конкретный показанный пейвол с конкретным пользователем и веб-страницей, на которую он перенаправляется. 2. Отслеживает возвращение пользователя в приложение, а затем с короткими интервалами вызывает `Adapty.GetProfile`, чтобы определить, обновились ли права доступа профиля. Таким образом, если платёж прошёл успешно и права доступа обновились, подписка активируется в приложении почти мгновенно. ```csharp showLineNumbers title="Unity" Adapty.OpenWebPaywall( product, (error) => { if (error != null) { Debug.LogError($"Failed to open web paywall: {error.Message}"); } else { Debug.Log("Web paywall opened successfully"); } } ); ``` :::note Существует две версии метода `OpenWebPaywall`: 1. `OpenWebPaywall(product)` — генерирует URL по пейволу и добавляет данные о продукте к URL. 2. `OpenWebPaywall(paywall)` — генерирует URL по пейволу без добавления данных о продукте к URL. Используйте её, когда продукты в пейволе Adapty отличаются от продуктов в веб-пейволе. ::: #### Обработка ошибок \{#handle-errors\} | Код ошибки | Описание | Рекомендуемые действия | |-----------|--------------------------------------------------------|---------------------------------------------------------------------------| | `AdaptyErrorCode.WrongParam` | У пейвола или продукта не настроен URL для веб-покупки, либо не удалось открыть URL в браузере | Проверьте сообщение об ошибке для получения подробностей. Убедитесь в правильности настройки пейвола/продукта в дашборде Adapty или проверьте настройки устройства. | | `AdaptyErrorCode.DecodingFailed` | Не удалось корректно закодировать параметры в URL | Убедитесь, что параметры URL корректны и правильно отформатированы | :::note Проверьте свойство `Message` ошибки, чтобы узнать подробности о причине сбоя: `WrongParam` может указывать на несколько разных проблем (отсутствующий URL покупки, ошибка открытия браузера и т. д.). ::: ## Открытие веб-пейволов во встроенном браузере \{#open-web-paywalls-in-an-in-app-browser\} :::important Открытие веб-пейволов во встроенном браузере поддерживается начиная с Adapty SDK v3.15. ::: По умолчанию веб-пейволы открываются во внешнем браузере, что уводит пользователей из вашего приложения. Для более комфортного пользовательского опыта можно открывать веб-пейволы во встроенном браузере. Это позволяет отображать страницу покупки прямо внутри приложения, так что пользователи завершают транзакцию, не переключаясь между приложениями. Чтобы включить эту возможность, передайте `AdaptyWebPresentation.InAppBrowser` в метод `OpenWebPaywall`: ```csharp showLineNumbers title="Unity" Adapty.OpenWebPaywall( product, AdaptyWebPresentation.InAppBrowser, // default — ExternalBrowser (error) => { if (error != null) { Debug.LogError($"Failed to open web paywall: {error.Message}"); } else { Debug.Log("Web paywall opened successfully"); } } ); ``` --- # File: unity-use-fallback-paywalls --- --- title: "Unity - Use fallback paywalls" description: "Обработка случаев, когда пользователи офлайн или серверы Adapty недоступны" --- :::warning Резервные пейволы поддерживаются начиная с Unity SDK v2.11. ::: Чтобы поддерживать бесперебойный пользовательский опыт, важно настроить [резервные пейволы](/fallback-paywalls) для флоу, [пейволов](paywalls) и [онбордингов](onboardings). Это позволит приложению продолжить работу при частичной или полной потере интернет-соединения. * **Если приложение не может обратиться к серверам Adapty:** Оно сможет отобразить резервный флоу или пейвол, а также использовать локальную конфигурацию онбординга. * **Если приложение не может подключиться к интернету:** Оно сможет отобразить резервный флоу или пейвол. Онбординги содержат удалённый контент и требуют интернет-соединения для работы. :::important Прежде чем следовать шагам этого гайда, [скачайте](/local-fallback-paywalls) файлы резервной конфигурации из Adapty. ::: ## Конфигурация \{#configuration\} 1. Добавьте файлы резервной конфигурации в общую директорию `Assets/StreamingAssets` вашего проекта. 2. Вызовите метод `.setFallback` **до** того, как запрашиваете целевой пейвол или онбординг. ```csharp using UnityEngine; using AdaptySDK; #if UNITY_IOS string fileName = "ios_fallback.json"; #elif UNITY_ANDROID string fileName = "android_fallback.json"; #else // Optional: handle Editor or other platforms string fileName = "fallback.json"; #endif Adapty.SetFallback(fileName, (error) => { if (error != null) { Debug.LogError($"Failed to set fallback: {error}"); return; } // Fallback set successfully }); ``` Параметры: | Параметр | Описание | |:-------------|:----------------------------------------------------------------------| | **fileName** | Строка с именем файла резервной конфигурации. | --- # File: unity-localizations-and-locale-codes --- --- title: "Использование локализаций и кодов языков в Unity SDK" description: "Узнайте, как локализовать пейволы в вашем Unity-приложении с помощью Adapty SDK." --- ## Почему это важно \{#why-this-is-important\} Коды языков (locale codes) задействованы в нескольких сценариях — например, когда вам нужно получить правильный пейвол для текущей локализации приложения. Коды языков могут быть сложными и различаться от платформы к платформе, поэтому мы используем внутренний стандарт для всех поддерживаемых платформ. Однако из-за этой сложности важно понимать, что именно вы отправляете на наш сервер для получения нужной локализации и что происходит дальше — чтобы всегда получать ожидаемый результат. ## Стандарт кодов языков в Adapty \{#locale-code-standard-at-adapty\} Adapty использует немного модифицированный стандарт [BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag): каждый код состоит из подтегов в нижнем регистре, разделённых дефисами. Например: `en` (английский), `pt-br` (португальский (Бразилия)), `zh` (упрощённый китайский), `zh-hant` (традиционный китайский). ## Сопоставление кодов языков \{#locale-code-matching\} Когда Adapty получает запрос от клиентского SDK с кодом языка и начинает поиск соответствующей локализации пейвола, происходит следующее: 1. Входящая строка с кодом языка приводится к нижнему регистру, а все символы подчёркивания (`_`) заменяются дефисами (`-`). 2. Выполняется поиск локализации с полным совпадением кода языка. 3. Если совпадение не найдено, берётся подстрока до первого дефиса (`pt` для `pt-br`) и снова выполняется поиск. 4. Если совпадение снова не найдено, возвращается локализация по умолчанию — `en`. Таким образом, устройство на iOS, отправившее `'pt_BR'`, устройство на Android, отправившее `pt-BR`, и другое устройство, отправившее `pt-br`, получат одинаковый результат. ## Реализация локализаций: рекомендуемый способ \{#implementing-localizations-recommended-way\} Если вы занимаетесь локализациями, скорее всего, вы уже работаете с файлами локализованных строк в своём проекте. В этом случае мы рекомендуем добавить в каждый такой файл пару ключ-значение с нужным кодом языка для Adapty. Затем извлекайте значение этого ключа при обращении к нашему SDK вот так: ```csharp showLineNumbers // 1. Modify your localization files (e.g., using Unity's Localization package) /* en.json */ { "adapty_paywalls_locale": "en" } /* es.json */ { "adapty_paywalls_locale": "es" } /* pt-BR.json */ { "adapty_paywalls_locale": "pt-br" } // 2. Extract and use the locale code using UnityEngine; using UnityEngine.Localization; using UnityEngine.Localization.Settings; using AdaptySDK; public class PaywallManager : MonoBehaviour { public async void FetchPaywall() { // Get the current locale from Unity's Localization system var locale = LocalizationSettings.SelectedLocale; var localeCode = GetAdaptyLocaleCode(locale); // Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => { if (error != null) { // handle the error return; } // Use the paywall }); } private string GetAdaptyLocaleCode(Locale locale) { // Convert Unity locale to Adapty format var localeIdentifier = locale.Identifier.Code; return localeIdentifier.ToLower().Replace('_', '-'); } } ``` Такой подход даёт вам полный контроль над тем, какая локализация будет загружена для каждого пользователя вашего приложения. ## Реализация локализаций: альтернативный способ \{#implementing-localizations-the-other-way\} Похожего (но не идентичного) результата можно достичь без явного задания кодов языков для каждой локализации. Для этого нужно извлекать код языка из других объектов, которые предоставляет ваша платформа, например вот так: ```csharp showLineNumbers using UnityEngine; using System.Globalization; using AdaptySDK; public class PaywallManager : MonoBehaviour { public void FetchPaywall() { var localeCode = GetSystemLocaleCode(); // Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => { if (error != null) { // handle the error return; } // Use the paywall }); } private string GetSystemLocaleCode() { // Get the system's current culture var culture = CultureInfo.CurrentCulture; var languageCode = culture.TwoLetterISOLanguageName; var regionCode = culture.Name.Contains('-') ? culture.Name.Split('-')[1] : null; if (!string.IsNullOrEmpty(regionCode)) { return $"{languageCode}-{regionCode.ToLower()}"; } return languageCode; } } ``` Мы не рекомендуем этот подход по нескольким причинам: 1. На iOS предпочтительные языки и текущая локаль — это не одно и то же. Чтобы локализация определялась корректно, придётся либо положиться на логику Apple (которая работает автоматически при использовании рекомендованного подхода с файлами локализованных строк), либо воспроизвести её самостоятельно. 2. Сложно предсказать, что именно получит сервер Adapty. Например, на iOS устройство может вернуть локаль вида `ar_OM@numbers='latn'`, которая будет отправлена на сервер. В ответ вы получите не локализацию `ar-om`, которую ожидали, а `ar` — что, скорее всего, не то, что нужно. Если вы всё же решите использовать этот подход — убедитесь, что учли все актуальные сценарии использования. --- # File: unity-troubleshoot-paywall-builder --- --- title: "Устранение неполадок Paywall Builder в Unity SDK" description: "Устранение неполадок Paywall Builder в Unity SDK" --- Этот гайд поможет вам решить распространённые проблемы при использовании пейволов, созданных в Adapty Paywall Builder, в Unity SDK. ## Ошибка при получении конфигурации пейвола \{#getting-a-paywall-configuration-fails\} **Проблема**: Метод `CreateView` не может получить конфигурацию пейвола. **Причина**: Пейвол не включён для отображения на устройстве в Paywall Builder. **Решение**: Включите переключатель **Show on device** в Paywall Builder. ## Слишком большое число просмотров пейвола \{#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) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. :::
Прежде чем начать получать пейволы и продукты в мобильном приложении (нажмите, чтобы развернуть) 1. [Создайте продукты](create-product) в дашборде Adapty. 2. [Создайте пейвол и добавьте продукты в него](create-paywall) в дашборде Adapty. 3. [Создайте плейсменты и добавьте пейвол в плейсмент](create-placement) в дашборде Adapty. 4. [Установите Adapty SDK](sdk-installation-unity) в своё мобильное приложение.
## Получение информации о пейволе \{#fetch-paywall-information\} В Adapty [продукт](product) объединяет продукты из App Store и Google Play. Эти кросс-платформенные продукты встраиваются в пейволы, что позволяет показывать их в нужных плейсментах мобильного приложения. Чтобы отобразить продукты, нужно получить [пейвол](paywalls) из одного из ваших [плейсментов](placements) с помощью метода `getPaywall`. :::important **Не хардкодьте ID продуктов.** Единственный ID, который нужно хардкодить — это ID плейсмента. Пейволы настраиваются удалённо, поэтому количество продуктов и доступных офферов может меняться в любой момент. Приложение должно обрабатывать эти изменения динамически: если сегодня пейвол возвращает два продукта, а завтра три — отображайте все без изменений в коде. ::: ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` | Параметр | Наличие | Описание | |---------|--------|-----------| | **placementId** | обязательный | Идентификатор [плейсмента](placements). Это значение, которое вы указали при создании плейсмента в дашборде Adapty. | | **locale** |

опциональный

по умолчанию: `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`. Это список, который может содержать до двух фаз скидки: фазу бесплатного пробного периода и фазу вводной цены. Каждый объект фазы содержит следующие полезные свойства:
• `PaymentMode`: enum со значениями `AdaptyPaymentMode.FreeTrial`, `AdaptyPaymentMode.PayAsYouGo`, `AdaptyPaymentMode.PayUpFront` и `AdaptyPaymentMode.Unknown`. Бесплатные пробные периоды имеют тип `AdaptyPaymentMode.FreeTrial`.
• `Price`: цена со скидкой в числовом виде. Для бесплатных пробных периодов здесь будет `0`.
• `LocalizedNumberOfPeriods`: строка, локализованная по локали устройства, описывающая длительность предложения. Например, для трёхдневного пробного периода в этом поле будет `"3 days"`.
• `SubscriptionPeriod`: альтернативный способ получить детали периода предложения. Работает так же, как описано в предыдущем разделе.
• `LocalizedSubscriptionPeriod`: форматированный период подписки скидки для локали пользователя. | ## Ускорьте загрузку пейвола с помощью пейвола для аудитории по умолчанию \{#speed-up-paywall-fetching-with-default-audience-paywall\} Как правило, пейволы загружаются почти мгновенно, поэтому беспокоиться об ускорении этого процесса не нужно. Однако если у вас много аудиторий и пейволов, а пользователи работают при слабом интернет-соединении, загрузка пейвола может занять больше времени, чем хотелось бы. В таких случаях имеет смысл показывать пейвол по умолчанию, чтобы пользователь не оставался без пейвола вовсе. Чтобы решить эту проблему, можно воспользоваться методом `GetPaywallForDefaultAudience`, который получает пейвол указанного плейсмента для аудитории **All Users**. Однако важно понимать, что рекомендуемый подход — получать пейвол с помощью метода `getPaywall`, как описано в разделе [Получение пейвола](#fetch-paywall) выше. :::warning Рекомендуем использовать `GetPaywall` вместо `GetPaywallForDefaultAudience`, так как последний имеет существенные ограничения: - **Проблемы совместимости**: могут возникнуть при поддержке нескольких версий приложения — придётся либо делать обратно совместимые дизайны, либо мириться с тем, что старые версии будут отображаться некорректно. - **Отсутствие персонализации**: показывает контент только для аудитории «All Users», исключая таргетинг по стране, атрибуции или пользовательским атрибутам. Если быстрая загрузка важнее этих недостатков для вашего случая, используйте `GetPaywallForDefaultAudience`, как показано ниже. В противном случае используйте `GetPaywall`, как описано [выше](#fetch-paywall). ::: ```csharp showLineNumbers Adapty.GetPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` Параметры: | Параметр | Обязательность | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указываете при создании плейсмента в дашборде Adapty. | | **locale** |

необязательный

по умолчанию: `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\}
Об офферных кодах Офферные коды позволяют предоставлять скидки или бесплатные пробные периоды конкретным пользователям. В отличие от обычных офферов, которые применяются автоматически, офферные коды распространяются за пределами приложения — через email-рассылки, социальные сети или печатные материалы. Пользователи активируют их, вводя код в App Store, переходя по ссылке для активации или через диалог внутри приложения. Чтобы настроить офферные коды, откройте подписку в App Store Connect и перейдите в раздел **Offer Codes**. Вы можете создать [три вида](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes) офферных кодов: - **Free** — подписка бесплатна на заданный период, следующее продление — по полной цене. - **Pay as you go** — пользователь платит сниженную цену в каждом расчётном периоде на протяжении заданного срока, после чего подписка продлевается по полной цене. - **Pay up front** — пользователь единовременно платит сниженную цену за весь срок оффера, после чего подписка продлевается по полной цене. Добавлять офферные коды в Adapty не нужно. Apple помечает каждую транзакцию в период действия оффера категорией офферного кода. Это касается как первоначальной активации, так и всех последующих продлений со скидкой. Adapty обнаруживает метку и записывает каждую транзакцию с категорией оффера `offer_code`. Как только период оффера заканчивается и подписка продлевается по полной цене, метка исчезает. Вы можете фильтровать аналитику по типу оффера **Offer Code** в [дашборде Adapty](controls-filters-grouping-compare-proceeds). #### Устранение расхождений в выручке \{#revenue-discrepancy-troubleshooting\} Если транзакция по офферному коду отображается в Adapty по полной цене продукта вместо сниженной цены оффера, проверьте следующее в App Store Connect: - Для офферного кода настроены корректные цены для всех регионов, где пользователи могут его активировать. - Цена оффера задана для конкретной страны или региона пользователя. Apple передаёт региональную цену в транзакции. Если для оффера не настроена региональная цена, Apple может передать полную цену продукта. Вы можете фильтровать и проверять транзакции по офферным кодам в [дашборде Adapty](controls-filters-grouping-compare-proceeds) по фильтрам типа оффера **Offer Code** и **Offer Discount Type**. #### Устаревшие промокоды (deprecated) \{#legacy-promo-codes-deprecated\} :::warning Apple прекратила поддержку промокодов для встроенных покупок в марте 2026 года. Офферные коды заменяют их с расширенными возможностями: настраиваемые условия применения, сроки действия и до 1 миллиона кодов в квартал. Если вы ранее использовали промокоды для встроенных покупок, перейдите на офферные коды в App Store Connect. ::: Устаревшие промокоды (не более 100 на приложение на версию) предоставляли бесплатный доступ к подписке. В отличие от офферных кодов, Apple не включала информацию о скидке в транзакции по промокодам — в чеке указывалась полная цена продукта. В результате Adapty записывал эти транзакции по полной цене, что приводило к расхождениям в выручке между аналитикой Adapty и App Store Connect. Если вы видите исторические транзакции по полной цене, которые должны были быть бесплатными, скорее всего, они связаны с устаревшими промокодами. Поскольку эти коды больше не поддерживаются, перейдите на офферные коды для точного учёта выручки.
Чтобы отобразить экран активации кода в приложении: ```csharp showLineNumbers Adapty.PresentCodeRedemptionSheet((error) => { // handle the error }); ``` :::danger По нашим наблюдениям, экран активации промокода (Offer Code Redemption sheet) в некоторых приложениях работает нестабильно. Мы рекомендуем перенаправлять пользователя напрямую в App Store. Для этого нужно открыть URL следующего формата: `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: ## Управление предоплаченными планами (Android) \{#manage-prepaid-plans-android\} Если пользователи вашего приложения могут покупать [предоплаченные планы](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (например, невозобновляемую подписку на несколько месяцев), вы можете включить [отложенные транзакции](https://developer.android.com/google/play/billing/subscriptions#pending) для предоплаченных планов. ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetGoogleEnablePendingPrepaidPlans(true); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` --- # File: unity-restore-purchase --- --- title: "Восстановление покупок в мобильном приложении через Unity SDK" description: "Узнайте, как восстановить покупки в Adapty для обеспечения бесперебойного пользовательского опыта." --- Восстановление покупок на iOS и Android позволяет пользователям снова получить доступ к ранее купленному контенту — подпискам или встроенным покупкам — без повторного списания средств. Это особенно удобно, если пользователь удалил и переустановил приложение или перешёл на новое устройство и хочет вернуть доступ к ранее приобретённому контенту. :::note В пейволах, созданных с помощью [Paywall Builder](adapty-paywall-builder), покупки восстанавливаются автоматически — дополнительный код писать не нужно. Если вы используете Paywall Builder, этот шаг можно пропустить. ::: Чтобы восстановить покупку без использования [Paywall Builder](adapty-paywall-builder) для настройки пейвола, вызовите метод `.restorePurchases()`: ```csharp showLineNumbers Adapty.RestorePurchases((profile, error) => { if (error != null) { // handle the error return; } var accessLevel = profile.AccessLevels["YOUR_ACCESS_LEVEL"]; if (accessLevel != null && accessLevel.IsActive) { // restore access } }); ``` Параметры ответа: | Параметр | Описание | |---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |

Объект [`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." --- В Observer Mode SDK Adapty не может самостоятельно отслеживать покупки, совершённые через вашу существующую систему. Вам нужно передавать транзакции из вашего стора вручную. Важно настроить это **до** выпуска приложения, чтобы избежать ошибок в аналитике. Используйте `reportTransaction`, чтобы явно сообщать Adapty о каждой транзакции. :::warning **Не пропускайте отчёт о транзакциях!** Если вы не вызываете `ReportTransaction`, Adapty не распознает транзакцию: она не появится в аналитике и не будет отправлена в интеграции. ::: Если вы используете пейволы Adapty, передавайте `variationId` при отчёте о транзакции. Это связывает покупку с пейволом, который её инициировал, и обеспечивает точную аналитику пейволов. ```csharp showLineNumbers Adapty.ReportTransaction( "YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID", // optional (error) => { // handle the error }); ``` Параметры: | Параметр | Обязательность | Описание | | ------------- | -------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | обязательный |
  • Для iOS: идентификатор транзакции.
  • Для 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). |
В Observer Mode SDK Adapty не может самостоятельно отслеживать покупки, совершённые через вашу существующую систему. Вам нужно передавать транзакции из вашего стора вручную или восстанавливать их. Важно настроить это **до** выпуска приложения, чтобы избежать ошибок в аналитике. Используйте `reportTransaction` на обеих платформах, чтобы явно сообщать о каждой транзакции, а на Android дополнительно вызывайте `restorePurchases`, чтобы Adapty гарантированно её распознал. :::warning **Не пропускайте отчёт о транзакциях и восстановление покупок!** Если вы не вызываете эти методы, Adapty не распознает транзакцию: она не появится в аналитике и не будет отправлена в интеграции. ::: Если вы используете пейволы Adapty, передавайте `PAYWALL_VARIATION_ID` при отчёте о транзакции. Это связывает покупку с пейволом, который её инициировал, и обеспечивает точную аналитику пейволов. ```csharp showLineNumbers // every time when calling transasction.finish() #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 }); ``` Параметры: | Параметр | Обязательность | Описание | | ------------- | -------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | обязательный |
  • Для 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). |
**Отчёт о транзакциях** - Версии до 3.1.x автоматически отслеживают транзакции в App Store, поэтому ручная передача данных не требуется. - Версия 3.2 не поддерживает Observer Mode. **Отчёт о транзакциях** Используйте `restorePurchases`, чтобы сообщить Adapty о транзакции в Observer Mode, как описано на странице [Восстановление покупок в мобильном коде](unity-restore-purchase). :::warning **Не пропускайте отчёт о транзакциях!** Если вы не вызываете `restorePurchases`, Adapty не распознает транзакцию: она не появится в аналитике и не будет отправлена в интеграции. ::: **Привязка пейволов к транзакциям** SDK Adapty не может определить источник покупок, так как их обрабатываете вы сами. Поэтому, если вы планируете использовать пейволы и/или A/B-тесты в Observer Mode, вам нужно связать транзакцию из вашего стора с соответствующим пейволом в коде мобильного приложения. Важно сделать это правильно до выпуска приложения, иначе это приведёт к ошибкам в аналитике. ```csharp Adapty.SetVariationForTransaction("", "", (error) => { if(error != null) { // handle the error return; } // successful binding }); ``` | Параметр | Обязательность | Описание | | ------------- | -------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | обязательный |

Для 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). |
--- # File: unity-troubleshoot-purchases --- --- title: "Устранение проблем с покупками в Unity SDK" description: "Устранение проблем с покупками в Unity SDK" --- Этот гайд поможет решить распространённые проблемы при ручной реализации покупок в Unity 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 в режиме наблюдателя \{#adaptyerror-cantmakepayments-in-observer-mode\} **Проблема**: Вы получаете `AdaptyError.cantMakePayments` при использовании `makePurchase` в режиме наблюдателя. **Причина**: В режиме наблюдателя покупки должны обрабатываться на вашей стороне — использовать метод `makePurchase` от Adapty не следует. **Решение**: Если вы используете `makePurchase` для покупок, отключите режим наблюдателя. Нужно либо использовать `makePurchase`, либо обрабатывать покупки самостоятельно в режиме наблюдателя. Подробнее см. в разделе [Реализация режима наблюдателя](implement-observer-mode-unity). ## Ошибка 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` не найден. **Причина**: Как правило, это связано с проблемами при тестировании в песочнице. **Решение**: Создайте нового пользователя песочницы и попробуйте снова. Обычно это решает проблемы с обработчиком завершения покупки в песочнице. ## Другие проблемы \{#other-issues\} **Проблема**: Вы столкнулись с другими проблемами, связанными с покупками, которые не описаны выше. **Решение**: При необходимости обновите SDK до последней версии с помощью [гайдов по миграции](unity-sdk-migration-guides). Многие проблемы устранены в новых версиях SDK. --- # File: unity-identifying-users --- --- title: "Идентификация пользователей в Unity SDK" description: "Узнайте, как идентифицировать пользователей в вашем Unity-приложении с помощью Adapty SDK." --- Adapty создаёт внутренний ID профиля для каждого пользователя. Однако если у вас есть собственная система аутентификации, вам следует задать свой Customer User ID. Вы можете находить пользователей по Customer User ID в разделе [Профили](profiles-crm), а также использовать его в [серверном API](getting-started-with-server-side-api) — он будет передаваться во все интеграции. ### Указание идентификатора пользователя при конфигурации \{#setting-customer-user-id-on-configuration\} Если у вас есть ID пользователя в момент конфигурации, просто передайте его как параметр `customerUserId` в метод `.activate()`: ```csharp showLineNumbers using UnityEngine; using AdaptySDK; var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID"); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ### Задание customer user ID после инициализации \{#setting-customer-user-id-after-configuration\} Если при настройке SDK у вас не было ID пользователя, его можно задать позже в любой момент с помощью метода `.identify()`. Чаще всего этот метод используется после регистрации или авторизации, когда пользователь переходит из анонимного состояния в аутентифицированное. ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { if(error == null) { // successful identify } }); ``` Параметры запроса: - **Customer User ID** (обязательный): строковый идентификатор пользователя. :::warning Повторная отправка важных данных пользователя В некоторых случаях, например когда пользователь повторно входит в свой аккаунт, серверы Adapty уже располагают информацией об этом пользователе. В таких сценариях Adapty SDK автоматически переключится на работу с новым пользователем. Если вы передавали какие-либо данные анонимному пользователю — например, пользовательские атрибуты или атрибуцию из сторонних сетей — необходимо повторно отправить эти данные для идентифицированного пользователя. Также важно учитывать, что после идентификации пользователя следует заново запросить все пейволы и продукты, поскольку данные нового пользователя могут отличаться. ::: ### Выход и вход пользователя \{#logging-out-and-logging-in\} Вы можете выйти из аккаунта пользователя в любой момент, вызвав метод `.logout()`: ```csharp showLineNumbers Adapty.Logout((error) => { if(error == null) { // successful logout } }); ``` После этого можно снова войти, используя метод `.identify()`. ## Назначение `appAccountToken` (iOS) \{#assign-appaccounttoken-ios\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) — это **UUID**, который позволяет связать транзакции App Store с внутренним идентификатором пользователя. StoreKit привязывает этот токен к каждой транзакции, поэтому ваш бэкенд может сопоставить данные App Store с конкретными пользователями. Используйте стабильный UUID, сгенерированный для каждого пользователя, и применяйте его для одного и того же аккаунта на всех устройствах. Это гарантирует, что покупки и уведомления App Store будут правильно привязаны к нужному пользователю. Токен можно задать двумя способами — при активации SDK или при идентификации пользователя. :::important `appAccountToken` необходимо всегда передавать вместе с `customerUserId`. Если передать только токен, он не будет включён в транзакцию. ::: ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; using System; // During configuration: var appAccountToken = new Guid("YOUR_APP_ACCOUNT_TOKEN"); var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID", appAccountToken); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); // Or when identifying users Adapty.Identify("YOUR_USER_ID", appAccountToken, (error) => { if (error == null) { // successful identify } }); ``` ## Установка обфусцированных идентификаторов аккаунта (Android) \{#set-obfuscated-account-ids-android\} Google Play требует обфусцированные идентификаторы аккаунта в ряде случаев — для защиты конфиденциальности и безопасности пользователей. Эти идентификаторы позволяют Google Play отслеживать покупки, не раскрывая личные данные пользователей, что особенно важно для предотвращения мошенничества и аналитики. Они могут понадобиться, если приложение работает с чувствительными пользовательскими данными или если вы обязаны соблюдать определённые требования по конфиденциальности. Обфусцированные идентификаторы позволяют Google Play отслеживать покупки, не раскрывая реальные пользовательские идентификаторы. ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; // During configuration: var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID", null, "YOUR_OBFUSCATED_ACCOUNT_ID"); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); // Or when identifying users Adapty.Identify("YOUR_USER_ID", null, "YOUR_OBFUSCATED_ACCOUNT_ID", (error) => { if (error == null) { // successful identify } }); ``` ## Обнаружение пользователей на разных устройствах \{#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: unity-setting-user-attributes --- --- title: "Установка атрибутов пользователя в Unity SDK" description: "Узнайте, как обновлять атрибуты пользователя и данные профиля в приложении Unity с помощью Adapty SDK." --- Вы можете задавать пользователям приложения дополнительные атрибуты: email, номер телефона и т. д. Атрибуты можно использовать для создания пользовательских [сегментов](segments) или просто просматривать их в CRM. ### Установка атрибутов пользователя \{#setting-user-attributes\} Чтобы задать атрибуты пользователя, вызовите метод `.updateProfile()`: ```csharp showLineNumbers var builder = new Adapty.ProfileParameters.Builder() .SetFirstName("John") .SetLastName("Appleseed") .SetBirthday(new DateTime(1970, 1, 3)) .SetGender(ProfileGender.Female) .SetEmail("example@adapty.io"); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != nil) { // handle the error } }); ``` Обратите внимание: атрибуты, ранее установленные с помощью метода `updateProfile`, не сбрасываются. :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ### Список допустимых ключей \{#the-allowed-keys-list\} Допустимые ключи `` для `AdaptyProfileParameters.Builder` и соответствующие значения `` перечислены ниже: | Ключ | Значение | |---|-----| |

email

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), чтобы узнать, есть ли у пользователя активная подписка.
Перед тем как проверять статус подписки (нажмите, чтобы раскрыть) - Для iOS настройте [App Store Server Notifications](enable-app-store-server-notifications) - Для Android настройте [Real-time Developer Notifications (RTDN)](enable-real-time-developer-notifications-rtdn)
## Уровень доступа и объект AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Уровни доступа — это свойства объекта [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). Рекомендуем получать профиль при запуске приложения, например, когда вы [идентифицируете пользователя](unity-identifying-users#setting-customer-user-id-on-configuration), и обновлять его при любых изменениях. Так вы сможете использовать объект профиля, не запрашивая его каждый раз заново. Чтобы получать уведомления об обновлениях профиля, подпишитесь на изменения профиля, как описано в разделе [Отслеживание обновлений статуса подписки](#listening-for-subscription-status-updates) ниже. :::tip Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши [примеры приложений](sample-apps) — они демонстрируют полную настройку: отображение пейволов, совершение покупок и другие базовые функции. ::: ## Получение уровня доступа с сервера \{#retrieving-the-access-level-from-the-server\} Чтобы получить уровень доступа с сервера, используйте метод `.GetProfile()`: ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access }); ``` Параметры ответа: | Параметр | Описание | | --------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Profile |

Объект [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. Идентификатор в формате `` однозначно будет расценён как сбор персональных данных — как и использование email. Для режима для детей лучшая практика — применять рандомизированные или анонимизированные идентификаторы (например, хешированные ID или UUID, сгенерированные на устройстве), чтобы обеспечить соответствие требованиям. ## Включение режима для детей \{#enabling-kids-mode\} ### Изменения в дашборде Adapty \{#updates-in-the-adapty-dashboard\} В дашборде Adapty необходимо отключить сбор IP-адресов. Для этого перейдите в [App settings](https://app.adapty.io/settings/general) и нажмите **Disable IP address collection** в разделе **Collect users' IP address**. ### Изменения в коде мобильного приложения \{#updates-in-your-mobile-app-code\} Поддержка режима для детей в Unity появится в ближайшее время! Пока вы можете воспользоваться гайдами для нативных платформ: - [Режим для детей в iOS SDK](kids-mode) — настройка для iOS - [Режим для детей в Android SDK](kids-mode-android) — настройка для Android --- # File: unity-get-onboardings --- --- title: "Получение онбордингов в Unity SDK" description: "Узнайте, как получать онбординги в Adapty для Unity." --- После того как вы [создали визуальную часть онбординга](design-onboarding) с помощью билдера в дашборде Adapty, его можно отобразить в вашем Unity-приложении. Первый шаг — получить онбординг, связанный с плейсментом, и его конфигурацию отображения, как описано ниже. Прежде чем начать, убедитесь, что: 1. Установлен [Adapty Unity SDK](sdk-installation-unity) версии 3.14.0 или выше. 2. Вы [создали онбординг](create-onboarding). 3. Вы добавили онбординг в [плейсмент](placements). ## Получение онбординга и создание представления \{#fetch-onboarding-and-create-view\} Когда вы создаёте [онбординг](onboardings) с помощью нашего no-code билдера, он сохраняется как контейнер с конфигурацией, которую приложение должно получить и отобразить. Этот контейнер управляет всем процессом: какой контент отображается, как он представлен и как обрабатываются действия пользователя (например, ответы на тесты или ввод данных в формы). Контейнер также автоматически отслеживает аналитические события, поэтому отдельно реализовывать отслеживание просмотров не нужно. Для лучшей производительности загружайте конфигурацию онбординга заранее, чтобы изображения успели скачаться до показа пользователям. Чтобы получить онбординг, используйте метод `GetOnboarding`: ```csharp showLineNumbers Adapty.GetOnboarding("YOUR_PLACEMENT_ID", (onboarding, error) => { if (error != null) { // handle the error return; } // the requested onboarding }); ``` Параметры: | Параметр | Обязательность | Описание | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | обязательный | Идентификатор нужного [плейсмента](placements). Это значение вы указывали при создании плейсмента в дашборде Adapty. | | **locale** |

опциональный

по умолчанию: `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) } ```
Пример события (нажмите, чтобы развернуть) ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ```
## Закрытие онбординга \{#closing-onboarding\} Онбординг считается закрытым, когда пользователь нажимает кнопку с назначенным действием **Close**. :::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 } ```
Пример события (нажмите, чтобы раскрыть) ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
## Открытие пейвола \{#opening-a-paywall\} :::tip Обрабатывайте это событие, чтобы открыть пейвол внутри онбординга. Если вы хотите открыть пейвол после его закрытия, есть более простой способ — обработайте [`OnboardingViewOnCloseAction`](#closing-onboarding) и откройте пейвол, не опираясь на данные события. ::: Самый удобный подход — сделать ID действия равным ID плейсмента пейвола. Тогда после получения события `OnboardingViewOnPaywallAction` можно сразу использовать этот ID, чтобы получить и открыть нужный пейвол. Обратите внимание, что в iOS одновременно на экране может отображаться только одно представление (пейвол или онбординг). Если вы показываете пейвол поверх онбординга, вы не можете программно управлять онбордингом в фоне. Попытка закрыть онбординг закроет пейвол вместо него, и онбординг останется видимым. Чтобы избежать этого, всегда закрывайте представление онбординга перед показом пейвола. ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnPaywallAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string actionId ) { // Dismiss onboarding before presenting paywall view.Dismiss((dismissError) => { if (dismissError != null) { // handle the error return; } Adapty.GetPaywall(actionId, (paywall, error) => { if (error != null) { // handle the error return; } AdaptyUI.CreatePaywallView(paywall, (paywallView, createError) => { if (createError != null) { // handle the error return; } paywallView.Present((presentError) => { if (presentError != null) { // handle the error } }); }); }); }); } // ... other interface methods } ```
Пример события (нажмите, чтобы развернуть) ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ```
## Завершение загрузки онбординга \{#finishing-loading-onboarding\} Когда онбординг завершает загрузку, реализуйте метод `OnboardingViewDidFinishLoading`: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewDidFinishLoading( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta ) { // handle loading completion } // ... other interface methods } ```
Пример события (нажмите, чтобы развернуть) ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ```
## Отслеживание навигации \{#tracking-navigation\} Метод `OnboardingViewOnAnalyticsEvent` вызывается при возникновении различных аналитических событий в ходе флоу онбординга. Объект `analyticsEvent` может быть одного из следующих типов: |Тип | Описание | |------------|-------------| | `AdaptyOnboardingsAnalyticsEventOnboardingStarted` | Когда онбординг загружен | | `AdaptyOnboardingsAnalyticsEventScreenPresented` | Когда отображается любой экран | | `AdaptyOnboardingsAnalyticsEventScreenCompleted` | Когда экран завершён. Включает необязательный `ElementId` (идентификатор завершённого элемента) и необязательный `Reply` (ответ пользователя). Срабатывает, когда пользователь выполняет любое действие для выхода с экрана. | | `AdaptyOnboardingsAnalyticsEventSecondScreenPresented` | Когда отображается второй экран | | `AdaptyOnboardingsAnalyticsEventUserEmailCollected` | Срабатывает, когда email пользователя собирается через поле ввода | | `AdaptyOnboardingsAnalyticsEventOnboardingCompleted` | Срабатывает, когда пользователь достигает экрана с идентификатором `final`. Если вам нужно это событие, [назначьте идентификатор `final` последнему экрану](design-onboarding). | | `AdaptyOnboardingsAnalyticsEventUnknown` | Для любого нераспознанного типа события. Включает `Name` (название неизвестного события) и `meta` (дополнительные метаданные) | Каждое событие содержит мета-информацию (`meta`) со следующими полями: | Поле | Описание | |------------|-------------| | `OnboardingId` | Уникальный идентификатор онбординга | | `ScreenClientId` | Идентификатор текущего экрана | | `ScreenIndex` | Позиция текущего экрана в флоу | | `ScreensTotal` | Общее количество экранов в флоу | Пример использования аналитических событий для отслеживания: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnAnalyticsEvent( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, AdaptyOnboardingsAnalyticsEvent analyticsEvent ) { switch (analyticsEvent) { case AdaptyOnboardingsAnalyticsEventOnboardingStarted: // track onboarding start TrackEvent("onboarding_started", meta); break; case AdaptyOnboardingsAnalyticsEventScreenPresented: // track screen presentation TrackEvent("screen_presented", meta); break; case AdaptyOnboardingsAnalyticsEventScreenCompleted screenCompleted: // track screen completion with user response TrackEvent("screen_completed", meta, screenCompleted.ElementId, screenCompleted.Reply); break; case AdaptyOnboardingsAnalyticsEventOnboardingCompleted: // track successful onboarding completion TrackEvent("onboarding_completed", meta); break; case AdaptyOnboardingsAnalyticsEventUnknown unknownEvent: // handle unknown events TrackEvent(unknownEvent.Name, meta); break; // handle other cases as needed } } // ... other interface methods } ``` :::note Метод `TrackEvent` — это заглушка, которую нужно реализовать самостоятельно для отправки аналитики в выбранный вами сервис. :::
Примеры событий (нажмите, чтобы развернуть) ```javascript // onboardingStarted { "name": "onboarding_started", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } // screenPresented { "name": "screen_presented", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "interests_screen", "screen_index": 2, "total_screens": 4 } } // screenCompleted { "name": "screen_completed", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 }, "params": { "element_id": "profile_form", "reply": "success" } } // secondScreenPresented { "name": "second_screen_presented", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 } } // userEmailCollected { "name": "user_email_collected", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 } } // onboardingCompleted { "name": "onboarding_completed", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
--- # File: unity-onboarding-input --- --- title: "Обработка данных из онбординга в Unity SDK" description: "Сохраняйте и используйте данные из онбординга в вашем Unity-приложении с помощью Adapty SDK." --- Когда пользователи отвечают на вопрос викторины или вводят данные в поле ввода, вызывается метод `OnboardingViewOnStateUpdatedAction`. Вы можете сохранить или обработать тип поля в своём коде. Реализуйте метод `OnboardingViewOnStateUpdatedAction` в вашем классе: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string elementId, AdaptyOnboardingsStateUpdatedParams @params ) { switch (@params) { case AdaptyOnboardingsSelectParams selectParams: // handle single selection break; case AdaptyOnboardingsMultiSelectParams multiSelectParams: // handle multiple selections break; case AdaptyOnboardingsInputParams inputParams: // handle text input break; case AdaptyOnboardingsDatePickerParams datePickerParams: // handle date selection break; } } // ... other interface methods } ``` Параметры включают: | Параметр | Описание | |---|---| | `elementId` | Уникальный идентификатор элемента ввода. Используйте его, чтобы связать вопросы с ответами при их сохранении. | | `@params` | Объект с данными, введёнными пользователем. Может быть одного из следующих типов. | | `AdaptyOnboardingsSelectParams` | Одиночный выбор из вариантов. Содержит `Id`, `Value`, `Label` | | `AdaptyOnboardingsMultiSelectParams` | Множественный выбор из вариантов. Содержит список `Params` (каждый с `Id`, `Value`, `Label`)
• `input`: объект с `type`, `value`
• `datePicker`: объект с `day`, `month`, `year` | | `AdaptyOnboardingsInputParams` | Текстовое поле ввода. Содержит `Input`, который может быть `AdaptyOnboardingsTextInput`, `AdaptyOnboardingsEmailInput` или `AdaptyOnboardingsNumberInput` | | `AdaptyOnboardingsDatePickerParams` | Выбор даты. Содержит nullable-поля `Day`, `Month`, `Year` |
Примеры сохранённых данных (в вашей реализации могут отличаться) ```javascript // Example of a saved select action { "elementId": "preference_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "preferences_screen", "screenIndex": 1, "screensTotal": 3 }, "params": { "type": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" } } } // Example of a saved multi-select action { "elementId": "interests_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "screensTotal": 3 }, "params": { "type": "multiSelect", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ] } } // Example of a saved input action { "elementId": "name_input", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "input", "value": { "type": "text", "value": "John Doe" } } } // Example of a saved date picker action { "elementId": "birthday_picker", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "datePicker", "value": { "day": 15, "month": 6, "year": 1990 } } } ```
## Варианты использования \{#use-cases\} ### Обогащение профилей пользователей данными \{#enrich-user-profiles-with-data\} Если вы хотите сразу связать введённые данные с профилем пользователя и не спрашивать его дважды об одном и том же, [обновите профиль пользователя](unity-setting-user-attributes) с этими данными при обработке действия. Например, вы просите пользователей ввести имя в текстовое поле с ID `name` и хотите установить значение этого поля в качестве имени пользователя. Кроме того, вы просите их ввести email в поле `email`. В коде приложения это может выглядеть так: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string elementId, AdaptyOnboardingsStateUpdatedParams @params ) { if (@params is AdaptyOnboardingsInputParams inputParams) { var builder = new AdaptyProfileParameters.Builder(); switch (elementId) { case "name": if (inputParams.Input is AdaptyOnboardingsTextInput textInput) { builder.SetFirstName(textInput.Value); } break; case "email": if (inputParams.Input is AdaptyOnboardingsEmailInput emailInput) { builder.SetEmail(emailInput.Value); } break; } Adapty.UpdateProfile(builder.Build(), (error) => { if (error != null) { // handle the error } }); } } // ... other interface methods } ``` ### Кастомизация пейволов на основе ответов \{#customize-paywalls-based-on-answers\} С помощью викторин в онбординге вы также можете настраивать пейволы, которые показываются пользователям после его прохождения. Например, можно спросить пользователей об их опыте в спорте и показывать разные призывы к действию и продукты разным группам пользователей. 1. [Добавьте викторину](onboarding-quizzes) в конструктор онбординга и задайте значимые ID её вариантам ответов. 2. Обрабатывайте ответы викторины по их ID и [устанавливайте пользовательские атрибуты](unity-setting-user-attributes) для пользователей. ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string elementId, AdaptyOnboardingsStateUpdatedParams @params ) { if (@params is AdaptyOnboardingsSelectParams selectParams) { var builder = new AdaptyProfileParameters.Builder(); switch (elementId) { case "experience": // set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.SetCustomStringAttribute("experience", selectParams.Value); break; } Adapty.UpdateProfile(builder.Build(), (error) => { if (error != null) { // handle the error } }); } } // ... other interface methods } ``` 3. [Создайте сегменты](segments) для каждого значения пользовательского атрибута. 4. Создайте [плейсмент](placements) и добавьте [аудитории](audience) для каждого созданного сегмента. 5. [Отобразите пейвол](unity-paywalls) для плейсмента в коде приложения. Если в вашем онбординге есть кнопка, открывающая пейвол, реализуйте код пейвола как [реакцию на действие этой кнопки](unity-handling-onboarding-events#opening-a-paywall). --- # File: unity-sdk-call-order --- --- title: "Порядок вызовов в Unity SDK" description: "Избегайте потери premium-доступа, отсутствия атрибуции и периодических ошибок #2002, вызывая методы Adapty SDK в правильном порядке." --- `Adapty.Activate()` должен завершиться до вызова любого другого метода Adapty SDK. Пока не сработает callback завершения, SDK не имеет состояния. Любой вызов, сделанный до или параллельно с `Activate()`, завершится ошибкой [`#2002 notActivated`](unity-handle-errors#custom-network-codes). Если ваше приложение аутентифицирует пользователей и вы получаете customer user ID после запуска, вызовите `Adapty.Identify()` в этот момент. Не вызывайте методы, требующие действий пользователя, пока не сработает колбэк `Identify`. Вызовы, конкурирующие с ним, либо завершаются ошибкой [`#3006 profileWasChanged`](unity-handle-errors#custom-network-codes), либо применяются к анонимному профилю, созданному при активации. В таком случае атрибуция, MMP ID (например, `appsflyer_id`) и принадлежность установки не всегда переносятся на идентифицированный профиль. Если ваше приложение не аутентифицирует пользователей, пропустите `Identify` и продолжайте работу с анонимным профилем. MMP и аналитические SDK (AppsFlyer, Adjust, Branch, PostHog) подчиняются тому же правилу. Сначала инициализируйте их и дождитесь коллбэков с UID, а затем вызывайте `Adapty.Activate`. Иначе MMP ID попадёт в кратковременный анонимный профиль и не всегда переносится в идентифицированный. Подробнее об особенностях AppsFlyer см. в разделе [AppsFlyer](appsflyer). ## Правильный порядок \{#the-correct-order\} Ваш путь зависит от двух вещей: когда вы узнаёте customer user ID и используете ли вы MMP или аналитический SDK. - **Шаги 2 и 5**: Обязательны для каждого приложения. Активируйте SDK, затем вызывайте методы SDK. - **Шаги 1 и 3**: Нужны только если вы интегрируете MMP или аналитический SDK (AppsFlyer, Adjust, Branch, PostHog). - **Шаг 4**: Нужен только если ваше приложение аутентифицирует пользователей и получает customer user ID после запуска. Если у вас есть customer user ID при запуске приложения, передайте его напрямую в `Activate()` (шаг 2a). В этом случае анонимный профиль не создаётся, поэтому шаг 4 не нужен. | Шаг | Вызов | Когда | Примечания | |------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | Инициализируйте MMP или аналитический SDK (AppsFlyer, Adjust, PostHog, Branch) | При запуске приложения, первым делом | Дождитесь коллбэка с UID от MMP, например `getAppsFlyerId`. | | 2a | `Adapty.Activate(builder.Build(), ...)` с `SetCustomerUserId` на билдере | При запуске приложения, после шага 1, если у вас есть customer user ID | Рекомендуется. Анонимный профиль не создаётся. | | 2b | `Adapty.Activate(builder.Build(), ...)` без `SetCustomerUserId` | При запуске приложения, после шага 1, если customer user ID нет (или вы его не собираете) | Adapty создаёт анонимный профиль. | | 3 | `Adapty.SetIntegrationIdentifier(key, value, callback)` для каждого MMP | После шага 2, до любых вызовов, связанных с действиями пользователя | Обязательно, чтобы идентификаторы MMP попали в правильный профиль. | | 4 | `Adapty.Identify("YOUR_USER_ID", callback)` | После шага 3 (или шага 2, если MMP нет), до шага 5 — только на пути 2b с аутентификацией | Дождитесь коллбэка завершения. Параллельные вызовы во время `Identify` приводят к `#3006 profileWasChanged`. | | 5 | `GetPaywall`, `GetPaywallProducts`, `RestorePurchases`, `MakePurchase`, `UpdateAttribution`, `UpdateProfile` | После шага 4, если вы вызываете `Identify`; иначе после шага 3 (или шага 2, если MMP нет) | Этим вызовам нужен стабильный профиль. | :::important Пропуск этих шагов приведёт к потере уровня доступа у вернувшихся пользователей, отсутствию `appsflyer_id` в профилях и отображению пейволов для неправильной аудитории. ::: ## Установки через web2app и веб-воронки \{#web2app-and-web-funnel-installs\} Если пользователь совершает покупку через веб-чекаут (Stripe, Paddle) и затем устанавливает нативное приложение, первый вызов `Activate()` на устройстве создаёт новый анонимный профиль. Этот профиль не связан с веб-профилем. Если вы можете получить customer user ID до запуска приложения (из потока аутентификации или реферера установки) — передайте его напрямую в `Activate()`. В противном случае веб-покупка останется невидимой на устройстве до тех пор, пока вы не вызовете `Identify("YOUR_USER_ID")`, а затем `RestorePurchases`. Подробнее о метаданных, которые нужно передавать при каждом веб-чекауте, читайте здесь: - [Stripe](stripe) - [Paddle](paddle) --- # File: unity-optimize-paywall-fetching --- --- title: "Оптимизация загрузки пейволов в Unity SDK" description: "Надёжная загрузка пейволов Adapty: тайминг, кеширование и резервные варианты для Unity." --- Надёжная загрузка пейвола в Unity решает три задачи: быстрый рендеринг, возврат пейвола, нацеленного на нужную аудиторию, и корректная работа в резервном режиме при медленной сети. Правила ниже охватывают тайминг, кеширование и резервные паттерны для достижения этих целей. :::tip Правила предполагают, что `Adapty.Activate()` и `Adapty.Identify()` уже выполнены. См. [Порядок вызовов в Unity SDK](unity-sdk-call-order). ::: ## Правила и подводные камни \{#rules-and-pitfalls\} | Делайте так | Не делайте так | Почему | |---|---|---| | Загружайте тот плейсмент, который собираетесь показать. | Не загружайте все плейсменты одновременно при запуске. | Массовая предзагрузка блокирует главный поток и вызывает чёрный экран во время пика нагрузки. | | Вызывайте `GetPaywall` после того, как атрибуция успела разрешиться — например, через 1–2 секунды после `Activate` или после срабатывания `OnLoadLatestProfile`. | Не вызывайте `GetPaywall` в `Awake()`. | Атрибуция ещё не получена. Пейвол разрешается относительно аудитории по умолчанию и незаметно игнорирует сегменты и персонализацию ASA. | | Задайте `loadTimeout` и настройте [резервный пейвол](fallback-paywalls) для каждого плейсмента. | Не ждите ответа `GetPaywall` бесконечно. | Без таймаута пользователи с плохим соединением видят пустой экран, пока сеть не ответит — или просто закрывают приложение. | Подробнее о параметрах `fetchPolicy` и `loadTimeout` см. в [Получение пейволов и продуктов](fetch-paywalls-and-products-unity), а о выборе нужного плейсмента — в [Плейсменты](placements). ## Настройка для нестабильного соединения \{#tune-for-poor-connectivity\} Для рынков с постоянно плохим качеством связи (сельская местность, транспорт, регионы с проблемной маршрутизацией): - Устанавливайте `fetchPolicy` в `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` при каждом запросе, кроме самого первого. - Настройте [резервный пейвол](fallback-paywalls) для каждого плейсмента в дашборде Adapty. - Задайте `loadTimeout` в диапазоне 3–5 секунд и принимайте резервный пейвол при срабатывании таймаута. - Не блокируйте отображение пейвола ожиданием `GetProfile`. Вызывайте `GetPaywall` независимо, чтобы медленная загрузка профиля не задерживала интерфейс. --- # File: unity-test --- --- title: "Тестирование и релиз в Unity SDK" description: "Узнайте, как тестировать и публиковать приложение на Unity с помощью Adapty SDK." --- Если вы уже интегрировали Adapty SDK в своё Unity-приложение, следующий шаг — убедиться, что всё настроено правильно и покупки работают корректно на платформах iOS и Android. Это включает тестирование как самой интеграции SDK, так и реального процесса покупки в песочнице Apple и тестовой среде Google Play. ## Тестирование приложения \{#test-your-app\} Для полноценного тестирования встроенных покупок обратитесь к нашим платформенным гайдам: [Тестирование на iOS](test-purchases-in-sandbox) и [Тестирование на Android](testing-on-android). ## Подготовка к релизу \{#prepare-for-release\} Перед отправкой приложения в стор пройдитесь по [Чеклисту для релиза](release-checklist) и убедитесь, что: - Подключение к стору и серверные уведомления настроены - Покупки проходят и передаются в Adapty - Уровни доступа корректно выдаются и восстанавливаются - Выполнены требования к конфиденциальности и прохождению ревью --- # File: InvalidProductIdentifiers-unity --- --- title: "Исправление ошибки Code-1000 noProductIDsFound в Unity SDK" description: "Устраните ошибки неверных идентификаторов продуктов при управлении подписками в Adapty." --- Ошибка с кодом 1000 — `noProductIDsFound` — означает, что ни один из продуктов, запрошенных на пейволе, недоступен для покупки в App Store, хотя они там указаны. Иногда эта ошибка сопровождается предупреждением `InvalidProductIdentifiers`. Если предупреждение появляется без ошибки, просто проигнорируйте его. Если вы столкнулись с ошибкой `noProductIDsFound`, выполните следующие шаги для её устранения: ## Шаг 1. Проверьте Bundle ID \{#step-2-check-bundle-id\} 1. Откройте [App Store Connect](https://appstoreconnect.apple.com/apps). Выберите своё приложение и перейдите в раздел **General** → **App Information**. 2. Скопируйте **Bundle ID** в подразделе **General Information**. 3. Откройте вкладку [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) в верхнем меню Adapty и вставьте скопированное значение в поле **Bundle ID**. 4. Вернитесь на страницу **App information** в App Store Connect и скопируйте **Apple ID**. 5. На странице [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) в дашборде Adapty вставьте этот ID в поле **Apple app ID**. ## Шаг 2. Проверьте продукты \{#step-3-check-products\} 1. Перейдите в **App Store Connect** и откройте раздел [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) в левом меню. 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 data = new Dictionary(); - - data["network"] = attribution.Network; - data["campaign"] = attribution.Campaign; - data["adgroup"] = attribution.Adgroup; - data["creative"] = attribution.Creative; - - String attributionString = JsonUtility.ToJson(data); - Adapty.UpdateAttribution(attributionString, AttributionSource.Adjust, adid, (error) => { - // handle the error - }); + if (adid != null) { + Adapty.SetIntegrationIdentifier( + "adjust_device_id", + adid, + (error) => { + // handle the error + }); } }); Adjust.GetAttribution((attribution) => { Dictionary data = new Dictionary(); data["network"] = attribution.Network; data["campaign"] = attribution.Campaign; data["adgroup"] = attribution.Adgroup; data["creative"] = attribution.Creative; String attributionString = JsonUtility.ToJson(data); - Adapty.UpdateAttribution(attributionString, AttributionSource.Adjust, adid, (error) => { + Adapty.UpdateAttribution(attributionString, "adjust", (error) => { // handle the error }); }); ``` ### Amplitude Обновите код своего мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Настройка SDK для интеграции с Amplitude](amplitude#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetAmplitudeUserId("YOUR_AMPLITUDE_USER_ID"); - builder.SetAmplitudeDeviceId(amplitude.getDeviceId()); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + Adapty.SetIntegrationIdentifier( + "amplitude_user_id", + "YOUR_AMPLITUDE_USER_ID", + (error) => { + // handle the error + }); + Adapty.SetIntegrationIdentifier( + "amplitude_device_id", + amplitude.getDeviceId(), + (error) => { + // handle the error + }); ``` ### AppMetrica Обновите код мобильного приложения, как показано ниже. Полный пример кода можно найти в разделе [Настройка SDK для интеграции с AppMetrica](appmetrica#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - var deviceId = AppMetrica.GetDeviceId(); - if (deviceId != null { - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetAppmetricaProfileId("YOUR_ADAPTY_CUSTOMER_USER_ID"); - builder.SetAppmetricaDeviceId(deviceId); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); - } + var deviceId = AppMetrica.GetDeviceId(); + if (deviceId != null { + Adapty.SetIntegrationIdentifier( + "appmetrica_device_id", + deviceId, + (error) => { + // handle the error + }); + + Adapty.SetIntegrationIdentifier( + "appmetrica_profile_id", + "YOUR_ADAPTY_CUSTOMER_USER_ID", + (error) => { + // handle the error + }); + } ``` ### AppsFlyer Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Настройка SDK для интеграции с AppsFlyer](appsflyer#connect-your-app-to-appsflyer). ```diff showLineNumbers using AppsFlyerSDK; using AdaptySDK; // before SDK initialization AppsFlyer.getConversionData(this.name); // in your IAppsFlyerConversionData void onConversionDataSuccess(string conversionData) { // It's important to include the network user ID - string appsFlyerId = AppsFlyer.getAppsFlyerId(); - Adapty.UpdateAttribution(conversionData, AttributionSource.Appsflyer, appsFlyerId, (error) => { + string appsFlyerId = AppsFlyer.getAppsFlyerId(); + + Adapty.SetIntegrationIdentifier( + "appsflyer_id", + appsFlyerId, + (error) => { // handle the error }); + + Adapty.UpdateAttribution( + conversionData, + "appsflyer", + (error) => { + // handle the error + }); } ``` ### Branch Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [настройки SDK для интеграции Branch](branch#connect-your-app-to-branch). ```diff showLineNumbers using AdaptySDK; - class YourBranchImplementation { - func initializeBranch() { - Branch.getInstance().initSession(launchOptions: launchOptions) { (data, error) in - if let data { - Adapty.updateAttribution(data, source: .branch) - } - } - } - } + Branch.initSession(delegate(Dictionary parameters, string error) { + string attributionString = JsonUtility.ToJson(parameters); + + Adapty.UpdateAttribution( + attributionString, + "branch", + (error) => { + // handle the error + }); + }); ``` ### Firebase и Google Analytics \{#firebase-and-google-analytics\} Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Настройка SDK для интеграции с Firebase и Google Analytics](firebase-and-google-analytics). ```diff showLineNumbers // We suppose FirebaseAnalytics Unity Plugin is already installed using AdaptySDK; Firebase.Analytics .FirebaseAnalytics .GetAnalyticsInstanceIdAsync() .ContinueWithOnMainThread((task) => { if (!task.IsCompletedSuccessfully) { // handle error return; } var firebaseId = task.Result var builder = new Adapty.ProfileParameters.Builder(); - builder.SetFirebaseAppInstanceId(firebaseId); - - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error + Adapty.SetIntegrationIdentifier( + "firebase_app_instance_id", + firebaseId, + (error) => { + // handle the error }); }); ``` ### Mixpanel Обновите код мобильного приложения, как показано ниже. Полный пример кода можно найти в разделе [настройка SDK для интеграции с Mixpanel](mixpanel#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetMixpanelUserId(Mixpanel.DistinctId); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + var distinctId = Mixpanel.DistinctId; + if (distinctId != null) { + Adapty.SetIntegrationIdentifier( + "mixpanel_user_id", + distinctId, + (error) => { + // handle the error + }); + } ``` ### OneSignal Обновите код мобильного приложения, как показано ниже. Полный пример кода смотрите в разделе [Настройка SDK для интеграции с OneSignal](onesignal#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - using OneSignalSDK; - var pushUserId = OneSignal.Default.PushSubscriptionState.userId; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetOneSignalPlayerId(pushUserId); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + var distinctId = Mixpanel.DistinctId; + if (distinctId != null) { + Adapty.SetIntegrationIdentifier( + "mixpanel_user_id", + distinctId, + (error) => { + // handle the error + }); + } ``` ### Pushwoosh \{#pushwoosh\} Обновите код вашего мобильного приложения, как показано ниже. Полный пример кода см. в разделе [Настройка SDK для интеграции с Pushwoosh](pushwoosh#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetPushwooshHWID(Pushwoosh.Instance.HWID); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + Adapty.SetIntegrationIdentifier( + "pushwoosh_hwid", + Pushwoosh.Instance.HWID, + (error) => { + // handle the error + }); ``` ## Обновите реализацию режима Observer \{#update-observer-mode-implementation\} Обновите способ привязки пейволов к транзакциям. Раньше для назначения `variationId` использовался метод `setVariationId`. Теперь `variationId` можно передавать напрямую при регистрации транзакции через новый метод `reportTransaction`. Смотрите итоговый пример кода в разделе [Привязка пейволов к транзакциям покупки в режиме Observer](report-transactions-observer-mode-unity). ```diff showLineNumbers // every time when calling transaction.finish() - Adapty.SetVariationForTransaction("", "", (error) => { - if(error != null) { - // handle the error - return; - } - - // successful binding - }); + Adapty.ReportTransaction( + "YOUR_TRANSACTION_ID", + "PAYWALL_VARIATION_ID", // optional + (error) => { + // handle the error + }); ``` ## Обновление инициализации плагина Unity \{#update-the-unity-plugin-initialization\} Начиная с Adapty Unity SDK 3.3.0, при инициализации плагина необходимо явно вызывать метод `Activate`: ```csharp showLineNumbers Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` --- # File: migration-to-unity-sdk-v3 --- --- title: "Миграция Adapty Unity SDK на v3.0" description: "Мигрируйте на Adapty Unity SDK v3.0 для улучшенной производительности и новых функций монетизации." --- Adapty SDK v3.0 включает поддержку нового [Adapty Paywall Builder](adapty-paywall-builder) — обновлённой версии no-code инструмента для создания пейволов. Благодаря широким возможностям настройки и богатому набору дизайн-инструментов ваши пейволы станут максимально эффективными и прибыльными. ## Процесс обновления \{#upgrade-process\} Процесс обновления для Unity включает те же шаги, что и для других платформ: 1. Обновитесь до Adapty SDK v3.x 2. Перенесите существующие пейволы в новый Paywall Builder Подробные инструкции по миграции для Unity см. в [гайде по установке Unity SDK](sdk-installation-unity) и следуйте общим шагам миграции, описанным в основном руководстве по миграции. --- # File: unity-migration-guide --- --- title: "Гайд по миграции SDK" description: "Гайды по миграции для Unity Adapty SDK." --- ## Гайды по миграции \{#migration-guides\} ### [Гайд по миграции на Unity Adapty SDK 3.x](unity-sdk-migration-guides) Узнайте, как перейти со старых версий на Unity Adapty SDK 3.x. ## Что нового \{#whats-new\} ### Версия 3.x \{#version-3x\} - Улучшенное отображение пейволов - Улучшенная обработка ошибок - Улучшенная поддержка C# - Оптимизация производительности ### Версия 2.x \{#version-2x\} - Новые функции онбординга - Улучшенная аналитика - Улучшенный процесс покупки - Исправления ошибок и улучшение стабильности ## Критические изменения \{#breaking-changes\} ### Версия 3.x \{#version-3x-breaking\} - Обновлённый API наблюдателя - Изменённые методы отображения пейволов - Изменённая структура обработки ошибок ### Версия 2.x \{#version-2x-breaking\} - Обновлённый API онбординга - Изменённая структура профиля - Изменённый процесс покупки ## Чеклист миграции \{#migration-checklist\} При переходе на новую версию: - [ ] Изучите критические изменения - [ ] Обновите вызовы API - [ ] Протестируйте весь функционал - [ ] Обновите обработку ошибок - [ ] Проверьте отслеживание аналитики - [ ] Протестируйте на всех платформах --- # End of Documentation _Generated on: 2026-07-24T13:01:12.986Z_ _Successfully processed: 41/41 files_