Activer les achats avec Flow 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 des produits aux utilisateurs, créées dans le Flow Builder sans code. Le SDK les récupère via
getFlow. Si vous préférez construire l’interface dans votre propre code, utilisez un paywall à la place — 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 ID 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 aux besoins de votre app :
| Implémentation | Complexité | Quand l’utiliser |
|---|---|---|
| Adapty Flow Builder | ✅ Facile | Vous créez un flow complet et prêt à l’achat dans le builder sans code. Adapty le rend automatiquement et gère tout le flux d’achat complexe, la validation des reçus et la gestion des abonnements en coulisses. |
| Paywalls créés manuellement | 🟡 Moyen | Vous implémentez l’interface de votre paywall dans le code de votre application, mais vous récupérez quand même l’objet flow depuis Adapty pour garder de la flexibilité dans les offres de produits. Voir le guide. |
| Mode observateur | 🔴 Difficile | Vous avez déjà votre propre infrastructure de gestion des achats et souhaitez continuer à l’utiliser. Notez que le mode observateur a ses limites dans Adapty. Voir l’article. |
Les étapes ci-dessous montrent comment implémenter un flow créé dans Adapty Flow Builder.
Si vous préférez construire l’interface du paywall vous-même, voir Implémenter les paywalls manuellement.
Pour afficher un flow créé dans Adapty Flow Builder, vous n’avez besoin que de quelques lignes dans le code de votre application :
- Récupérer le flow : Obtenez-le depuis Adapty.
- L’afficher et laisser Adapty gérer les achats : Affichez la vue dans votre application.
- Gérer les actions des boutons : Associez les interactions utilisateur aux réponses de votre application. Par exemple, ouvrir des liens ou fermer le flow quand les utilisateurs cliquent sur des boutons.
Avant de commencer
Avant de commencer, effectuez ces étapes :
- Connectez votre application à l’App Store et/ou à Google Play dans 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 APIs du SDK Adapty Flutter v4.
La façon la plus rapide de réaliser ces étapes est de suivre le guide de démarrage rapide ou de créer des paywalls et des placements via la 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’exécuter des flows différents pour différentes audiences ou de lancer des tests A/B.
Pour récupérer un flow créé dans Adapty Flow Builder, vous devez :
-
Obtenir l’objet
flowpar l’ID de placement en utilisant la méthodegetFlowet vérifier s’il a été créé dans le builder grâce à la propriétéhasViewConfiguration. -
Créer la vue du flow en utilisant la méthode
createFlowView. La vue contient les éléments d’interface et le style nécessaires pour afficher le flow.
Pour obtenir la configuration de la vue, vous devez activer le bouton Show on device dans le builder. Sinon, vous obtiendrez une configuration de vue vide et le flow ne sera pas affiché.
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, quelques lignes suffisent 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, elle 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
Quand 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 n’importe quel écran. Si un utilisateur a effectué une action, flowViewDidPerformAction sera appelé et votre application devra répondre en fonction de l’ID de l’action.
Trois méthodes d’observateur 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 des boutons.
Implémentez l’observateur comme un objet dédié à longue durée de vie plutôt que comme un widget. Comme un seul slot d’observateur global est partagé dans toute l’application, le lier à un State entraînerait une fuite de l’écran (le SDK conserve une référence forte vers lui) et serait silencieusement remplacé lorsque le prochain écran s’enregistre. Utiliser extends hérite également du comportement par défaut du SDK, donc en dehors des trois méthodes obligatoires, 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 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 toutes ces étapes peuvent être intégrées ensemble 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'),
),
),
);
}
}