在 Flutter SDK 中将数据传入流程
自定义标签是一个自定义变量,其值来自您的应用。在变量设置中选择 Value comes from outside the app 后,您的应用可以通过 Adapty SDK 设置该变量的值。例如,一个文本元素包含”Coins:“和一个自定义标签。如果您的应用为该标签传入”120”,用户将看到”Coins: 120”。
开始之前
您需要使用 Adapty SDK v4 或更高版本。v4 之前的版本不支持显示流程。
向流程添加自定义标签
要在流程中显示应用的数据,请在编辑工具中设置自定义标签:
-
为应用传递的每个值创建一个自定义标签。
-
记录每个标签的完整名称,包括其所属分组。应用代码在传递对应值时需使用该名称。例如,若
user分组中包含streak标签,则该标签的完整名称为user.streak。
传入自定义标签值
将应用中的值传入 AdaptyUI().createFlowView 或 AdaptyUIFlowPlatformView 的 customTags 参数,类型为 Map<String, String>:
- 每个键是自定义标签的完整名称,例如
user.streak。 - 每个值是用户看到的替换文本。
- 每个值必须是易读的格式,例如 “1,250”,而非 “1250.0”。Adapty 不会对其进行格式化或翻译。
SDK 在创建视图时读取一次这些值,因此在流程打开期间不会更新。
要测试自定义标签,请在添加设置其值的代码后,在应用中打开流程。编辑工具画布和在设备上预览只显示初始值:Adapty 移动应用不会设置自定义标签的值。
如果你的应用已为旧版付费墙编辑工具的付费墙设置了自定义标签值,请参阅流程中自定义标签的差异。
用户在没有值时看到的内容
在以下情况下,用户会看到自定义标签的初始值作为备用内容:
- 您的应用未为该标签传递任何值。
- 用户尚未将应用更新到能传递该值的版本。
- 应用代码中的名称与标签的完整名称不匹配,包括字母大小写。
- 同一文本元素中的另一个自定义标签没有值。此时该文本元素中的每个自定义标签都会显示其初始值。
如需在标签位置不显示任何内容,请传入空字符串。Adapty 将空字符串视为有效值,因此不会显示备用内容。
示例:根据用户引导中的答案显示 BMI
流程可以收集用户的答案,自定义标签可以显示来自你应用的值。将两者结合,即可向用户展示由你的应用根据其答案计算得出的结果,例如得分、推荐套餐或健康指标:
- 流程收集答案并将其发送给你的应用。
- 你的应用计算结果。
- 你的应用将结果作为自定义标签值传递给下一个流程。
在此示例中,一个用户引导流程收集用户的体重和身高。当用户在最后一屏关闭用户引导流程后,你的应用会计算其身体质量指数(BMI)。然后它会打开一个付费墙流程,显示该 BMI 值。
设置流程
-
创建两个流程:一个用于收集用户体重和身高的用户引导流程,以及一个展示 BMI 的付费墙流程。
-
在用户引导流程中添加两个 Number 输入框:
- 一个用于输入体重(千克),Element ID 设为
weight。 - 一个用于输入身高(厘米),Element ID 设为
height。
两个输入框的 Format 均设为 Integer。输入框会将用户输入的内容原样以文本形式发送,示例代码对 “70.5” 和 “70,5” 的解析结果并不相同。整数没有小数分隔符,因此在任何语言环境下代码的解析结果都一致。
- 一个用于输入体重(千克),Element ID 设为
-
为确保您的应用能收到两个值,请在用户引导流程的最后添加一个不含输入框的屏幕。在该屏幕上添加一个带有 Close flow 操作的按钮。输入框会在失去焦点或用户切换到其他屏幕时发送其值,而 Close flow 操作不会触发发送。示例代码只有在用户到达最后一屏时才会打开付费墙。
-
在付费墙流程中,创建一个名为
bmi的自定义标签。在 Initial value 字段中输入一个破折号(—)。如果您的应用未传入 BMI 值,用户将看到该破折号。 -
在付费墙流程中添加一个文本元素,内容为”Your BMI:“。在这些文字后面插入
bmi自定义标签。 -
将用户引导流程添加到某个版位,例如
onboarding。将付费墙流程添加到 ID 为bmi_paywall的版位。将 BMI 传递给付费墙中的代码通过此 ID 获取付费墙。
将 BMI 传递给付费墙
从用户引导流程的 flow_user_input 事件中收集体重和身高数据,具体方法请参阅处理流程数据。若要判断用户是否到达最后一屏,可监听 flow_screen_showed 事件,并检查 is_last_screen 是否为 true,具体方法请参阅追踪流程页面浏览。当用户在该屏后关闭用户引导流程时,计算 BMI,然后创建付费墙视图,并将 BMI 传入 bmi 自定义标签。
将以下方法添加到你通过 AdaptyUI().setFlowsEventsObserver 注册的观察者中。该观察者还必须实现 flowViewDidFinishRestore 和 flowViewDidReceiveError,本示例中未包含这两个方法:
final Map<String, String> bodyAnswers = {};
bool reachedLastScreen = false;
void flowViewDidReceiveAnalyticEvent(
AdaptyUIFlowView view,
String name,
Map<String, dynamic> params,
) {
if (name == 'flow_screen_showed' && params['is_last_screen'] == true) {
reachedLastScreen = true;
return;
}
if (name != 'flow_user_input') return;
final elementId = params['element_id'];
final value = params['value'];
if (elementId is! String || value is! String) return;
bodyAnswers[elementId] = value;
}
void flowViewDidDisappear(AdaptyUIFlowView view) {
// 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.
final answers = Map<String, String>.of(bodyAnswers);
final finished = reachedLastScreen;
bodyAnswers.clear();
reachedLastScreen = false;
// Number inputs send their values as strings.
final weight = double.tryParse(answers['weight'] ?? '');
final height = double.tryParse(answers['height'] ?? '');
if (!finished || weight == null || height == null || height <= 0) return;
final heightInMeters = height / 100;
final bmi = weight / (heightInMeters * heightInMeters);
showBmiPaywall(bmi.toStringAsFixed(1));
}
Future<void> showBmiPaywall(String bmi) async {
try {
final flow = await Adapty().getFlow(placementId: 'bmi_paywall');
final view = await AdaptyUI().createFlowView(
flow: flow,
customTags: {'bmi': bmi},
);
await view.present();
} on AdaptyError catch (e) {
// handle the error
} catch (e) {
// handle the error
}
}
toStringAsFixed 始终使用句点作为小数分隔符。如需使用用户语言环境的分隔符,请使用 intl 包中的 NumberFormat 格式化 BMI。
将 BMI 保存到用户画像
要根据用户的 BMI 展示不同的流程,请将其作为自定义属性保存到用户画像中。在 Adapty 看板中,创建一个 Number 类型的自定义属性,键名设为 bmi。然后为每个流程创建一个基于该属性的目标受众。
在 flowViewDidDisappear 中调用 updateProfile 方法,紧接在计算 bmi 的那行代码之后。传入 double 值而非格式化后的字符串,这样市场细分才能将 BMI 与阈值进行比较:
try {
final builder = AdaptyProfileParametersBuilder()
..setCustomDoubleAttribute(bmi, 'bmi');
await Adapty().updateProfile(builder.build());
} on AdaptyError catch (e) {
// handle the error
} catch (e) {
// handle the error
}