Backend-Driven UI: рекомендации в iOS

Используйте этот сценарий, когда приложение само рисует виджет, а сервер управляет его структурой, стилем и подборкой товаров. Загрузите контент по selector, сохраните campaign/content/slot для engagement и передайте структуру собственному рендереру. Общие правила загрузки.

Структура виджета

Поле Как использовать
response.data[*].payload[*].contents[*] Выберите блок кампании, который будет отображаться
content.variables?.frameUI?.container Внешний контейнер: фон, скругление, padding, margin, size и onClick
content.variables?.elements Элементы в порядке, заданном сервером
products-container Место вставки товарного блока
element.style.productContainerType Layout row или grid
element.style.gridColumns Число колонок; если отсутствует, используйте дефолт клиента
content.products?.slots Товары в порядке ранжирования сервера
slot.item Поля товара из вашего фида

products.strategyId, products.name и products.fallback описывают выбранную стратегию. Сохраняйте порядок товаров и элементов; не подменяйте серверный заголовок или layout локальными значениями.

Поддерживаемые элементы

Элемент / действие Встроенный SDK Рендерер из примера
text, image, button, spacer Поддерживает Поддерживает
products-container, row/grid Поддерживает row через ProductViewBuilder; grid не отображается Рисует собственные карточки в row и grid
items-container, webview Поддерживает Требует дополнительной реализации
URL, deeplink, copy Поддерживает; навигация передаётся в callback Обрабатывает через переданные функции и clipboard
openStep Переключает шаг кампании Требует дополнительной реализации

Пример применяет backgroundColor, cornerRadius, padding, margin, size, fontSize, fontWeight, textColor, contentAlignment, src, fit и параметры товарного layout. Добавляйте новые элементы и действия явно; для неизвестных типов определите безопасный fallback. frameUI.container.onClick можно подключить к wrapper через тот же обработчик действий, что для element.onClick.

Подключите полный пример

Скачайте server_driven_widget.swift и добавьте файл в проект с SDK. Кампания для примера содержит один корневой блок без дополнительных шагов. Передайте обычное имя selector, PageContext и обработчики открытия URL, deeplink и товара.

SwiftUI-пример требует iOS 15, поскольку использует AsyncImage. Для iOS 14 замените загрузчик изображения. В этой среде проверен синтаксис Swift; полная сборка с iOS SDK требует Xcode.

ServerDrivenRecommendationWidget(
    selector: "homepage-recommendations",
    pageContext: pageContext,
    onOpenUrl: openUrl,
    onOpenDeeplink: openDeeplink,
    onOpenProduct: openProduct
)

Аналитика и ограничения

Пример вручную отправляет impression после появления виджета, visible impression — при видимости минимум 50% в течение секунды, клик товара — до навигации. Видимые показы дедуплицируются для размещения. Detector сравнивает геометрию с viewport и не учитывает перекрывающие слои.

Не передавайте decisionId или tracking URL отдельно: используйте campaign/content/slot из ответа. Ручной engagement не вызывает gravityEventCallback. Типы engagement и условия отправки.

Проверка

  1. Переключите row/grid, заголовок и порядок elements в кампании: после новой загрузки UI должен использовать серверную конфигурацию.
  2. Прокрутите виджет, нажмите товар и проверьте engagement без дублирования из callback.
  3. Проверьте пустой ответ, ошибку загрузки и отсутствующие поля: виджет должен безопасно скрыться.
  4. Не добавляйте неподдерживаемые элементы или дополнительные шаги без расширения рендерера.