Свой UI и Custom JSON в iOS

Используйте этот путь, когда приложение само рисует кампанию или рекомендации. SDK получает контент и отправляет content load tracking; видимость, клики и навигацию определяет приложение. Сначала выполните инициализацию.

getContentBySelector(selector:pageContext:)

Используйте этот метод для manual rendering и кастомного UI.

let response = await GravitySDK.instance.getContentBySelector(
    selector: "homepage-recommendations",
    pageContext: PageContext(
        type: .homepage,
        data: [],
        location: "app://homepage"
    )
)

if let response {
    // Разберите response.data и постройте собственный UI.
}

Для вызова требуется корректно заполненный PageContext.

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

  • успешный getContentBySelector(...) автоматически запускает content load tracking для всех contents, пришедших в response;
  • при сетевой ошибке или ошибке декодирования метод возвращает nil и пишет SDK-лог;
  • это означает, что ContentLoadEvent может прийти в gravityEventCallback сразу после загрузки контента, даже если UI еще не был показан пользователю;
  • impression / visible impression / click для manual widget SDK автоматически не отправляет: приложение по-прежнему должно вызвать sendContentEngagement(...) и sendProductEngagement(...) самостоятельно.

Загрузка по группе и ID кампании

Для группы и ID кампании используйте getContentByGroupSelector(...) и getContentByCampaignId(...): сигнатуры.

Методы загрузки по группе и ID кампании возвращают ту же структуру ContentResponse?, автоматически отправляют content load tracking и не показывают UI. Все методы выбора контента используют Options и ContentSettings, установленные через setOptions(...).

Custom JSON

Пользовательский JSON приходит в content.custom?.json как строка. SDK не декодирует её в модель приложения. Например, для кампании с JSON { "variant": "compact" }:

struct ExperimentConfig: Decodable {
    let variant: String
}

if let campaign = response?.data.first,
   let content = campaign.payload.first?.contents.first,
   let json = content.custom?.json,
   let data = json.data(using: .utf8) {
    do {
        let config = try JSONDecoder().decode(ExperimentConfig.self, from: data)
        // Покажите UI для config.variant. Для неизвестного значения используйте свой fallback.
    } catch {
        // Используйте стандартный UI приложения.
    }
}

Вариант A/B выбирает сервер; приложение использует полученный JSON и сохраняет исходные campaign/content для engagement. Полный сценарий A/B.

Отдельного параметра headless у native SDK нет. getContentBySelector(...) сам не показывает UI, но trackView(...) и triggerEvent(...) могут запустить автопоказ. Для сценария со своим UI используйте selector/Custom JSON кампании; presentation lock ограничивает новые in-app показы, но не отменяет HTTP-запросы и content load tracking.

Аналитика собственного UI

Загрузка не означает показ. Сохраните исходные campaign/content и при работе с товарами slot. Передавайте их в engagement после фактического взаимодействия:

Действие Тип engagement
Контент появился в интерфейсе ContentImpressionEngagement
Контент достиг порога видимости ContentVisibleImpressionEngagement
Контент закрыт ContentCloseEngagement
Карточка товара достигла порога видимости ProductVisibleImpressionEngagement
Пользователь нажал на товар ProductClickEngagement

Порог и дедупликацию реализует приложение. Встроенный iOS detector использует 50% площади без задержки; в полном примере собственного рендерера выбрано 50% в течение секунды.

Публичного ContentClickEngagement нет. sendContentEngagement/sendProductEngagement вызывают tracking URL, но не gravityEventCallback. Для бизнес-действий отправляйте TriggerEvent отдельно. Справочник engagement.