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

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

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

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

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

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

1. Создайте [кампанию в приложении](/personalization/Campaigns/app_campaigns/getting_started.md) с двумя вариантами и нужным распределением аудитории для A/B-теста.
2. Настройте кампанию с Custom JSON для selector `checkout_button`, контекстом `CART` и location `app://cart`. Для примера используйте один корневой content без дополнительных шагов (`step` отсутствует).
3. В контрольном варианте задайте JSON:

```json
{ "variant": "control", "label": "Перейти к оплате" }
```

4. Во втором варианте задайте JSON:

```json
{ "variant": "compact", "label": "Оформить заказ" }
```

5. Опубликуйте кампанию. Названия `variant` и типы полей должны совпадать с моделями приложения. Настройте цель по бизнес-событию `checkout-started-v1`, которое отправляется при нажатии кнопки.

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

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

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

```kotlin
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-кавычек; [почему это требуется](./custom_ui.md#формат-selector-в-android-104).

## Fallback

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

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

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

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

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

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

## Проверка

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