---
title: "Передача данных во флоу в iOS SDK"
description: "Передайте значение из iOS-приложения во флоу и отобразите его в текстовом элементе."
---

> **AI agents**: to search Adapty docs faster and with fewer tokens, install the Adapty skill. Claude Code (self-updating via plugin): `claude plugin marketplace add adaptyteam/adapty-skills && claude plugin install adapty-skills@adapty` — other tools: `npx skills add adaptyteam/adapty-skills --all`

[Пользовательский тег](flow-custom-tags) — это кастомная переменная, значение которой задаётся в вашем приложении. Если в настройках переменной выбрать **Value comes from outside the app**, приложение сможет передавать её значение через Adapty SDK. Например, текстовый элемент содержит «Coins:» и пользовательский тег. Если приложение передаёт «120» для этого тега, пользователь видит «Coins: 120».

## Прежде чем начать \{#before-you-start\}

Вам необходим Adapty SDK версии 4 или выше. Версии ниже v4 не отображают флоу.

## Добавление кастомных тегов во флоу \{#add-custom-tags-to-the-flow\}

Чтобы отображать значения из вашего приложения во флоу, настройте кастомные теги в билдере:

1. [Создайте кастомный тег](flow-custom-tags#create-a-custom-tag) для каждого значения, которое передаёт ваше приложение.

   <ZoomImage id="flow-custom-tag-create.webp" width="500px" alt="Форма создания переменной с именем, описанием, типом значения String и начальным значением" />

2. [Вставьте каждый тег в текстовый элемент](flow-custom-tags#add-a-custom-tag-to-a-text-element).
3. Запишите полное имя каждого тега, включая его группу. Именно под этим именем код вашего приложения передаёт каждое значение. Например, если группа `user` содержит тег `streak`, полное имя тега — `user.streak`.

   <ZoomImage id="flow-custom-tag-full-name.webp" width="500px" alt="Вкладка Custom в выпадающем списке Add variable с тегом streak в группе user" />

## Передача значений кастомных тегов \{#pass-custom-tag-values\}

Передайте значения вашего приложения в параметр `tagResolver` метода `getFlowConfiguration` в виде словаря `[String: String]`:

- Каждый ключ — это полное имя кастомного тега, например `user.streak`.
- Каждое значение — это строка, которую пользователи видят вместо тега.
- Каждое значение должно быть удобочитаемым, например "1 250", а не "1250.0". Adapty не форматирует и не переводит его.

```swift showLineNumbers title="Swift"
let customTags = [
    "username": "DragonSlayer42",
    "coins": "1,250",
]

do {
    let flowConfiguration = try await AdaptyUI.getFlowConfiguration(
        forFlow: flow,
        tagResolver: customTags
    )
    // present the flow
} catch {
    // handle the error
}
```

SwiftUI [модификатор `.flow` и `AdaptyFlowView`](ios-present-paywalls#present-flows-and-paywalls-in-swiftui), а также UIKit [контроллер флоу](ios-present-paywalls#present-flows-and-paywalls-in-uikit) не имеют параметра для пользовательских значений тегов. Они отображают значения из конфигурации флоу, которую вы им передаёте.

Чтобы протестировать пользовательские теги, откройте флоу в своём приложении после добавления кода, который устанавливает их значения. Холст конструктора и [предпросмотр на устройствах](paywall-device-compatibility-preview#preview-on-devices) отображают только начальные значения: мобильное приложение Adapty не устанавливает значения пользовательских тегов.

Если ваше приложение уже задаёт пользовательские значения тегов для пейволов старого Paywall Builder, ознакомьтесь с тем, [чем пользовательские теги во флоу отличаются](migrate-to-flows#custom-tags-from-the-old-paywall-builder).

## Что видят пользователи при отсутствии значения \{#what-users-see-without-a-value\}

Пользователи видят **Начальное значение** пользовательского тега как резервное в следующих случаях:

- Ваше приложение не передаёт никакого значения для тега.
- Пользователь не обновил приложение до версии, которая передаёт это значение.
- Имя в коде вашего приложения не совпадает с полным именем тега, включая регистр букв.
- Другой пользовательский тег в том же текстовом элементе не имеет значения. В этом случае каждый пользовательский тег в этом текстовом элементе показывает своё начальное значение.

Чтобы ничего не отображалось вместо тега, передайте пустую строку. Adapty считает пустую строку значением, поэтому резервный вариант не показывается.

## Пример: показ ИМТ по ответам из онбординга \{#example-show-a-bmi-from-onboarding-answers\}

Флоу может собирать ответы пользователей, а кастомный тег — показывать значение из вашего приложения. Объедините эти возможности, чтобы показывать пользователям результат, который приложение вычисляет на основе их ответов: оценку, рекомендованный план или метрику здоровья:

1. Флоу собирает ответы и передаёт их в ваше приложение.
2. Приложение вычисляет результат.
3. Приложение передаёт результат в следующий флоу в виде значения кастомного тега.

В этом примере онбординг-флоу собирает вес и рост пользователя. Когда пользователь закрывает онбординг-флоу после последнего экрана, приложение вычисляет индекс массы тела (ИМТ). Затем открывается пейвол-флоу, который показывает этот ИМТ.

### Настройка флоу \{#set-up-the-flows\}

1. [Создайте два флоу](paywall-builder-templates): онбординг-флоу, собирающий вес и рост пользователя, и флоу-пейвол, показывающий его ИМТ.
2. Добавьте два поля [**Number**](builder-inputs-and-forms) в онбординг-флоу:
   - Одно для веса в килограммах с **Element ID** `weight`.
   - Одно для роста в сантиметрах с **Element ID** `height`.

   Для обоих полей установите **Format** в значение **Integer**. Поле отправляет значение как текст, точно так, как его ввёл пользователь, а [пример кода](#pass-the-bmi-to-the-paywall) не воспринимает «70.5» и «70,5» одинаково. Целые числа не содержат разделителя дробной части, поэтому код читает их одинаково в любой локали.
3. Чтобы убедиться, что приложение получает оба значения, завершите онбординг-флоу экраном без полей ввода. На этом экране добавьте кнопку с действием [**Close flow**](onboarding-actions#close-flow). Поля отправляют свои значения при потере фокуса или при переходе пользователя на другой экран. Действие Close flow не отправляет их. Пример кода открывает пейвол только в том случае, если пользователь добрался до последнего экрана.
4. В флоу-пейволе [создайте кастомный тег](flow-custom-tags#create-a-custom-tag) с именем `bmi`. В поле **Initial value** введите тире (`—`). Пользователь увидит тире, если приложение не передало значение ИМТ.
5. Добавьте текстовый элемент со словами «Your BMI:» в флоу-пейвол. После этих слов [вставьте кастомный тег `bmi`](flow-custom-tags#add-a-custom-tag-to-a-text-element).
6. Добавьте онбординг-флоу в [плейсмент](placements), например `onboarding`. Добавьте флоу-пейвол в плейсмент с ID `bmi_paywall`. Код из раздела [Pass the BMI to the paywall](#pass-the-bmi-to-the-paywall) получает пейвол по этому ID.

### Передайте BMI на пейвол \{#pass-the-bmi-to-the-paywall\}

Соберите вес и рост пользователя из событий `flow_user_input` флоу онбординга, как описано в [Обработка данных из флоу](ios-flow-input). Чтобы определить, что пользователь дошёл до последнего экрана, отслеживайте событие `flow_screen_showed` с `is_last_screen` равным `true`, как описано в [Отслеживание просмотров экранов флоу](ios-flow-screen-views). Когда пользователь закрывает флоу онбординга после этого экрана, вычислите BMI. Затем загрузите конфигурацию флоу пейвола и передайте BMI для кастомного тега `bmi`.

Следующий код написан для UIKit. В нём реализованы методы `AdaptyFlowControllerDelegate` в одном контроллере представления, который является делегатом как контроллера флоу онбординга, так и контроллера пейвола. Контроллер представления также должен реализовывать методы делегата для покупки и восстановления — в этом примере они опущены. Чтобы их увидеть, перейдите в раздел [Отображение флоу и пейволов в UIKit](ios-present-paywalls#present-flows-and-paywalls-in-uikit).

```swift showLineNumbers title="Swift"
private var bodyAnswers: [String: String] = [:]
private var reachedLastScreen = false

func flowController(
    _ controller: AdaptyFlowController,
    didReceiveAnalyticEvent name: String,
    params: [String: any Sendable]
) {
    if name == "flow_screen_showed", params["is_last_screen"] as? Bool == true {
        reachedLastScreen = true
        return
    }
    guard name == "flow_user_input",
          let elementId = params["element_id"] as? String,
          let value = params["value"] as? String
    else { return }

    bodyAnswers[elementId] = value
}

func flowControllerDidDisappear(_ controller: AdaptyFlowController) {
    // This delegate receives events from both flows. Reset `bodyAnswers` and
    // `reachedLastScreen` whenever a flow disappears, so that the paywall
    // doesn't open again when the user closes it.
    let answers = bodyAnswers
    let finished = reachedLastScreen
    bodyAnswers.removeAll()
    reachedLastScreen = false

    // Number inputs send their values as strings.
    guard finished,
          let weight = answers["weight"].flatMap({ Double($0) }),
          let height = answers["height"].flatMap({ Double($0) }),
          height > 0
    else { return }

    let heightInMeters = height / 100
    let bmi = weight / (heightInMeters * heightInMeters)

    Task {
        await showBMIPaywall(bmi: bmi.formatted(.number.precision(.fractionLength(1))))
    }
}

func showBMIPaywall(bmi: String) async {
    do {
        let flow = try await Adapty.getFlow(placementId: "bmi_paywall")
        let flowConfiguration = try await AdaptyUI.getFlowConfiguration(
            forFlow: flow,
            tagResolver: ["bmi": bmi]
        )
        let flowController = try AdaptyUI.flowController(
            with: flowConfiguration,
            delegate: self
        )
        present(flowController, animated: true)
    } catch {
        // handle the error
    }
}
```

`formatted` использует десятичный разделитель из локали пользователя: "22.7" в английской, "22,7" в немецкой.

В SwiftUI используйте замыкания модификатора `.flow` онбординг-флоу вместо методов делегата:

- `didReceiveAnalyticEvent`: собирайте вес и рост, а также отслеживайте событие `flow_screen_showed` последнего экрана.
- `didDisappear`: если пользователь дошёл до последнего экрана, вычислите ИМТ. Затем получите конфигурацию флоу пейвола и передайте ИМТ в кастомный тег `bmi`. Отобразите эту конфигурацию с помощью второго модификатора `.flow`.

### Сохранение ИМТ в профиль пользователя \{#save-the-bmi-to-the-users-profile\}

Чтобы показывать пользователям разные флоу в зависимости от ИМТ, сохраните его как [пользовательский атрибут](setting-user-attributes#custom-user-attributes) профиля. В дашборде Adapty [создайте пользовательский атрибут типа **Number**](segments#custom-attributes) с ключом `bmi`. Затем покажите каждый флоу нужной [аудитории](audience), сформированной на основе этого атрибута.

Вызовите метод `updateProfile` внутри `flowControllerDidDisappear` — сразу после строки, где вычисляется `bmi`. Передавайте именно `Double`, а не форматированную строку, чтобы сегмент мог сравнивать ИМТ с пороговым значением:

```swift showLineNumbers title="Swift"
do {
    let params = try AdaptyProfileParameters.Builder()
        .with(customAttribute: bmi, forKey: "bmi")
        .build()
    try await Adapty.updateProfile(params: params)
} catch {
    // handle the error
}
```