Кампании и рекомендации в iOS

Сначала подключите SDK и опубликуйте кампанию в приложении. Навигация по URL/deeplink реализуется в приложении через callback.

In-App кампании

SDK автоматически показывает кампании с deliveryMethod:

  • fullScreen
  • modal
  • bottomSheet
  • snackBar

Что требуется для автопоказа:

  • подходящая активная кампания на backend;
  • корректный PageContext;
  • доступный UIViewController в момент показа после загрузки и задержки кампании;
  • заполненный variables.elements в ответе и снятая presentation lock. Блокировка новых in-app показов описана в Конфигурации.

Inline-компоненты

iOS SDK предоставляет компоненты для загрузки по selector и группе:

  • GravityInlineSwiftUIView — для SwiftUI-экранов;
  • GravityInlineView — для UIKit-экранов, включая ячейки UITableView;
  • GravityInlineListView — горизонтальный список блоков из группы кампаний для UIKit.

SwiftUI:

GravityInlineSwiftUIView(
    selector: "homepage-recommendations",
    pageContext: PageContext(
        type: .homepage,
        data: [],
        location: "app://homepage"
    )
)

UIKit:

let inlineView = GravityInlineView(selector: "homepage-recommendations")

inlineView.initialize(
    pageContext: PageContext(
        type: .homepage,
        data: [],
        location: "app://homepage"
    )
)

Что важно учесть:

  • selector должен совпадать с selector кампании на backend;
  • PageContext должен соответствовать таргетингу кампании;
  • если backend не вернул подходящий контент, компонент останется пустым;
  • для UIKit-компонента нужно корректно настроить constraints и вызвать initialize(pageContext:);
  • высота inline-блока может обновляться по frameUI.container.style.size.height, если это значение пришло с backend.

Оба одиночных компонента поддерживают loader:

GravityInlineSwiftUIView(selector: "homepage-recommendations", pageContext: pageContext) {
    ProgressView()
}

inlineView.initialize(pageContext: pageContext) {
    ProgressView()
}

Для группы кампаний:

let listView = GravityInlineListView(groupSelector: "homepage-group")
listView.initialize(pageContext: pageContext) {
    ProgressView()
}

У UIKit list-компонента высота берётся из максимального frameUI.container.style.size.height среди загруженных блоков. Если ни у одного блока высота не задана, SDK устанавливает 0; задайте размер в кампании.

После успешной загрузки эти компоненты сохраняют полученный контент. Изменение PageContext на том же экземпляре не гарантирует новый запрос: UIKit-компоненты прекращают загрузку, когда контент уже сохранён, а SwiftUI-компонент загружает его в onAppear. Для смены товара/контекста создайте новый UIKit view или измените identity SwiftUI view через .id(...). Публичных методов сброса inline-кэша, как в Android SDK, здесь нет.

Встроенный iOS рендерер отображает товарный контейнер только в layout row; для grid он возвращает EmptyView. Если нужна сетка, используйте собственный рендерер.

Карточки товаров

ProductViewBuilder нужен для отображения карточек товара в product-based или recommendation-блоках. Это обязательная часть интеграции товарных рекомендаций: приложение должно передать SDK шаблон карточки, иначе SDK не знает, какой UI использовать для товара в вашем приложении.

SDK получает блок рекомендаций, управляет контейнером, списком слотов и tracking-контекстом, но сам шаблон товарной карточки задает приложение. Разработчик реализует ProductViewBuilder или LegacyProductViewBuilder и передает его в GravitySDK.initialize(...) через параметр productViewBuilder.

После этого SDK использует переданный шаблон для каждого товара в блоке: вызывает builder для каждого slot и передает в него slot, content и campaign. Поэтому карточка отображается как native UI приложения, а не как готовая карточка, нарисованная SDK.

slot содержит данные одного рекомендованного товара:

  • slot.item - словарь с полями товара из фида или из запрошенных fields: например sku, name, price, old_price, image_url, url, brand, currency и другие кастомные поля;
  • slot.strId и slot.slotId - идентификаторы позиции товара в выдаче;
  • slot.fallback - признак, что товар пришел из fallback-логики;
  • slot.events - tracking-данные товара, которые SDK использует при отправке engagement.

Названия ключей в slot.item должны совпадать с вашим фидом и настройкой fields. Например, если в ответе приходит imageUrl, читайте imageUrl; если используется поле фида image_url, читайте image_url.

Сигнатуры протоколов — в справочнике API.

Пример шаблона карточки:

Полный пример: product_view_builder.swift. Реализуйте openProduct и передайте MyProductBuilder в initialize. Изображения через SwiftUI.AsyncImage доступны с iOS 15; для iOS 14 подключите свой загрузчик.

Что важно учесть:

  • ProductViewBuilder получает slot, content и campaign, поэтому карточка товара может учитывать контекст кампании и content block;
  • если в приложении уже есть UIKit-карточка товара, используйте LegacyProductViewBuilder и верните UIView из createView(...);
  • SDK автоматически отслеживает visible impression товара во встроенном блоке, а tap по кастомной карточке приложение отправляет вручную через sendProductEngagement(...) перед навигацией;
  • productFilter применяется к Products.slots при декодировании ответа SDK. Используйте его только для простого клиентского исключения слотов, когда это действительно нужно в приложении.

Кто отправляет engagement

Успешная загрузка автоматически отправляет content load tracking. Встроенные UI-компоненты отправляют показы контента, видимость товаров и tracking для поддерживаемых действий. Карточка из ProductViewBuilder уже обёрнута detector SDK: вручную отправляйте её клик перед навигацией, не дублируйте visible impression.

Ручные вызовы engagement не генерируют tracking callback. Для собственного UI используйте отдельные правила аналитики.

iOS учитывает не менее 50% площади в окне сразу, один раз на экземпляр detector.