A/B-тестирование интерфейса в Android

В этом сценарии сервер выбирает вариант кнопки перехода к оплате, а приложение рисует его по content.custom?.json. Сначала инициализируйте SDK. Методы выбора контента сами не показывают UI; ограничения автопоказа описаны в Своём UI и Custom JSON.

Для ручного учёта показа отключите неявный impression в Options после инициализации:

GravitySDK.instance.setOptions(
    options = Options(isImplicitImpression = false),
    contentSettings = null,
    proxyUrl = null,
)

Настройка глобальная. Если приложение уже задаёт ContentSettings или proxyUrl, передайте их здесь вместо null; остальные Options тоже сохраните явно. Проверьте tracking показов кампании по фактическому ответу сервера.

Подготовьте кампанию

  1. Создайте кампанию в приложении с двумя вариантами и нужным распределением аудитории для A/B-теста.
  2. Настройте кампанию с Custom JSON для selector checkout_button, контекстом CART и location app://cart. Для примера используйте один корневой content без дополнительных шагов (step отсутствует).
  3. В контрольном варианте задайте JSON:
{ "variant": "control", "label": "Перейти к оплате" }
  1. Во втором варианте задайте JSON:
{ "variant": "compact", "label": "Оформить заказ" }
  1. Опубликуйте кампанию. Названия variant и типы полей должны совпадать с моделями приложения. Настройте цель по бизнес-событию checkout-started-v1, которое отправляется при нажатии кнопки.

Приложение не распределяет аудиторию случайным образом: оно использует вариант из ответа сервера. Повторный выбор контента выполняйте при новом открытии размещения или явном обновлении, а не при каждом пересчёте UI.

Получите и проверьте вариант

Добавьте в проект gravity_content.kt и ab_example.kt. Первый файл загружает корневой content и проверяет JSON; второй показывает кнопку и отправляет engagement. Модель принимает только control и compact, непустой label и корректные типы полей.

val cartContext = PageContext(
    type = ContextType.CART,
    data = emptyList(),
    location = "app://cart",
)

CheckoutExperiment(
    pageContext = cartContext,
    activityContext = activity,
    onCheckout = ::openCheckout,
)

В Android helper принимает обычный selector и сам выполняет JSONObject.quote(...) один раз. Передавайте ему checkout_button без JSON-кавычек; почему это требуется.

Fallback

Если нет кампании, запрос завершился ошибкой, JSON повреждён, variant неизвестен или label пуст, показывайте стандартную кнопку приложения. Пример не связывает такой fallback с campaign/content и не отправляет ему impression выбранного варианта.

Не считайте fallback контрольной группой теста: контрольный вариант должен прийти из опубликованной кампании. Сбой выбора контента — отдельное состояние интеграции.

Учтите фактический показ

getContentBySelector автоматически отправляет content load tracking. Это не подтверждение показа кнопки. Пример отправляет ContentImpressionEngagement только после появления UI с успешно разобранным вариантом и сохраняет исходные campaign/content для аналитики.

Показ в примере означает появление компонента в UI, без проверки перекрывающих слоёв. Если нужно учитывать видимость в scroll-контейнере, реализуйте detector и отправляйте ContentVisibleImpressionEngagement по правилам собственного UI. Не отправляйте impression ещё раз из callback загрузки.

При нажатии кнопки отдельно отправляется CustomEvent типа checkout-started-v1 с текущим PageContext. Публичного ContentClickEngagement у native SDK нет. Результат теста оценивайте по выбранной бизнес-цели, а не по числу загрузок JSON.

Проверка

  1. Убедитесь, что оба серверных варианта отображаются с ожидаемым label и отступами.
  2. Проверьте пустой ответ, ошибку сети, неизвестный variant и некорректные типы JSON: стандартный UI должен работать.
  3. Проверьте, что загрузка не учитывается как ручной показ, а повторный пересчёт UI не создаёт новый выбор варианта.
  4. Проверьте бизнес-событие после нажатия и отсутствие impression кампании для fallback.