Flutter SDKで初回起動時にAA対象ペイウォールを表示する
この記事はアプリのiOSビルドに適用されます。Apple AdsのアトリビューションはiOSのみで利用可能です。
Apple Ads(AA)のアトリビューションは、Adapty().activate() の後に非同期で届きます。初回起動時はまだ届いていないことが多いため、すぐに getFlow を呼び出すと、Adapty はデフォルトのオーディエンスに基づいてリクエストを解決し、AA でセグメントされたペイウォールが Apple Ads ユーザーに表示されません。ペイウォールを一度表示してから差し替えるのではなく、何も表示する前に AA アトリビューションを短時間だけ待ちましょう。アトリビューションが短いタイムアウト内に届いた場合はターゲット向けのペイウォールを、届かなかった場合はデフォルトオーディエンスのペイウォールを表示します。AdaptyProfile.appliedExternalAttributionProviders を使うと、AA アトリビューションが適用されたかどうかを確認できます。
このプロパティはApple Adsのみを報告します。他のプロバイダーからのアトリビューションはユーザープロファイルで確認でき、セグメントフィルターでも利用できますが、ここにはまだ表示されません。
始める前に
必要なもの:
- Adapty Flutter SDK 4.1 以降。4.0.x では、プロファイルのプロパティ名は
appliedAttributionSourcesで、値はAdaptyAttributionSourceです。詳細は v4.1 への移行 を参照してください。3.17.0〜3.x では、フローもgetPaywall/getPaywallForDefaultAudienceで取得でき、返り値の型はAdaptyPaywallです。詳細は v4.0 への移行 を参照してください。 - Apple Ads が Adapty のアプリ設定で構成されていること。詳細は Apple Ads を参照してください。
仕組み
Adapty().activate() の呼び出し後、SDKはバックグラウンドでApple AdsのアトリビューションをAppleにリクエストし、その結果をAdaptyのバックエンドに転送します。AAがプロファイルのアクティブなアトリビューションソースになると、SDKはdidUpdateProfileStreamリスナーに更新されたAdaptyProfileを届けます。このとき、appliedExternalAttributionProvidersリストにはAdaptyExternalAttributionProvider.appleAdsが含まれています。
初回起動時には、次の2つのケースに対応する必要があります。
- アトリビューションがタイムアウト内に届いた場合。
getFlowを呼び出すと、Adapty はリクエストを Apple Ads オーディエンスに対して解決し、ターゲティングされたペイウォールを返します。 - 先にタイムアウトが経過した場合。 代わりにデフォルトオーディエンスのペイウォールを表示します。これにより、Apple Ads のアトリビューションがないユーザーを待たせずに済みます。
getFlowForDefaultAudienceはセグメンテーションを待たずにそれを返します。
appliedExternalAttributionProviders は空になる場合があります。その場合、以下のいずれかを意味します。
- このプロファイルの Apple Ads アトリビューションがまだ処理されていない。
- アトリビューションがまったく届いていない。
- 別のプロバイダーからアトリビューションが届いているが、この配列にはそのデータが含まれていない。
いずれの場合も、getFlowForDefaultAudience は安全に呼び出せます。プロファイルの状態にかかわらず、デフォルトオーディエンスのペイウォールを返します。
この待機は初回起動時のみ適用されます。Apple Ads のアトリビューションが一度記録されると、それはプロファイルに永続的に保存されます。2回目以降の起動では、キャッシュされたプロファイルの appliedExternalAttributionProviders にすでに AdaptyExternalAttributionProvider.appleAds が含まれているため、アトリビューションパスはすぐに解決され、getFlow は遅延なく Apple Ads セグメント向けのペイウォールを返します。
実装
初回起動時は AdaptyExternalAttributionProvider.appleAds を待機し、ハードタイムアウトを設定してください。Apple Ads のアトリビューションが届かなかった場合でも、そのユーザーにはペイウォールを表示する必要があります。
- SDKを有効化する。 Flutter SDKのインストールと設定を参照してください。
Adapty().didUpdateProfileStream.listen(…)でプロファイルの更新を購読する。 リスナーをまだ設定していない場合は、サブスクリプション更新のリッスンを参照してください。appliedExternalAttributionProviders内のAdaptyExternalAttributionProvider.appleAdsを監視する。 それが現れたら、getFlowでペイウォールを読み込みます — AdaptyはAAセグメント済みのバリアントを返します:
final subscription = Adapty().didUpdateProfileStream.listen((profile) async {
if (!profile.appliedExternalAttributionProviders.contains(AdaptyExternalAttributionProvider.appleAds)) return;
final paywall = await Adapty().getFlow(placementId: placementId);
// present the segmented paywall, then cancel the subscription and the timer
});
didUpdateProfileStream はブロードキャストストリームであり、過去のイベントを再生しません。そのため、getProfile() を使って現在のプロファイルも一度確認してください。アプリを再起動した場合、保存済みのアトリビューションはすでに適用済みのため、再度イベントは発行されません。
AdaptyExternalAttributionProvider.appleAdsが返ってくる前にタイマーが発火した場合は、代わりにgetFlowForDefaultAudienceでデフォルトオーディエンスのペイウォールを読み込むよう、サブスクリプションと並行して3〜5秒のタイマーを開始します。 先に解決した方のペイウォールを表示してもう一方のパスはキャンセルし、ペイウォールが2回取得されないようにしてください。ネットワークリクエストが失敗してもユーザーが止まらないよう、プレースメントにフォールバックペイウォールを設定してください。
完全な実装例
以下の実装では、アトリビューションとタイムアウトを競わせながら、デフォルトオーディエンスのペイウォールを並行してプリフェッチし、適切なペイウォールを返します。呼び出し元は単一の関数を await するだけで済み、コールサイトでリスナーやステートフラグを管理する必要はありません。
- アトリビューションが
timeout以内に取得できた場合、getFlowを通じてセグメント化されたペイウォールを返します。 timeoutが先に経過した場合、getFlowForDefaultAudienceを通じてプリフェッチされたデフォルトオーディエンスのペイウォールを返します。
/// Returns the Apple Ads-segmented paywall if attribution is applied within
/// [timeout], otherwise the default-audience paywall. Call after Adapty().activate().
Future<AdaptyFlow> getFlowOrDefault({
required String placementId,
required Duration timeout,
}) {
// Prefetch the default-audience paywall right away so the timeout path resolves
// without an extra network round-trip. `getFlowForDefaultAudience` 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().getFlowForDefaultAudience(placementId: placementId)..ignore();
final completer = Completer<AdaptyFlow>();
late final StreamSubscription<AdaptyProfile> subscription;
late final Timer timer;
void resolve(Future<AdaptyFlow> paywall) {
if (completer.isCompleted) return;
timer.cancel();
subscription.cancel();
completer.complete(paywall);
}
void onProfile(AdaptyProfile profile) {
if (profile.appliedExternalAttributionProviders.contains(AdaptyExternalAttributionProvider.appleAds)) {
resolve(Adapty().getFlow(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 getFlowOrDefault(
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 はブロードキャストストリームなので、複数の独立したリスナーが互いに影響を与えることなく使用できます。