---
title: "Kotlin Multiplatform SDKでフローにデータを渡す"
description: "Kotlin Multiplatformアプリからフローに値を渡し、テキスト要素に表示する方法を説明します。"
---

> **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を通じてその値を設定できます。たとえば、テキスト要素に「コイン:」とカスタムタグが含まれていて、アプリがタグに「120」を渡すと、ユーザーには「コイン: 120」と表示されます。

## 始める前に \{#before-you-start\}

Adapty SDK v4 以降が必要です。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="streakタグがuserグループ内にある、変数追加ドロップダウンのカスタムタブ" />

## カスタムタグの値を渡す \{#pass-custom-tag-values\}

アプリの値を `AdaptyUI.createFlowView` または `createNativeFlowView` の `customTags` パラメータに `Map<String, String>` 形式で渡します。

- 各キーは `user.streak` のように、カスタムタグの完全な名前です。
- 各値は、タグの代わりにユーザーに表示される文字列です。
- 各値は「1,250」のように人が読める形式にしてください。「1250.0」は不可です。Adapty はフォーマットや翻訳を行いません。

SDK はビューの作成時に値を一度だけ読み込むため、フローが開いている間は値が変わりません。

<Tabs>
<TabItem value="standalone" label="With Compose Multiplatform" default>

```kotlin showLineNumbers title="Kotlin Multiplatform"

viewModelScope.launch {
    val customTags = mapOf(
        "username" to "DragonSlayer42",
        "coins" to "1,250",
    )

    AdaptyUI.createFlowView(
        flow = flow,
        customTags = customTags,
    ).onSuccess { view ->
        view.present()
    }.onError { error ->
        // handle the error
    }
}
```

Compose レイアウトにフローを埋め込むには、同じ `customTags` パラメータを `AdaptyUIFlowPlatformView` コンポーザブルに渡します。異なる `customTags` マップを渡すと、コンポーザブルは新しいビューを作成し、ユーザーはフローの最初の画面に戻ります。

</TabItem>
<TabItem value="native" label="Without Compose Multiplatform">

```kotlin showLineNumbers title="Kotlin Multiplatform (Android)"

val customTags = mapOf(
    "username" to "DragonSlayer42",
    "coins" to "1,250",
)

val nativeView = AdaptyUI.createNativeFlowView(
    context = context,
    viewModelStoreOwner = activity,
    flow = flow,
    observer = myFlowObserver,
    customTags = customTags,
)
```

```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)"

val customTags = mapOf(
    "username" to "DragonSlayer42",
    "coins" to "1,250",
)

val nativeView = AdaptyUI.createNativeFlowView(
    flow = flow,
    observer = myFlowObserver,
    customTags = customTags,
)
```

</TabItem>
</Tabs>

カスタムタグをテストするには、タグの値を設定するコードを追加した後、アプリでフローを開いてください。ビルダーのキャンバスおよび[デバイスでのプレビュー](paywall-device-compatibility-preview#preview-on-devices)には初期値のみが表示されます。Adapty モバイルアプリはカスタムタグの値を設定しません。

アプリがすでに旧ペイウォールビルダーのペイウォール向けにカスタムタグの値を設定している場合は、[フローにおけるカスタムタグの違い](migrate-to-flows#custom-tags-from-the-old-paywall-builder)を確認してください。

## 値がない場合にユーザーに表示されるもの \{#what-users-see-without-a-value\}

以下の場合、ユーザーにはカスタムタグの**初期値**がフォールバックとして表示されます。

- アプリがそのタグに値を渡していない場合。
- ユーザーがアプリを値を渡すバージョンにアップデートしていない場合。
- アプリのコード内の名前が、大文字・小文字を含めタグのフルネームと一致していない場合。
- 同じテキスト要素内の別のカスタムタグに値がない場合。その場合、そのテキスト要素内のすべてのカスタムタグが初期値を表示します。

タグの位置に何も表示しないようにするには、空の文字列を渡してください。Adapty は空の文字列を値として扱うため、フォールバックは表示されません。

## 例：オンボーディングの回答からBMIを表示する \{#example-show-a-bmi-from-onboarding-answers\}

フローはユーザーから回答を収集でき、カスタムタグはアプリの値を表示できます。この2つを組み合わせることで、スコア、おすすめプラン、健康指標など、回答からアプリが計算した結果をユーザーに表示できます：

1. フローが回答を収集し、アプリに送信します。
2. アプリが結果を計算します。
3. アプリが次のフローにカスタムタグの値として結果を渡します。

この例では、オンボーディングフローがユーザーの体重と身長を収集します。ユーザーがオンボーディングフローの最後の画面を閉じると、アプリがBMI（ボディマス指数）を計算します。そして、BMIを表示するペイウォールフローを開きます。

### フローを設定する \{#set-up-the-flows\}

1. [2つのフローを作成します](paywall-builder-templates): ユーザーの体重と身長を収集するオンボーディングフローと、BMIを表示するペイウォールフローです。
2. オンボーディングフローに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. ペイウォールフローで、`bmi`という名前の[カスタムタグを作成します](flow-custom-tags#create-a-custom-tag)。**Initial value**フィールドにダッシュ（`—`）を入力します。アプリがBMIを渡さない場合、ユーザーにはダッシュが表示されます。
5. ペイウォールフローに「Your BMI:」という文字列を含むテキスト要素を追加します。この文字列の後に、[`bmi`カスタムタグを挿入します](flow-custom-tags#add-a-custom-tag-to-a-text-element)。
6. オンボーディングフローを`onboarding`などの[プレースメント](placements)に追加します。ペイウォールフローをID `bmi_paywall`のプレースメントに追加します。[BMIをペイウォールに渡す](#pass-the-bmi-to-the-paywall)のコードは、このIDでペイウォールを取得します。

### ペイウォールにBMIを渡す \{#pass-the-bmi-to-the-paywall\}

オンボーディングフローの`flow_user_input`イベントから体重と身長を収集します。詳細は[フローからデータを処理する](kmp-flow-input)を参照してください。ユーザーが最後の画面に到達したことを確認するには、`is_last_screen`が`true`に設定された`flow_screen_showed`イベントを監視します。詳細は[フローの画面表示を追跡する](kmp-flow-screen-views)を参照してください。その画面の後にユーザーがオンボーディングフローを閉じたら、BMIを計算します。次にペイウォールのビューを作成し、`bmi`カスタムタグにBMIを渡します。

`flowViewDidReceiveAnalyticEvent`メソッドは、`kotlinx.serialization.json`ライブラリを使用してイベントパラメータを解析します。プロジェクトにこのライブラリがまだない場合は、アプリの依存関係に`org.jetbrains.kotlinx:kotlinx-serialization-json`を追加してください。次に、`AdaptyUI.setFlowsEventsObserver`で登録するオブザーバーに以下のメソッドを実装してください：

```kotlin showLineNumbers title="Kotlin Multiplatform"

class MyFlowsEventsObserver(
    private val scope: CoroutineScope,
) : AdaptyUIFlowsEventsObserver {

    private val bodyAnswers = mutableMapOf<String, String>()
    private var reachedLastScreen = false

    override fun flowViewDidReceiveAnalyticEvent(
        view: AdaptyUIFlowView,
        name: String,
        paramsJsonString: String,
    ) {
        if (name != "flow_user_input" && name != "flow_screen_showed") return

        val params = Json.parseToJsonElement(paramsJsonString).jsonObject
        if (name == "flow_screen_showed") {
            if (params["is_last_screen"]?.jsonPrimitive?.booleanOrNull == true) {
                reachedLastScreen = true
            }
            return
        }
        val elementId = params["element_id"]?.jsonPrimitive?.content ?: return
        val value = params["value"]?.jsonPrimitive?.contentOrNull ?: return

        bodyAnswers[elementId] = value
    }

    override fun flowViewDidDisappear(view: AdaptyUIFlowView) {
        // The observer receives events from every flow. Reset `bodyAnswers` and
        // `reachedLastScreen` whenever a flow disappears, so that the paywall
        // doesn't open again when the user closes it.
        val answers = bodyAnswers.toMap()
        val finished = reachedLastScreen
        bodyAnswers.clear()
        reachedLastScreen = false

        // Number inputs send their values as strings.
        if (!finished) return
        val weight = answers["weight"]?.toDoubleOrNull() ?: return
        val height = answers["height"]?.toDoubleOrNull()?.takeIf { it > 0 } ?: return

        val heightInMeters = height / 100
        val bmi = weight / (heightInMeters * heightInMeters)
        val bmiText = ((bmi * 10).roundToInt() / 10.0).toString()

        scope.launch { showBmiPaywall(bmiText) }
    }
}

suspend fun showBmiPaywall(bmi: String) {
    Adapty.getFlow(placementId = "bmi_paywall").onSuccess { flow ->
        AdaptyUI.createFlowView(
            flow = flow,
            customTags = mapOf("bmi" to bmi),
        ).onSuccess { view ->
            view.present()
        }.onError { error ->
            // handle the error
        }
    }.onError { error ->
        // handle the error
    }
}
```

`toString` は小数点区切り文字として常にピリオドを使用します（例：「22.7」）。ユーザーのロケールに応じた区切り文字を使用するには、各プラットフォームのロケール対応フォーマッターを使用してください（Androidなら `java.text.NumberFormat`、iOSなら `NSNumberFormatter` など）。

### BMIをユーザーのプロファイルに保存する \{#save-the-bmi-to-the-users-profile\}

BMIに基づいてユーザーに異なるフローを表示するには、BMIをプロファイルの[カスタム属性](kmp-setting-user-attributes#custom-user-attributes)として保存します。Adapty ダッシュボードで、キー `bmi` を持つ **Number** 型のカスタム属性を[作成](segments#custom-attributes)してください。その後、その属性から作成した[オーディエンス](audience)に各フローを表示します。

`flowViewDidDisappear` 内の `bmi` を計算する行のすぐ後で `updateProfile` メソッドを呼び出します。セグメントがBMIをしきい値と比較できるよう、フォーマット済みの文字列ではなく `Double` 型の値を渡してください：

```kotlin showLineNumbers title="Kotlin Multiplatform"

val params = AdaptyProfileParameters.Builder()
    .withCustomAttribute("bmi", bmi)
    .build()

scope.launch {
    Adapty.updateProfile(params).onError { error ->
        // handle the error
    }
}
```