Quick Actions Flutter : 10 minutes, gros impact

On passe souvent un temps indécent à peaufiner des "grosses features". Et puis, parfois, une micro-action planquée dans un coin te rappelle qu'en produit... le timing > la complexité.

Aujourd'hui on parle des Quick Actions : le menu qui apparaît quand tu fais un long press sur l'icône de ton app. En Flutter, avec le package quick_actions, tu peux les intégrer vite et les brancher à ton routing (GoRouter) sans te créer une mini-architecture du mal. (Dart packages)


1) Pourquoi ça marche

Les Quick Actions ont un super pouvoir : elles te permettent d'ajouter une action "haute valeur" sans ajouter un écran de plus dans un parcours déjà chargé.

Le meilleur usage : réduire la friction au moment où l'utilisateur est déjà en intention. Typiquement : il veut gérer son abonnement, restaurer un achat, contacter le support... ou "juste" accéder à une fonctionnalité clé.


2) C'est quoi une Quick Action (iOS) / App Shortcut (Android) ?

Sur iOS, Apple parle de Home Screen quick actions : des raccourcis vers des actions de ton app depuis l'écran d'accueil. Sur Android, le concept équivalent s'appuie sur les App Shortcuts (static / dynamic / pinned).

Et côté Flutter, quick_actions te donne 2 briques :

  • initialize() : un callback appelé quand l'app est lancée via un raccourci.
  • setShortcutItems() : la liste de tes actions (type, label, icône...).

3) Des exemples que tout le monde a déjà vus

Apple donne des exemples très parlants côté utilisateur :

  • Caméra → Selfie
  • Plans → Envoyer ma position
  • Notes → Nouvelle note

Le pattern est simple : ce ne sont pas des "features", ce sont des intentions fréquentes. Et ça t'aide à choisir les tiennes : une Quick Action doit faire gagner du temps à l'utilisateur.


4) Idées de Quick Actions

Un bon filtre : si l'utilisateur clique, est-ce que ça l'aide vraiment ? Si oui, tu peux te permettre un petit levier business au passage.

Idées orientées abonnement / revenus

  • "Offre spéciale -30%" → ouvre ton paywall avec une promo pré-sélectionnée.
  • "Passer en Premium" → ouvre ton écran d'upgrade (simple, clair, pas de dark pattern).
  • "Restaurer mes achats" → tu sauves des utilisateurs iOS/Android qui changent de tel (et donc des tickets support).

Idées orientées rétention / confiance

  • "Support / Signaler un bug" → ouvre un formulaire court (ou un chat si tu en as un).
  • "FAQ / Aide" → ouvre une page d'aide "top 5 questions".
  • "Donner mon avis" → ouvre ton écran feedback interne (et seulement ensuite tu pousses vers le store).

Côté Android, la doc recommande d'être sobre : même si l'API supporte jusqu'à 15 raccourcis (static + dynamic), ils recommandent d'en publier 4 pour une meilleure lisibilité.


5) Mise en place Flutter (avec GoRouter)

Objectif : du copier/coller qui marche, et un routing propre. On va faire un exemple "Offre abonnement" accessible depuis le long press.

Dépendances

dependencies:
  quick_actions: ^1.1.0 # (check la version au moment d'écrire)
  go_router: ^14.0.0

quick_actions sert à déclarer et écouter les actions. go_router sert à router proprement vers un écran (avec paramètres si besoin).

Le router (GoRouter)

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

final GoRouter router = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (context, state) => const HomeScreen(),
    ),
    GoRoute(
      path: '/paywall',
      builder: (context, state) {
        final offer = state.uri.queryParameters['offer']; // ex: discount30
        final src = state.uri.queryParameters['src'];     // ex: quick_action
        return PaywallScreen(offer: offer, source: src);
      },
    ),
    GoRoute(
      path: '/support',
      builder: (context, state) => const SupportScreen(),
    ),
  ],
);

GoRouter gère routes, query params, deep links, etc.

Brancher les Quick Actions + navigation

import 'package:flutter/material.dart';
import 'package:quick_actions/quick_actions.dart';

class AppBootstrap extends StatefulWidget {
  const AppBootstrap({super.key});

  @override
  State<AppBootstrap> createState() => _AppBootstrapState();
}

class _AppBootstrapState extends State<AppBootstrap> {
  final QuickActions _quickActions = const QuickActions();

  @override
  void initState() {
    super.initState();

    // 1) Écoute des actions (à init le plus tôt possible)
    _quickActions.initialize((String shortcutType) {
      // Évite de naviguer "au mauvais moment" (app pas encore rendue)
      WidgetsBinding.instance.addPostFrameCallback((_) {
        _handleQuickAction(shortcutType);
      });
    });

    // 2) Déclaration des actions
    _quickActions.setShortcutItems(const <ShortcutItem>[
      ShortcutItem(
        type: 'offer_discount',
        localizedTitle: 'Offre -30%',
        icon: 'ic_discount', // ressource native (iOS xcassets / Android drawable)
      ),
      ShortcutItem(
        type: 'support',
        localizedTitle: 'Support',
        icon: 'ic_support',
      ),
    ]);
  }

  void _handleQuickAction(String type) {
    switch (type) {
      case 'offer_discount':
        router.go('/paywall?offer=discount30&src=quick_action');
        break;
      case 'support':
        router.go('/support?src=quick_action');
        break;
      default:
        // no-op
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: router,
    );
  }
}

Le package recommande d'initialiser tôt, et rappelle que :

  • type doit être unique.
  • icon doit être le nom d'une ressource native (xcassets iOS / drawable Android).

Si tu veux voir un exemple minimal "officiel", l'exemple du package montre exactement ce duo initialize() + setShortcutItems().


6) Les pièges classiques (et comment ne pas y passer ta soirée)

Android : ça compile en SDK 16+, mais...

Le plugin tourne sur Android SDK 16+, mais les shortcuts sont un no-op en dessous d'Android 7.1 (SDK 25). Donc : ne base pas un parcours critique sur ça, et prévois un fallback (bouton dans l'app, menu profil, etc.).

Les icônes qui disparaissent en release

Si tes drawables Android ne sont référencés "que" dans du Dart, le shrinker peut les virer. Le README du package le mentionne et renvoie vers la doc Android pour "garder" explicitement ces ressources.

Navigation trop tôt (cold start)

Quand l'app est lancée via Quick Action, tu peux recevoir le callback très vite. Le addPostFrameCallback dans l'exemple évite les cas où tu navigues avant que le router soit prêt.


7) Mesurer l'impact (sinon c'est juste "sympa")

Si tu veux savoir si ta Quick Action "Offre -30%" sert à quelque chose, vise simple :

  • quick_action_triggered (type)
  • paywall_viewed (source=quick_action, offer=discount30)
  • purchase_completed (source=quick_action)

Ensuite, tu compares :

  • taux de conversion paywall avec src=quick_action
  • taux d'usage de la Quick Action (par semaine)
  • impact support (si tu ajoutes un raccourci "Support")

8) Checklist et conclusion

Si tu devais retenir une règle : 4 actions max, et chacune doit être défendable en une phrase. Tes labels doivent être courts, et tes actions doivent mener à une page qui "fait le job" direct.

Checklist :

  • 2 à 4 Quick Actions max
  • icônes natives OK (iOS + Android)
  • navigation safe (post-frame)
  • tracking minimal (3 events)
  • action "business" seulement si elle apporte aussi de la valeur (sinon ça se voit)

Liens utiles

Tags

  • flutter
  • mobile
  • quick-actions
  • go-router
  • flutter-package

Cet article à été posté le