Activer les achats avec Flow & Paywall Builder dans le SDK Flutter
Pour activer les achats intégrés, vous devez comprendre trois concepts clés :
- Produits – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie)
- Flows – des séquences d’écrans qui présentent les produits aux utilisateurs, créées dans le Flow & Paywall Builder sans code. Le SDK les récupère via
getFlow. Si vous préférez créer l’interface dans votre propre code, utilisez plutôt un paywall — voir Implémenter les paywalls manuellement. - Placements – où et quand vous affichez les flows dans votre application (par exemple
main,onboarding,settings). Vous associez les flows aux placements dans le tableau de bord, puis vous les demandez par identifiant de placement dans votre code. Cela facilite les tests A/B et l’affichage de flows différents selon les utilisateurs.
Adapty vous propose trois façons d’activer les achats dans votre application. Choisissez celle qui correspond à vos besoins :
| Implémentation | Complexité | Quand l’utiliser |
|---|---|---|
| Adapty Flow & Paywall Builder | ✅ Facile | Vous créez un flow complet et prêt à l’achat dans le builder no-code. Adapty l’affiche automatiquement et gère toute la logique d’achat, la validation des reçus et la gestion des abonnements en coulisses. |
| Paywalls créées manuellement | 🟡 Moyen | Vous implémentez l’interface de votre paywall dans le code de votre application, mais récupérez tout de même l’objet flow depuis Adapty pour garder de la flexibilité dans vos offres de produits. Consultez le guide. |
| Mode observateur | 🔴 Difficile | Vous disposez déjà de votre propre infrastructure de gestion des achats et souhaitez continuer à l’utiliser. Notez que le mode observateur présente certaines limitations dans Adapty. Consultez l’article. |
Les étapes ci-dessous montrent comment implémenter un flow créé dans l’Adapty Flow & Paywall Builder.
Si vous préférez créer l’interface du paywall vous-même, consultez Implémenter les paywalls manuellement.
Pour afficher un flow créé dans l’Adapty Flow & Paywall Builder, dans le code de votre application, vous n’avez qu’à :
- Récupérer le flow : Récupérez-le depuis Adapty.
- L’afficher et laisser Adapty gérer les achats : Affichez la vue dans votre app.
- Gérer les actions des boutons : Associez les interactions utilisateur aux réponses de votre app. Par exemple, ouvrir des liens ou fermer le flow lorsque l’utilisateur clique sur un bouton.
Avant de commencer
Avant de commencer, effectuez les étapes suivantes :
- Connectez votre application à l’App Store et/ou à Google Play dans l’Adapty Dashboard.
- Créez vos produits dans Adapty.
- Créez un flow et ajoutez-y des produits.
- Créez un placement et ajoutez-y votre flow.
- Installez et activez le SDK Adapty dans le code de votre application. Ce guide utilise les API du SDK Adapty Flutter v4.
Le moyen le plus rapide d’effectuer ces étapes est de suivre le guide de démarrage rapide ou de créer des paywalls et des placements à l’aide du CLI développeur.
1. Récupérer le flow
Vos flows sont associés à des placements configurés dans le tableau de bord. Les placements vous permettent d’afficher différents flows pour différentes audiences ou de lancer des tests A/B.
Pour récupérer un flow créé dans l’Adapty Flow & Paywall Builder, vous devez :
-
Récupérer l’objet
flowpar l’identifiant du placement en utilisant la méthodegetFlow, puis vérifier s’il a été créé dans le builder grâce à la propriétéhasViewConfiguration. -
Créer la vue du flow à l’aide de la méthode
createFlowView. La vue contient les éléments d’interface et le style nécessaires à l’affichage du flow.
Pour obtenir la configuration de la vue, publiez le flow. Un flow avec des modifications non publiées a le statut Dirty, et son placement continue de servir la dernière version publiée.
try {
// the requested flow
final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID');
final view = await AdaptyUI().createFlowView(
flow: flow,
);
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
// handle the error
}
2. Afficher le flow
Maintenant que vous avez la vue du flow, il suffit d’ajouter quelques lignes pour l’afficher.
Pour afficher le flow, utilisez la méthode view.present() sur la view créée par la méthode createFlowView. Chaque view ne peut être présentée qu’une seule fois : une fois fermée, la vue est libérée de la mémoire. Si vous avez besoin d’afficher le flow à nouveau, appelez createFlowView une nouvelle fois pour créer une nouvelle instance de view.
try {
await view.present();
} on AdaptyError catch (e) {
// handle the error
} catch (e) {
// handle the error
}
Pour plus de détails sur l’affichage d’un flow, consultez notre guide.
3. Gérer les actions des boutons
Lorsque les utilisateurs cliquent sur des boutons dans le flow, le SDK Flutter gère automatiquement les achats, la restauration, la fermeture de la vue et l’ouverture des URLs. Cependant, les autres boutons ont des IDs personnalisés ou prédéfinis et nécessitent une gestion des actions dans votre code.
Pour contrôler ou surveiller les processus sur l’écran du flow, implémentez les méthodes AdaptyUIFlowsEventsObserver et définissez l’observateur avant d’afficher tout écran. Si un utilisateur a effectué une action, la méthode flowViewDidPerformAction sera invoquée, et votre application doit réagir en fonction de l’ID de l’action.
Les trois méthodes d’observation sont obligatoires : flowViewDidFinishPurchase, flowViewDidFinishRestore et flowViewDidReceiveError — votre classe ne compilera pas sans elles.
Consultez nos guides sur la gestion des actions et des événements de boutons.
Implémentez l’observer comme un objet dédié et à longue durée de vie plutôt qu’un widget. Comme un seul emplacement d’observer global est partagé dans toute l’application, le lier à un State provoquerait une fuite mémoire (le SDK conserve une référence forte vers lui) et serait silencieusement remplacé dès que l’écran suivant s’enregistre. Utiliser extends hérite également du comportement par défaut du SDK, donc en dehors des trois méthodes requises, vous ne surchargez que les callbacks qui vous intéressent.
// A dedicated, long-lived handler for flow events.
// It does NOT live inside a Widget/State, so it never leaks and is never
// silently replaced when screens are pushed or popped.
class FlowEventsHandler extends AdaptyUIFlowsEventsObserver {
// A single, app-wide instance — same idiom as Adapty() and AdaptyUI().
static final FlowEventsHandler _instance = FlowEventsHandler._();
factory FlowEventsHandler() => _instance;
FlowEventsHandler._();
// This method is called when user performs an action on the flow UI.
// Overriding it replaces the default behavior (dismiss on close, open URLs),
// so keep those cases if you want to preserve it.
@override
void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) {
switch (action) {
case const CloseAction():
case const AndroidSystemBackAction(): // close the flow on the Android back button
view.dismiss();
break;
case OpenUrlAction(:final url, :final openIn):
AdaptyUI().openUrl(url, openIn: openIn);
break;
default:
break;
}
}
// Required: decide what happens after a purchase finishes
@override
void flowViewDidFinishPurchase(AdaptyUIFlowView view,
AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) {
if (purchaseResult is! AdaptyPurchaseResultUserCancelled) {
view.dismiss();
}
}
// Required: dismiss the flow once a restore succeeds
@override
void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) {
view.dismiss();
}
// Required: handle rendering and other view errors
@override
void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) {
print('Flow error: $error');
view.dismiss();
}
}
Enregistrez le handler une seule fois au démarrage de l’application, avant qu’un flow ne soit affiché :
AdaptyUI().setFlowsEventsObserver(FlowEventsHandler());
Étapes suivantes
Des questions ou des problèmes ? Consultez notre forum d’assistance où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider !
Votre flow est prêt à être affiché dans l’application. Testez vos achats dans le sandbox App Store ou dans le Google Play Store pour vous assurer de pouvoir effectuer un achat test depuis le flow.
Vous devez maintenant vérifier le niveau d’accès des utilisateurs pour vous assurer d’afficher un flow ou de donner accès aux fonctionnalités payantes aux bons utilisateurs.
Exemple complet
Voici comment intégrer toutes ces étapes dans votre application.
void main() {
// Register a single, long-lived observer once, before any flow is shown.
// It is intentionally a plain object (NOT a Widget/State): its lifetime is the
// whole app, so it never leaks and is never silently replaced when screens are
// pushed or popped.
AdaptyUI().setFlowsEventsObserver(FlowEventsHandler());
runApp(MaterialApp(home: FlowScreen()));
}
/// A dedicated handler for AdaptyUI flow events.
///
/// It `extends` [AdaptyUIFlowsEventsObserver] (rather than being implemented
/// by a `State`), which gives you two things for free:
/// * the SDK's sensible defaults for optional callbacks, so besides the three
/// required methods you only override what you actually care about;
/// * a lifecycle that is independent of the widget tree — there is no strong
/// reference back into a `Widget`, so nothing leaks and there is nothing to
/// unregister.
///
/// Every callback receives the [AdaptyUIFlowView] it relates to, so handling
/// flow actions never requires a `BuildContext` or widget state.
class FlowEventsHandler extends AdaptyUIFlowsEventsObserver {
// A single, app-wide instance — same idiom as Adapty() and AdaptyUI().
static final FlowEventsHandler _instance = FlowEventsHandler._();
factory FlowEventsHandler() => _instance;
FlowEventsHandler._();
// Called when the user performs an action on the flow UI.
@override
void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) {
switch (action) {
case const CloseAction():
case const AndroidSystemBackAction(): // close the flow on the Android back button
view.dismiss();
break;
case OpenUrlAction(:final url, :final openIn):
// Open the URL natively, honoring the dashboard browser setting.
AdaptyUI().openUrl(url, openIn: openIn);
break;
default:
break;
}
}
// Required: decide what happens after a purchase finishes.
@override
void flowViewDidFinishPurchase(AdaptyUIFlowView view,
AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) {
if (purchaseResult is! AdaptyPurchaseResultUserCancelled) {
view.dismiss();
}
}
// Required: dismiss the flow once a restore succeeds.
@override
void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) {
view.dismiss();
}
// Required: handle rendering and other view errors.
@override
void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) {
print('Flow error: $error');
view.dismiss();
}
}
class FlowScreen extends StatefulWidget {
const FlowScreen({super.key});
@override
State<FlowScreen> createState() => _FlowScreenState();
}
class _FlowScreenState extends State<FlowScreen> {
@override
void initState() {
super.initState();
_showFlowIfNeeded();
}
Future<void> _showFlowIfNeeded() async {
try {
final flow = await Adapty().getFlow(
placementId: 'YOUR_PLACEMENT_ID',
);
if (!flow.hasViewConfiguration) return;
final view = await AdaptyUI().createFlowView(flow: flow);
await view.present();
} catch (_) {
// Handle any errors (network, SDK issues, etc.)
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Adapty Flow Example')),
body: Center(
// Add a button to re-trigger the flow for testing purposes.
child: ElevatedButton(
onPressed: _showFlowIfNeeded,
child: const Text('Show Flow'),
),
),
);
}
}