Afficher un paywall ciblé par Apple Ads au premier lancement dans Flutter SDK

Cet article s’applique à la version iOS de votre application. L’attribution Apple Ads est disponible sur iOS uniquement.

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 : si vous appelez getFlow immédiatement, Adapty résout la requête sur 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 : montrez le paywall ciblé si l’attribution arrive dans un court délai, ou celui de l’audience par défaut dans le cas contraire. AdaptyProfile.appliedExternalAttributionProviders vous indique quand l’attribution AA a été appliquée.

Important

Cette propriété ne rapporte que les données Apple Ads. L’attribution provenant d’autres fournisseurs est visible sur les profils utilisateurs et disponible dans les filtres de segments, mais pas encore ici.

Avant de commencer

Vous avez besoin de :

  • Adapty Flutter SDK 4.1 ou version ultérieure. Avec la version 4.0.x, la propriété de profil est nommée appliedAttributionSources et ses valeurs sont de type AdaptyAttributionSource — voir Migrer vers v4.1. Avec les versions 3.17.0–3.x, les flows sont également récupérés avec getPaywall/getPaywallForDefaultAudience et le type retourné est AdaptyPaywall — voir Migrer vers v4.0.
  • Apple Ads configuré pour l’application dans Adapty. Voir Apple Ads.

Comment ça fonctionne

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

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

  1. L’attribution arrive dans le délai imparti. Appelez getFlow — Adapty résout la requête en fonction de l’audience Apple Ads et renvoie le paywall ciblé.
  2. Le délai expire en premier. Affichez alors le paywall de l’audience par défaut, afin que les utilisateurs sans attribution Apple Ads n’aient pas à attendre. getFlowForDefaultAudience le renvoie sans attendre la segmentation.

appliedExternalAttributionProviders peut être vide. Cela signifie l’une des choses suivantes :

  • L’attribution Apple Ads n’a pas encore été traitée pour ce profil.
  • Aucune attribution n’est arrivée.
  • Une attribution est arrivée d’un autre fournisseur, que ce tableau ne rapporte pas.

Dans les trois cas, getFlowForDefaultAudience peut être appelé sans risque — il renvoie le paywall de l’audience par défaut quel que soit l’état du profil.

Important

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à AdaptyExternalAttributionProvider.appleAds dans appliedExternalAttributionProviders, donc le chemin d’attribution se résout immédiatement et getFlow renvoie le paywall segmenté par Apple Ads sans aucun délai.

Mise en œuvre

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

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

  1. Démarrez un minuteur de 3 à 5 secondes en parallèle de l’abonnement. Si le minuteur se déclenche avant l’apparition de AdaptyExternalAttributionProvider.appleAds, chargez le paywall de l’audience par défaut avec getFlowForDefaultAudience à la place. Affichez le premier paywall qui se résout 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 reste jamais bloqué en cas d’échec de la requête réseau.

Exemple complet

L’implémentation ci-dessous fait la course entre l’attribution et un délai d’expiration, précharge en parallèle le paywall de l’audience par défaut, et retourne le paywall approprié. L’appelant attend une seule fonction — pas d’écouteurs ni d’indicateurs d’état à gérer côté appelant :

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

Appelez cette fonction depuis votre écran de démarrage, puis affichez le paywall une fois la promesse résolue :

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
}

Ajustez le timeout en fonction du délai maximal que vous êtes prêt à imposer aux utilisateurs avant qu’un paywall n’apparaisse. La plupart des utilisateurs n’ont pas d’attribution Apple Ads, ils attendent donc la totalité du délai — 3 à 5 secondes est un bon compromis. Lorsqu’une attribution est en route, elle arrive généralement dans les quelques secondes qui suivent le lancement.

Si votre application écoute déjà didUpdateProfileStream à d’autres fins (par exemple, vérifier le statut d’un abonnement), vous n’avez pas besoin de le modifier. didUpdateProfileStream est un broadcast stream, ce qui lui permet de prendre en charge plusieurs écouteurs indépendants sans les affecter mutuellement.