iOSのSDKでフローにデータを渡す

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

始める前に

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

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

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

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

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

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

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

カスタムタグの値を渡す

アプリの値をgetFlowConfigurationのtagResolverパラメータに、[String: String]ディクショナリとして渡します:

  • 各キーはuser.streakなど、カスタムタグのフル名です。
  • 各値は、タグの代わりにユーザーに表示される文字列です。
  • 各値は「1250.0」ではなく「1,250」のように、人間が読める形式である必要があります。Adaptyはフォーマットや翻訳を行いません。
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、および UIKit のフローコントローラーには、カスタムタグ値を指定するパラメーターはありません。渡したフロー設定に含まれる値がそのまま表示されます。

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

The following code is for UIKit. It implements the AdaptyFlowControllerDelegate methods on one view controller, which is the delegate of both the onboarding flow’s controller and the paywall’s controller. The view controller must also implement the delegate’s purchase and restore methods, which this example leaves out. To see them, go to UIKit でフローとペイウォールを表示する.

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 を計算します。次に、ペイウォールのフロー設定を取得し、bmi カスタムタグに BMI を渡します。その設定を2番目の .flow モディファイアで表示します。

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

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

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

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