Получение флоу и пейволов — Kotlin Multiplatform

Что возвращает getFlow
✦
Флоу Создаются в Flow & Paywall Builder — рендерятся нативно на устройстве, без WebView
✦
Пейволы старого Paywall Builder Весь контент, созданный в старом Paywall Builder

После того как вы разработали флоу, его можно отобразить в мобильном приложении. Первый шаг — получить флоу или пейвол, связанный с плейсментом, а также его конфигурацию отображения, как описано ниже.

Tip

Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши примеры приложений, которые демонстрируют полную настройку, включая отображение пейволов, совершение покупок и другую базовую функциональность.

Прежде чем начать

Вам понадобятся:

Получение флоу/пейвола

Если вы создали флоу или пейвол в конструкторе, вам не нужно думать о его отрисовке в коде мобильного приложения — всё, что должно отображаться и как именно, уже заложено внутри. Тем не менее вам нужно получить его ID через плейсмент, конфигурацию представления, а затем показать его в мобильном приложении.

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

Чтобы получить флоу или пейвол, используйте метод getFlow:


Adapty.getFlow(
    placementId = "YOUR_PLACEMENT_ID",
    fetchPolicy = AdaptyPaywallFetchPolicy.Default,
    loadTimeout = 5.seconds
).onSuccess { flow ->
    // запрошенный флоу/пейвол
}.onError { error ->
    // обработка ошибки
}

Параметры:

ПараметрНаличиеОписание
placementIdобязательныйИдентификатор нужного плейсмента. Это значение вы указали при создании плейсмента в дашборде Adapty.
fetchPolicyпо умолчанию: AdaptyPaywallFetchPolicy.Default

fetchPolicy определяет, какой слой SDK читает первым, а не то, может ли он использовать кэш. По умолчанию SDK обращается сначала к серверу и возвращает кэшированные данные, если запрос не удался. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают самые актуальные данные.

Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad — он меняет порядок на обратный: сначала читает кэш и обращается к серверу только тогда, когда кэш пуст. Пользователи могут не получить самые последние данные, зато загрузка будет быстрее вне зависимости от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.

Третья политика, AdaptyPaywallFetchPolicy.ReturnCacheDataIfNotExpiredElseLoad(maxAgeMillis), находится между двумя первыми: она читает кэш, пока его возраст меньше maxAgeMillis, и обращается к серверу, когда кэш устарел.

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

Adapty SDK хранит флоу и пейволы локально в двух слоях: регулярно обновляемый кэш, описанный выше, и резервные пейволы. Для ускорения загрузки используется CDN, а в случае его недоступности — отдельный резервный сервер. Эта система обеспечивает получение актуальных данных и надёжную работу даже при слабом интернет-соединении.

loadTimeoutпо умолчанию: 5 сек

Это значение ограничивает таймаут данного метода. Если таймаут истёк, будут возвращены кэшированные данные или локальный резервный пейвол.

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

Для Kotlin Multiplatform: вы можете создать Duration с помощью функций-расширений, например 5.seconds, где .seconds — из kotlin.time.Duration.Companion.seconds.

ПараметрОписание
FlowОбъект AdaptyFlow, содержащий плейсмент, идентификаторы (instanceIdentity, variationId), название, варианты пейвола (paywalls — список AdaptyFlowPaywall) и Remote Config (remoteConfigs — список с одной записью на каждую локаль). Чтобы получить продукты для предзагрузки, кастомного UI или программных проверок, вызовите getPaywallProducts(flow).

Получение конфигурации представления

После получения флоу или пейвола загрузите конфигурацию представления и создайте само представление за один шаг с помощью метода createFlowView. Отдельного флага для проверки нет: если плейсмент был создан в Flow & Paywall Builder (флоу) или в old Paywall Builder (пейвол), createFlowView возвращает представление, готовое к отображению. Если плейсмент является кастомным пейволом без интерфейса Builder, createFlowView возвращает AdaptyResult.Error — обработайте его как пейвол с Remote Config.

Important

Обязательно опубликуйте флоу. Флоу с неопубликованными изменениями имеет статус Dirty, и его плейсмент продолжает отдавать последнюю опубликованную версию.


AdaptyUI.createFlowView(
    flow = flow,
    loadTimeout = 5.seconds,
    preloadProducts = true
).onSuccess { view ->
    // use view
}.onError { error ->
    // the flow has no view configured, or view creation failed
}
ПараметрНаличиеОписание
flowобязательныйОбъект AdaptyFlow, полученный через Adapty.getFlow.
localeнеобязательныйИдентификатор локализации флоу для отображения — например, en или pt-br. Если не указан, представление отображается на en, или с локализацией флоу по умолчанию, если у флоу нет en. См. Локализации и коды локалей.
customLayoutId

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

по умолчанию: null

SDK 4.1+

Пользовательский ID макета, заданного в Flow Builder. Передайте его, чтобы отобразить конкретный макет вместо того, который SDK выбирает автоматически исходя из типа устройства и размера экрана. Если макет с таким ID не найден, флоу загружается без конфигурации представления.
loadTimeoutнеобязательныйОграничивает таймаут для этого метода. При достижении таймаута возвращаются кешированные данные или локальный резервный пейвол. Обратите внимание, что в редких случаях метод может завершиться с таймаутом немного позже указанного в loadTimeout значения, так как операция может включать несколько запросов под капотом. Вы можете использовать функции-расширения, например 5.seconds из kotlin.time.Duration.Companion.
preloadProductsнеобязательныйУстановите true для предварительной загрузки продуктов и повышения производительности. При включении продукты загружаются заранее, сокращая время, необходимое для отображения флоу или пейвола.
productPurchaseParamsнеобязательныйСловарь AdaptyProductIdentifier → AdaptyPurchaseParameters. Используйте для настройки параметров покупки, таких как персонализированные предложения или параметры обновления подписки для отдельных продуктов во флоу или пейволе.
Note

Если вы используете несколько языков, узнайте, как добавить локализацию флоу.

После загрузки отобразите флоу или пейвол.

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

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

Чтобы решить эту задачу, можно использовать метод getFlowForDefaultAudience, который получает флоу или пейвол указанного плейсмента для аудитории All Users. Однако важно понимать, что рекомендуемый подход — получать флоу или пейвол через метод getFlow, как описано в разделе Получение флоу/пейвола выше.

Warning

Почему мы рекомендуем использовать getFlow

Метод getFlowForDefaultAudience имеет ряд существенных недостатков:

  • Потенциальные проблемы обратной совместимости: если вам нужно показывать разные флоу для разных версий приложения (текущей и будущих), могут возникнуть сложности. Придётся либо разрабатывать флоу, совместимые с текущей (устаревшей) версией, либо смириться с тем, что пользователи этой версии могут столкнуться с проблемами при отображении флоу.
  • Потеря таргетинга: все пользователи будут видеть одинаковый флоу, настроенный для аудитории All Users, — это означает потерю персонализированного таргетинга (в том числе по странам, маркетинговой атрибуции или вашим собственным пользовательским атрибутам).

Если вы готовы принять эти ограничения ради более быстрой загрузки флоу или пейвола, используйте метод getFlowForDefaultAudience следующим образом. В противном случае используйте getFlow, описанный выше.


Adapty.getFlowForDefaultAudience(
    placementId = "YOUR_PLACEMENT_ID",
    fetchPolicy = AdaptyPaywallFetchPolicy.Default,
).onSuccess { flow ->
    // the requested flow
}.onError { error ->
    // handle the error
}
ПараметрНаличиеОписание
placementIdобязательныйИдентификатор плейсмента. Это значение вы указали при создании плейсмента в дашборде Adapty.
fetchPolicyпо умолчанию: AdaptyPaywallFetchPolicy.Default

fetchPolicy определяет, какой слой SDK читает первым, а не то, может ли он использовать кэш. По умолчанию SDK сначала обращается к серверу и возвращает кэшированные данные, если запрос не удался. Мы рекомендуем этот вариант, поскольку он гарантирует, что пользователи всегда получают актуальные данные.

Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad — он меняет порядок на обратный: сначала читается кэш, и только если он пуст, выполняется запрос к серверу. Пользователи могут не получить самые последние данные, но загрузка будет быстрее независимо от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.

Третья политика, AdaptyPaywallFetchPolicy.ReturnCacheDataIfNotExpiredElseLoad(maxAgeMillis), находится между двумя: она читает кэш, пока его возраст меньше maxAgeMillis, и обращается к серверу, когда кэш устарел.

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

Настройка ресурсов

Чтобы настроить изображения и видео во флоу или пейволе, используйте кастомные ресурсы.

Hero-изображения и видео имеют предопределённые идентификаторы: hero_image и hero_video. В бандле кастомных ресурсов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение.

Для остальных изображений и видео нужно задать кастомный идентификатор в дашборде Adapty.

Например, можно:

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

Вот пример того, как можно передавать кастомные ресурсы через map:

Info

SDK для Kotlin Multiplatform поддерживает только локальные ресурсы. Для удалённого контента необходимо скачать и закэшировать ресурсы локально, прежде чем использовать их в кастомных ресурсах.

// Import generated Res class for accessing resources

viewModelScope.launch {
    // Get URIs for bundled resources using Res.getUri()
    val heroImagePath = Res.getUri("files/images/hero_image.png")
    val demoVideoPath = Res.getUri("files/videos/demo_video.mp4")

    // Or read image as byte data
    val imageByteData = Res.readBytes("files/images/avatar.png")

    // Create custom assets map
    val customAssets: Map<String, AdaptyCustomAsset> = mapOf(
        // Load image from app resources (bundled with the app)
        // Files should be placed in commonMain/composeResources/files/
        "hero_image" to AdaptyCustomAsset.localImageResource(
            path = heroImagePath
        ),

        // Or use image byte data
        "avatar" to AdaptyCustomAsset.localImageData(
            data = imageByteData
        ),

        // Load video from app resources
        "demo_video" to AdaptyCustomAsset.localVideoResource(
            path = demoVideoPath
        ),

        // Or use a video file from device storage
        "intro_video" to AdaptyCustomAsset.localVideoFile(
            path = "/path/to/local/video.mp4"
        )
    )

    // Use custom assets when creating the flow view
    AdaptyUI.createFlowView(
        flow = flow,
        customAssets = customAssets
    ).onSuccess { view ->
        // Present the flow with custom assets
        view.present()
    }.onError { error ->
        // Handle the error - the flow will fall back to default appearance
    }
}
Note

Если ресурс не найден или не удаётся загрузить, флоу или пейвол вернётся к внешнему виду по умолчанию, настроенному в Builder.

После того как вы оформили визуальную часть пейвола с помощью старого Paywall Builder в дашборде Adapty, его можно отобразить в мобильном приложении. Первый шаг — получить пейвол, связанный с плейсментом, и конфигурацию его представления, как описано ниже.

Обратите внимание, что этот раздел посвящён пейволам, созданным с помощью Paywall Builder. Если вы реализуете пейволы вручную, обратитесь к разделу Получение пейволов и продуктов для пейволов с Remote Config в вашем мобильном приложении.

Tip

Хотите увидеть реальный пример интеграции Adapty SDK в мобильное приложение? Посмотрите наши примеры приложений, которые демонстрируют полную настройку, включая отображение пейволов, совершение покупок и другую базовую функциональность.

Прежде чем начать показывать пейволы в вашем мобильном приложении (нажмите, чтобы развернуть)
  1. Создайте продукты в дашборде Adapty.
  2. Создайте пейвол и добавьте в него продукты в дашборде Adapty.
  3. Создайте плейсменты и добавьте в них пейвол в дашборде Adapty.
  4. Установите SDK Adapty в своём мобильном приложении.

Получение пейвола, созданного в Paywall Builder

Если вы создали пейвол с помощью Paywall Builder, вам не нужно беспокоиться о его отрисовке в коде мобильного приложения. Такой пейвол содержит как то, что должно отображаться, так и то, как именно это должно выглядеть. Тем не менее вам нужно получить его ID через плейсмент, конфигурацию его отображения, а затем показать пейвол в мобильном приложении.

Для обеспечения оптимальной производительности важно получать пейвол и его конфигурацию отображения как можно раньше, чтобы у изображений было достаточно времени для загрузки перед показом пользователю.

Для получения пейвола используйте метод getPaywall:


Adapty.getPaywall(
    placementId = "YOUR_PLACEMENT_ID",
    locale = "en",
    fetchPolicy = AdaptyPaywallFetchPolicy.Default,
    loadTimeout = 5.seconds
).onSuccess { paywall ->
    // the requested paywall
}.onError { error ->
    // handle the error
}

Параметры:

ПараметрНаличиеОписание
placementIdобязательныйИдентификатор нужного плейсмента. Это значение вы указали при создании плейсмента в дашборде Adapty.
locale

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

по умолчанию: en

Идентификатор локализации пейвола. Ожидается языковой код, состоящий из одного или двух подтегов, разделённых знаком минус (-). Первый подтег обозначает язык, второй — регион.

Пример: en означает английский, pt-br — бразильский португальский.

Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе Локализации и коды локалей.

fetchPolicyпо умолчанию: AdaptyPaywallFetchPolicy.Default

fetchPolicy определяет, из какого слоя SDK читает данные в первую очередь, а не то, может ли он вообще использовать кеш. По умолчанию SDK сначала обращается к серверу и возвращает кешированные данные, если запрос не удался. Мы рекомендуем этот вариант, так как он гарантирует получение самых актуальных данных.

Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите вариант AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad — он меняет порядок на обратный: сначала читается кеш, и только если там ничего нет, выполняется запрос к серверу. Пользователи могут не получить самые последние данные, зато загрузка будет быстрее независимо от качества соединения. Кеш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы избежать лишних сетевых запросов.

Третья политика, AdaptyPaywallFetchPolicy.ReturnCacheDataIfNotExpiredElseLoad(maxAgeMillis), занимает промежуточное положение: сначала читается кеш, пока его возраст меньше maxAgeMillis, а после этого порога выполняется запрос к серверу.

Обратите внимание: кеш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.

Adapty SDK хранит пейволы локально в двух слоях: регулярно обновляемый кеш, описанный выше, и резервные пейволы. Для более быстрой загрузки пейволов мы также используем CDN и отдельный резервный сервер на случай недоступности CDN. Эта система обеспечивает получение актуальной версии пейволов при сохранении надёжности даже при нестабильном интернет-соединении.

loadTimeoutпо умолчанию: 5 сек

Это значение ограничивает таймаут метода. При его истечении будут возвращены кешированные данные или локальный резервный вариант.

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

Для Kotlin Multiplatform: можно создать TimeInterval с помощью функций-расширений (например, 5.seconds, где .seconds из import com.adapty.utils.seconds) или TimeInterval.seconds(5). Чтобы убрать ограничение, используйте TimeInterval.INFINITE.

Параметры ответа:

ПараметрОписание
PaywallОбъект AdaptyPaywall со списком идентификаторов продуктов, идентификатором пейвола, Remote Config и рядом других свойств.

Получение конфигурации отображения пейвола, созданного в Paywall Builder

Important

Убедитесь, что в Paywall Builder включён тумблер Show on device. Если эта опция отключена, конфигурация отображения будет недоступна для получения.

После получения пейвола проверьте, содержит ли он ViewConfiguration — это указывает на то, что он был создан с помощью Paywall Builder. Это поможет вам определить, как отображать пейвол. Если ViewConfiguration присутствует, обрабатывайте его как пейвол Paywall Builder; если нет, обработайте его как пейвол с Remote Config.

Используйте метод createPaywallView, чтобы загрузить конфигурацию отображения.


if (paywall.hasViewConfiguration) {
    AdaptyUI.createPaywallView(
        paywall = paywall,
        loadTimeout = 5.seconds,
        preloadProducts = true
    ).onSuccess { paywallView ->
        // use paywallView
    }.onError { error ->
        // handle the error
    }
} else {
    // use your custom logic
}
ParameterPresenceDescription
paywallrequiredОбъект AdaptyPaywall для получения контроллера нужного пейвола.
loadTimeoutoptionalОграничивает таймаут для этого метода. Если таймаут истекает, возвращаются кешированные данные или локальный резервный вариант. Обратите внимание, что в редких случаях метод может завершиться чуть позже указанного в loadTimeout значения, поскольку операция может состоять из нескольких запросов. Можно использовать функции-расширения, например 5.seconds из kotlin.time.Duration.Companion.
preloadProductsoptionalУстановите true, чтобы заранее загрузить продукты для повышения производительности. При включении продукты загружаются заблаговременно, сокращая время отображения пейвола.
productPurchaseParamsoptionalСловарь, сопоставляющий AdaptyProductIdentifier с AdaptyPurchaseParameters. Используйте его для настройки параметров покупки — например, персонализированных офферов или параметров обновления подписки для отдельных продуктов пейвола.
Note

Если вы поддерживаете несколько языков, добавьте локализацию в ваш пейвол. Коды для использования см. в разделе Локализации и коды локалей.

После загрузки отобразите пейвол.

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

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

Чтобы решить эту проблему, используйте метод getPaywallForDefaultAudience, который загружает пейвол указанного плейсмента для аудитории All Users. Однако важно понимать, что рекомендуемый подход — загружать пейвол с помощью метода getPaywall, как описано в разделе Получение информации о пейволе выше.

Warning

Почему мы рекомендуем использовать getPaywall

Метод getPaywallForDefaultAudience имеет ряд существенных недостатков:

  • Возможные проблемы с обратной совместимостью: если вам нужно показывать разные пейволы для разных версий приложения (текущей и будущих), могут возникнуть сложности. Придётся либо проектировать пейволы с поддержкой текущей (устаревшей) версии, либо смириться с тем, что пользователи этой версии могут столкнуться с проблемами — пейволы не будут отображаться.
  • Потеря таргетинга: все пользователи будут видеть один и тот же пейвол, настроенный для аудитории All Users, — это означает отказ от персонализированного таргетинга (в том числе по странам, маркетинговой атрибуции или собственным пользовательским атрибутам).

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


Adapty.getPaywallForDefaultAudience(
    placementId = "YOUR_PLACEMENT_ID",
    locale = "en",
    fetchPolicy = AdaptyPaywallFetchPolicy.Default,
).onSuccess { paywall ->
    // the requested paywall
}.onError { error ->
    // handle the error
}
ПараметрНаличиеОписание
placementIdобязательныйИдентификатор плейсмента. Это значение вы указали при создании плейсмента в дашборде Adapty.
locale

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

по умолчанию: en

Идентификатор локализации пейвола. Ожидается, что этот параметр будет языковым кодом, состоящим из одного или нескольких подтегов, разделённых символом минус (-). Первый подтег обозначает язык, второй — регион.

Пример: en означает английский язык, pt-br — бразильский португальский.

Подробнее о кодах локалей и рекомендациях по их использованию см. в разделе Локализации и коды локалей.

fetchPolicyпо умолчанию: AdaptyPaywallFetchPolicy.Default

fetchPolicy определяет, какой источник данных SDK опрашивает первым, а не то, может ли он вообще использовать кэш. По умолчанию SDK сначала обращается к серверу и возвращает кэшированные данные только в случае неудачи. Мы рекомендуем этот вариант, так как он гарантирует, что пользователи всегда получают актуальные данные.

Однако если у ваших пользователей нестабильное интернет-соединение, рассмотрите AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad — эта политика работает в обратном порядке: сначала читает кэш и обращается к серверу только при его отсутствии. Пользователи могут не получить самые свежие данные, зато загрузка будет быстрее независимо от качества соединения. Кэш регулярно обновляется, поэтому его безопасно использовать в течение сессии, чтобы сократить количество сетевых запросов.

Третья политика, AdaptyPaywallFetchPolicy.ReturnCacheDataIfNotExpiredElseLoad(maxAgeMillis), занимает промежуточное положение: она читает кэш, пока его возраст не превышает maxAgeMillis, и обращается к серверу, как только кэш устаревает.

Обратите внимание: кэш сохраняется при перезапуске приложения и очищается только при его переустановке или вручную.

Настройка ресурсов

Чтобы настроить изображения и видео в пейволе, используйте пользовательские ресурсы.

Главные изображения и видео имеют предопределённые идентификаторы: hero_image и hero_video. В пользовательском наборе ресурсов вы обращаетесь к этим элементам по их идентификаторам и настраиваете их поведение.

Для других изображений и видео нужно задать пользовательский идентификатор в дашборде Adapty.

Например, вы можете:

  • Показывать разные изображения или видео разным пользователям.
  • Показывать локальное превью-изображение, пока загружается основное удалённое изображение.
  • Показывать превью-изображение перед воспроизведением видео.
Important

Чтобы использовать эту функцию, обновите SDK до версии 3.7.0 или выше.

Вот пример того, как можно передать пользовательские ресурсы через map:

Info

Kotlin Multiplatform SDK поддерживает только локальные ресурсы. Для удалённого контента необходимо заранее скачать и кэшировать ресурсы локально, прежде чем использовать их в качестве пользовательских ресурсов.

// Import generated Res class for accessing resources

viewModelScope.launch {
    // Get URIs for bundled resources using Res.getUri()
    val heroImagePath = Res.getUri("files/images/hero_image.png")
    val demoVideoPath = Res.getUri("files/videos/demo_video.mp4")

    // Or read image as byte data
    val imageByteData = Res.readBytes("files/images/avatar.png")

    // Create custom assets map
    val customAssets: Map<String, AdaptyCustomAsset> = mapOf(
        // Load image from app resources (bundled with the app)
        // Files should be placed in commonMain/composeResources/files/
        "hero_image" to AdaptyCustomAsset.localImageResource(
            path = heroImagePath
        ),

        // Or use image byte data
        "avatar" to AdaptyCustomAsset.localImageData(
            data = imageByteData
        ),

        // Load video from app resources
        "demo_video" to AdaptyCustomAsset.localVideoResource(
            path = demoVideoPath
        ),

        // Or use a video file from device storage
        "intro_video" to AdaptyCustomAsset.localVideoFile(
            path = "/path/to/local/video.mp4"
        ),

        // Apply custom brand colors
        "brand_primary" to AdaptyCustomAsset.color(
            colorHex = "#FF6B35"
        ),

        // Create gradient background
        "card_gradient" to AdaptyCustomAsset.linearGradient(
            colors = listOf("#1E3A8A", "#3B82F6", "#60A5FA"),
            stops = listOf(0.0f, 0.5f, 1.0f)
        )
    )

    // Use custom assets when creating paywall view
    AdaptyUI.createPaywallView(
        paywall = paywall,
        customAssets = customAssets
    ).onSuccess { paywallView ->
        // Present the paywall with custom assets
        paywallView.present()
    }.onError { error ->
        // Handle the error - paywall will fall back to default appearance
    }
}
Note

Если ресурс не найден или не загружается, пейвол вернётся к внешнему виду по умолчанию, настроенному в Paywall Builder.