在 Flutter SDK 中首次启动时显示 AA 定向付费墙
Apple Ads (AA) 归因数据在 Adapty().activate() 调用后会异步到达。首次启动时,归因数据通常尚未就位,因此如果你立即调用 getPaywall,Adapty 会基于默认目标受众处理该请求,导致 Apple Ads 用户无法看到针对 AA 细分设置的付费墙。与其先展示付费墙再替换,不如在显示任何内容前短暂等待 AA 归因数据:若归因在短暂超时内到达,则展示定向付费墙;否则展示默认目标受众的付费墙。AdaptyProfile.appliedAttributionSources 可告知你 AA 归因是否已生效。
开始之前
您需要:
- Adapty Flutter SDK 3.17.0 或更高版本。
- 在 Adapty 中为应用配置 Apple Ads。请参阅 Apple Ads。
工作原理
调用 Adapty().activate() 后,SDK 会在后台向 Apple 请求 Apple Ads 归因数据,并将结果转发至 Adapty 后端。当 AA 成为该用户画像的有效归因来源时,SDK 会向你的 didUpdateProfileStream 监听器推送更新后的 AdaptyProfile,其 appliedAttributionSources 列表中将包含 AdaptyAttributionSource.appleAds。
首次启动时,你需要处理以下两种情况:
- 归因在超时时间内完成。 调用
getPaywall— Adapty 根据 Apple Ads 目标受众解析请求,并返回对应的付费墙。 - 超时时间先到。 改为显示默认目标受众的付费墙,避免没有 Apple Ads 归因的用户白白等待。
getPaywallForDefaultAudience无需等待分群即可直接返回结果。
appliedAttributionSources 可以为空,这意味着:
- 该用户画像的 Apple Ads 归因尚未处理完成,或
- 根本没有收到任何归因数据。
无论如何,
getPaywallForDefaultAudience都可以安全调用——它会直接返回默认受众的付费墙,不受用户画像状态影响。
等待仅发生在首次启动时。一旦 Apple Ads 归因数据记录完成,它就会永久保存在用户画像中。在此后的每次启动时,缓存的用户画像已经在 appliedAttributionSources 中包含了 AdaptyAttributionSource.appleAds,因此归因路径会立即解析,getPaywall 无需任何等待即可返回针对 Apple Ads 市场细分的付费墙。
实现
首次启动时,等待 AdaptyAttributionSource.appleAds 回调并设置硬超时——如果 Apple Ads 归因数据始终未到达,这些用户仍然需要看到付费墙。
- 激活 SDK。 请参阅安装并配置 Flutter SDK。
- 订阅用户画像更新,使用
Adapty().didUpdateProfileStream.listen(…)。如果尚未设置监听器,请参阅监听订阅更新。 - 在
appliedAttributionSources中监听AdaptyAttributionSource.appleAds。 当它出现时,使用getPaywall加载付费墙 —— Adapty 将返回 AA 细分的实验变体:
final subscription = Adapty().didUpdateProfileStream.listen((profile) async {
if (!profile.appliedAttributionSources.contains(AdaptyAttributionSource.appleAds)) return;
final paywall = await Adapty().getPaywall(placementId: placementId);
// present the segmented paywall, then cancel the subscription and the timer
});
didUpdateProfileStream 是广播流,不会重播历史事件,因此还需通过 getProfile() 单独检查当前用户画像。应用重启后,已存储的归因数据不会再次触发事件。
4. 与订阅同步启动一个 3–5 秒的计时器。 如果计时器先于 AdaptyAttributionSource.appleAds 触发,则改用 getPaywallForDefaultAudience 加载默认受众付费墙。优先展示先完成的那个付费墙,并取消另一路请求,避免重复获取。为该版位配置备用付费墙,确保网络请求失败时用户也不会卡住。
完整示例
下面的实现方案会让归因与超时同时竞争,并行预取默认受众付费墙,然后返回合适的付费墙。调用方只需等待单个函数,无需在调用处管理监听器或状态标志:
- 如果归因在
timeout内完成,则通过getPaywall返回分段付费墙。 - 如果
timeout先到期,则通过getPaywallForDefaultAudience返回预取的默认受众付费墙。
/// Returns the Apple Ads-segmented paywall if attribution is applied within
/// [timeout], otherwise the default-audience paywall. Call after Adapty().activate().
Future<AdaptyPaywall> getPaywallOrDefault({
required String placementId,
required Duration timeout,
}) {
// Prefetch the default-audience paywall right away so the timeout path resolves
// without an extra network round-trip. `getPaywallForDefaultAudience` skips the
// wait for segmentation data. `..ignore()` keeps an unused prefetch from surfacing
// as an unhandled error; the error still reaches the caller if this paywall wins.
final defaultPaywall =
Adapty().getPaywallForDefaultAudience(placementId: placementId)..ignore();
final completer = Completer<AdaptyPaywall>();
late final StreamSubscription<AdaptyProfile> subscription;
late final Timer timer;
void resolve(Future<AdaptyPaywall> paywall) {
if (completer.isCompleted) return;
timer.cancel();
subscription.cancel();
completer.complete(paywall);
}
void onProfile(AdaptyProfile profile) {
if (profile.appliedAttributionSources.contains(AdaptyAttributionSource.appleAds)) {
resolve(Adapty().getPaywall(placementId: placementId));
}
}
// Attribution path: react to profile updates as attribution is applied.
subscription = Adapty().didUpdateProfileStream.listen(onProfile);
// The stream is a broadcast stream and doesn't replay, so check the current
// profile too — on relaunches attribution is already stored and won't re-emit.
Adapty().getProfile().then(onProfile).ignore();
// Timeout path: fall back to the prefetched default-audience paywall.
timer = Timer(timeout, () => resolve(defaultPaywall));
return completer.future;
}
在启动画面中调用,待其完成后再展示付费墙:
try {
final paywall = await getPaywallOrDefault(
placementId: 'YOUR_PLACEMENT_ID',
timeout: const Duration(seconds: 5),
);
// present the paywall
} on AdaptyError catch (adaptyError) {
// handle the error or show a fallback paywall
} catch (e) {
// handle the error
}
调整 timeout 参数,设置用户在付费墙出现前最多等待的时间。大多数用户没有 Apple Ads 归因数据,因此他们会等待完整的超时时长——3 到 5 秒是一个合理的平衡点。如果有归因数据,通常会在应用启动后几秒内到达。
如果你的应用已经在监听 didUpdateProfileStream(例如用于检查订阅状态),则无需做任何修改。didUpdateProfileStream 是一个广播流,支持多个独立监听器互不干扰。