Afficher un paywall ciblé AA au premier lancement dans Flutter SDK

L’attribution Apple Ads (AA) arrive de manière asynchrone après Adapty().activate(). Au premier lancement, elle n’est généralement pas encore disponible, donc si vous appelez getPaywall immédiatement, Adapty résout la requête par rapport à l’audience par défaut et les utilisateurs Apple Ads ratent votre paywall segmenté AA. Plutôt que d’afficher un paywall puis de le remplacer, attendez brièvement l’attribution AA avant d’afficher quoi que ce soit : affichez le paywall ciblé si l’attribution arrive dans un court délai, ou le paywall de l’audience par défaut si ce n’est pas le cas. AdaptyProfile.appliedAttributionSources vous indique quand l’attribution AA a été appliquée.

Avant de commencer

Vous avez besoin de :

  • Adapty Flutter SDK 3.17.0 ou version ultérieure.
  • Apple Ads configuré pour l’application dans Adapty. Voir Apple Ads.

Fonctionnement

Après Adapty().activate(), le SDK demande l’attribution Apple Ads à Apple en arrière-plan et transmet le résultat au backend d’Adapty. Quand AA devient la source d’attribution active pour le profil, le SDK envoie un AdaptyProfile mis à jour à votre listener didUpdateProfileStream, avec AdaptyAttributionSource.appleAds dans sa liste appliedAttributionSources.

Au premier lancement, deux cas sont à gérer :

  1. L’attribution arrive dans le délai imparti. Appelez getPaywall — Adapty résout la requête par rapport à l’audience Apple Ads et retourne le paywall ciblé.
  2. Le délai expire en premier. Affichez plutôt le paywall de l’audience par défaut, afin que les utilisateurs sans attribution Apple Ads n’attendent pas indéfiniment. getPaywallForDefaultAudience le retourne sans attendre la segmentation.

appliedAttributionSources peut être vide. Cela signifie soit :

  • L’attribution Apple Ads n’a pas encore été traitée pour ce profil, ou
  • aucune attribution n’est arrivée du tout.

Dans tous les cas, getPaywallForDefaultAudience peut être appelé en toute sécurité — il retourne le paywall de l’audience par défaut quel que soit l’état du profil.

L’attente ne s’applique qu’au premier lancement. Une fois l’attribution Apple Ads enregistrée, elle est stockée définitivement sur le profil. À chaque lancement suivant, le profil en cache contient déjà AdaptyAttributionSource.appleAds dans appliedAttributionSources, donc le chemin d’attribution se résout immédiatement et getPaywall retourne le paywall segmenté Apple Ads sans aucun délai.

Implémentation

Au premier lancement, attendez AdaptyAttributionSource.appleAds et appliquez un délai strict — si l’attribution Apple Ads n’arrive jamais, ces utilisateurs doivent quand même voir un paywall.

  1. Activez le SDK. Voir Installer et configurer le Flutter SDK.
  2. Abonnez-vous aux mises à jour du profil avec Adapty().didUpdateProfileStream.listen(…). Si vous n’avez pas encore configuré le listener, voir Écouter les mises à jour d’abonnement.
  3. Surveillez AdaptyAttributionSource.appleAds dans appliedAttributionSources. Quand il apparaît, chargez le paywall avec getPaywall — Adapty retourne la variante segmentée 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 est un broadcast stream et ne rejoue pas les événements passés, donc vérifiez aussi le profil actuel une fois avec getProfile(). Lors des relances, l’attribution stockée est déjà appliquée et ne sera pas renvoyée.

  1. Démarrez un timer de 3 à 5 secondes en parallèle de l’abonnement. Si le timer se déclenche avant que AdaptyAttributionSource.appleAds n’apparaisse, chargez plutôt le paywall de l’audience par défaut avec getPaywallForDefaultAudience. Affichez le premier paywall résolu et annulez l’autre chemin, afin que le paywall ne soit pas récupéré deux fois. Configurez un paywall de secours pour le placement afin que l’utilisateur ne soit jamais bloqué en cas d’échec réseau.

Exemple complet

L’implémentation ci-dessous met en compétition l’attribution et un délai, précharge le paywall de l’audience par défaut en parallèle, et retourne le paywall approprié. L’appelant attend une seule fonction — aucun listener ni indicateur d’état à gérer côté appelant :

  • Si l’attribution arrive dans le timeout, elle retourne le paywall segmenté via getPaywall.
  • Si le timeout expire en premier, elle retourne le paywall de l’audience par défaut préchargé via 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;
}

Appelez depuis votre écran de démarrage, puis affichez le paywall une fois qu’il est résolu :

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
}

Ajustez timeout selon le temps que vous êtes prêt à faire attendre les utilisateurs avant qu’un paywall n’apparaisse. La plupart des utilisateurs n’ont pas d’attribution Apple Ads, donc ils attendent le délai complet — 3 à 5 secondes est un équilibre raisonnable. L’attribution qui arrive le fait généralement dans les quelques secondes suivant le lancement.

Si votre application écoute déjà didUpdateProfileStream à d’autres fins (par exemple, vérifier l’état de l’abonnement), vous n’avez pas besoin de le modifier. didUpdateProfileStream est un broadcast stream, donc il prend en charge plusieurs listeners indépendants sans affecter les autres.