Androidアプリからフローにデータを渡す

カスタムタグとは、アプリから値を受け取るカスタム変数です。変数の設定で Value comes from outside the app を選択すると、アプリは Adapty SDK を通じてその値を設定できます。たとえば、テキスト要素に「Coins:」とカスタムタグが含まれている場合、アプリが「120」を渡すと、ユーザーには「Coins: 120」と表示されます。

始める前に

Adapty SDK v4 以降が必要です。v4 より前のバージョンではフローが表示されません。

フローにカスタムタグを追加する

アプリの値をフローで表示するには、ビルダーでカスタムタグを設定します。

  1. アプリが渡す各値に対してカスタムタグを作成します。

    名前、説明、String値タイプ、および初期値を含む変数作成フォーム
  2. 各タグをテキスト要素に挿入します。

  3. グループ名を含む各タグのフルネームを確認してください。アプリのコードはこの名前で各値を渡します。たとえば、user グループに streak タグが含まれている場合、タグのフルネームは user.streak となります。

    streakタグがuserグループ内にある、変数追加ドロップダウンのカスタムタブ

カスタムタグ値の受け渡し

AdaptyUiTagResolver を作成し、AdaptyUI.getFlowView の tagResolver パラメータとして渡します。SDK は user.streak のようなカスタムタグの完全な名前を引数にしてリゾルバを呼び出します。リゾルバは次のいずれかを返します:

  • 文字列: ユーザーにはタグの代わりにその値が表示されます。"1250.0" ではなく "1,250" のように人間が読める形式にしてください。Adapty はフォーマットや翻訳を行いません。
  • null: ユーザーにはフォールバックとしてタグの初期値が表示されます。
  • 空文字列: タグの位置には何も表示されません。

AdaptyFlowViewを自分で作成する場合は、リゾルバーをそのshowFlowメソッドに渡してください。Jetpack Composeの場合は、AdaptyFlowScreenに渡してください。各呼び出しの例については、フローとペイウォールの表示を参照してください。

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

アプリが旧ペイウォールビルダーのペイウォールにカスタムタグの値をすでに設定している場合は、フローにおけるカスタムタグの違いを確認してください。

値が設定されていない場合にユーザーが見るもの

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

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

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

オンボーディングの回答からBMIを表示する例

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

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

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

フローを設定する

  1. 2つのフローを作成します: ユーザーの体重と身長を収集するオンボーディングフローと、BMIを表示するペイウォールフローです。

  2. オンボーディングフローに2つのNumber入力を追加します:

    • 体重(キログラム)用。Element IDをweightに設定します。
    • 身長(センチメートル)用。Element IDをheightに設定します。

    両方の入力で、FormatをIntegerに設定します。入力はユーザーが入力した通りのテキストとして値を送信するため、サンプルコードは”70.5”と”70,5”を同じように読み取りません。整数には小数点区切り文字がないため、すべてのロケールで同じように読み取られます。

  3. アプリが両方の値を確実に受け取れるよう、オンボーディングフローを入力のない画面で終了させます。その画面に、Close flowアクションを持つボタンを追加します。入力はフォーカスを失ったとき、またはユーザーが別の画面に移動したときに値を送信します。Close flowアクションは値を送信しません。サンプルコードは、ユーザーが最後の画面に到達した場合にのみペイウォールを開きます。

  4. ペイウォールフローで、bmiという名前のカスタムタグを作成します。Initial valueフィールドにダッシュ(—)を入力します。アプリがBMIを渡さない場合、ユーザーにはダッシュが表示されます。

  5. ペイウォールフローに「Your BMI:」という文字列を含むテキスト要素を追加します。この文字列の後に、bmiカスタムタグを挿入します。

  6. オンボーディングフローをonboardingなどのプレースメントに追加します。ペイウォールフローをID bmi_paywallのプレースメントに追加します。BMIをペイウォールに渡すのコードは、このIDでペイウォールを取得します。

BMIをペイウォールに渡す

オンボーディングフローの flow_user_input イベントから体重と身長を収集します(フローからデータを処理するを参照)。ユーザーが最後の画面に到達したことを検知するには、is_last_screen が true に設定された flow_screen_showed イベントを監視します(フロー画面の表示をトラッキングするを参照)。ユーザーがその画面の後にオンボーディングフローを閉じたら、BMIを計算します。次に、ペイウォールのフロービューを作成し、bmi カスタムタグにBMIを渡します。

オンボーディングフローのビューに以下のリスナーを渡します:

class OnboardingEventListener(
    private val onBmiCalculated: (bmi: String) -> Unit,
) : AdaptyFlowDefaultEventListener() {

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

    override fun onAnalyticEvent(
        name: String,
        params: Map<String, Any?>,
        context: Context,
    ) {
        if (name == "flow_screen_showed" && params["is_last_screen"] == true) {
            reachedLastScreen = true
            return
        }
        if (name != "flow_user_input") return

        val elementId = params["element_id"] as? String ?: return
        val value = params["value"] as? String ?: return

        bodyAnswers[elementId] = value
    }

    override fun onFlowClosed() {
        // Reset `bodyAnswers` and `reachedLastScreen` on every close,
        // so that the next run starts without old answers.
        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)

        onBmiCalculated(String.format(Locale.getDefault(), "%.1f", bmi))
    }
}

最後の画面の後にオンボーディングフローをユーザーが閉じると、リスナーは BMI を伴って onBmiCalculated を呼び出します。onBmiCalculated に、以下の関数を呼び出すラムダを渡してください。この関数はペイウォールフローを取得してビューを作成し、bmi カスタムタグに BMI を渡します。

fun showBmiPaywall(activity: Activity, bmi: String) {
    Adapty.getFlow("bmi_paywall") { flowResult ->
        when (flowResult) {
            is AdaptyResult.Success -> {
                AdaptyUI.getFlowConfiguration(flowResult.value) { configResult ->
                    when (configResult) {
                        is AdaptyResult.Success -> {
                            val flowView = AdaptyUI.getFlowView(
                                activity,
                                configResult.value,
                                products = null,
                                eventListener = AdaptyFlowDefaultEventListener(),
                                tagResolver = AdaptyUiTagResolver { tag ->
                                    if (tag == "bmi") bmi else null
                                },
                            )
                            // add flowView to your view hierarchy
                        }
                        is AdaptyResult.Error -> {
                            // handle the error
                        }
                    }
                }
            }
            is AdaptyResult.Error -> {
                // handle the error
            }
        }
    }
}

String.format に Locale.getDefault() を指定すると、ユーザーのロケールに応じた小数点区切り文字が使用されます。英語では “22.7”、ドイツ語では “22,7” となります。

BMIをユーザーのプロファイルに保存する

BMIに基づいて異なるフローをユーザーに表示するには、BMIをプロファイルのカスタム属性として保存します。Adapty ダッシュボードで、キー bmi を持つNumber カスタム属性を作成してください。その後、その属性をもとに作成したオーディエンスに各フローを表示します。

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

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

Adapty.updateProfile(params) { error ->
    if (error != null) {
        // handle the error
    }
}