ITSkillsCenter
Blog

Flutter tutoriel PME : démarrer concrètement 2026

12 min de lecture

Lecture : 12 minutes · Niveau : intermédiaire · Mise à jour : avril 2026

Flutter est l’un des frameworks mobiles cross-platform les plus matures. Ce tutoriel pratique amène une équipe PME (ou un dev solo) du zéro à une première app fonctionnelle : installation, premier projet, widgets essentiels, gestion d’état, appel API, build APK pour Play Store et IPA pour App Store. L’objectif est de poser des fondations solides en quelques heures de pratique.

Avant de plonger dans le code, un mot sur la philosophie de Flutter qui détermine la façon de penser le développement. Tout en Flutter est widget : un texte, un bouton, un layout, mais aussi un padding, une marge, une animation. Cette approche déroute au début si l’on vient du développement web où l’on sépare HTML, CSS et JavaScript. En Flutter, l’arbre des widgets décrit à la fois la structure, le style et le comportement. Une fois cette logique acquise, la productivité est élevée car tout se fait au même endroit, dans un même langage, avec une même grammaire.

L’autre concept clé est la composition. Plutôt qu’hériter de classes complexes ou utiliser des configurations multiples, Flutter encourage à construire des écrans en imbriquant de petits widgets simples. Un bouton avec icône et texte n’est pas un widget monolithique « IconButton » mais une composition d’un Row contenant une Icon et un Text, le tout enveloppé dans un Padding et un GestureDetector. Cette approche modulaire produit du code lisible et réutilisable.

Voir aussi → Application mobile pour PME : guide complet et Flutter vs React Native : comparatif détaillé.


Sommaire

  1. Installation de Flutter
  2. Premier projet et structure
  3. Comprendre les widgets
  4. Stateless vs Stateful
  5. Layout : Row, Column, Stack
  6. Navigation entre écrans
  7. Gestion d’état avec Provider
  8. Appel API REST avec http
  9. Persistance locale avec shared_preferences
  10. Build APK pour Play Store
  11. Build IPA pour App Store
  12. FAQ

1. Installation de Flutter

Pré-requis : Windows, macOS ou Linux. 8 Go de RAM minimum recommandés. 20-30 Go d’espace disque pour Flutter SDK + Android Studio + émulateurs.

Étapes Windows :

  1. Télécharger Flutter SDK depuis flutter.dev/docs/get-started/install
  2. Décompresser dans C:\flutter (éviter les chemins avec espaces ou caractères spéciaux)
  3. Ajouter C:\flutter\bin au PATH système
  4. Installer Android Studio (inclut le SDK Android, Android Emulator, et le plugin Flutter recommandé)
  5. Installer Visual Studio Code avec l’extension Flutter (alternative plus légère)
  6. Vérifier l’installation :
flutter doctor

flutter doctor liste les dépendances manquantes. Suivre chaque ligne [!] ou [X] pour résoudre.

Pour iOS (macOS uniquement) :
– Installer Xcode depuis le Mac App Store
– Accepter la licence : sudo xcodebuild -license accept
– Installer CocoaPods : sudo gem install cocoapods

Choisir son éditeur : Android Studio offre une intégration profonde (debugger, profiler, émulateur Android intégré) mais consomme plus de ressources. Visual Studio Code avec l’extension Flutter est plus léger et suffit largement pour la majorité du développement quotidien. Beaucoup de développeurs Flutter utilisent VS Code par défaut et lancent Android Studio occasionnellement pour des tâches spécifiques comme le débogage avancé du code natif Android.

Configurer un émulateur Android : depuis Android Studio, ouvrir le Device Manager, créer un nouveau Virtual Device. Choisir un modèle proche du parc utilisateur cible (Pixel 4 ou Galaxy A pour rester réaliste avec une cible PME ouest-africaine). Privilégier une image système récente avec Google Play. L’émulateur consomme beaucoup de RAM, prévoir au moins 16 Go sur la machine de développement pour une expérience fluide.

Configurer un émulateur iOS (macOS uniquement) : Xcode propose des simulateurs iOS pré-installés. Lancer le Simulator depuis le menu Xcode ou la commande open -a Simulator. Tester sur plusieurs tailles d’écran (iPhone SE pour les petits écrans, iPhone Pro Max pour les grands).


2. Premier projet et structure

Créer un projet :

flutter create mon_app
cd mon_app
flutter run

flutter run lance l’app sur le device connecté ou l’émulateur ouvert. Hot Reload : modifier un fichier, sauvegarder, l’app se met à jour instantanément.

Structure typique d’un projet Flutter :

mon_app/
├── android/         # Code natif Android
├── ios/             # Code natif iOS
├── lib/             # Code Dart de l'app
│   └── main.dart    # Point d'entrée
├── test/            # Tests unitaires
├── pubspec.yaml     # Dépendances et assets
└── README.md

pubspec.yaml est l’équivalent du package.json de Node.js. On y déclare les dépendances et les fichiers d’assets (images, polices).


3. Comprendre les widgets

En Flutter, tout est widget. Texte, bouton, layout, padding, écran complet : chaque élément visible (et même certains invisibles comme Padding) est un widget.

Exemple minimal lib/main.dart :

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Mon App',
      home: Scaffold(
        appBar: AppBar(title: const Text('Bienvenue')),
        body: const Center(
          child: Text('Hello PME', style: TextStyle(fontSize: 24)),
        ),
      ),
    );
  }
}

Widgets essentiels à connaître :
Container : conteneur avec padding, margin, decoration
Text : afficher du texte
Row, Column : disposition horizontale et verticale
Stack : superposition d’éléments
Image.network, Image.asset : images réseau ou locales
ElevatedButton, TextButton, IconButton : boutons
TextField : champ de saisie
ListView, GridView : listes scrollables


4. Stateless vs Stateful

StatelessWidget : widget sans état interne. Affiche selon les paramètres reçus. Exemple : un titre, un logo, un bouton statique.

StatefulWidget : widget avec état mutable. Quand l’état change, le widget se reconstruit automatiquement. Exemple : un compteur, un formulaire avec validation, une liste qui se met à jour.

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

  @override
  State<Compteur> createState() => _CompteurState();
}

class _CompteurState extends State<Compteur> {
  int _valeur = 0;

  void _incrementer() {
    setState(() {
      _valeur++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text('Compteur : $_valeur', style: const TextStyle(fontSize: 32)),
        ElevatedButton(
          onPressed: _incrementer,
          child: const Text('Ajouter 1'),
        ),
      ],
    );
  }
}

setState() est l’appel qui dit à Flutter « l’état a changé, redessine ce widget ».


5. Layout : Row, Column, Stack

Column : empile verticalement. Row : aligne horizontalement. Stack : superpose en couches.

Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    const Text('Titre', style: TextStyle(fontSize: 24)),
    const SizedBox(height: 8),
    Row(
      children: [
        const Icon(Icons.person),
        const SizedBox(width: 8),
        const Text('Auteur'),
      ],
    ),
  ],
)

Astuces :
SizedBox(height: 8) ou SizedBox(width: 8) : espacement simple
Expanded : prend tout l’espace disponible dans Row ou Column
Padding : marge intérieure
Container(decoration: BoxDecoration(...)) : bordures, fonds, ombres

Comprendre la contrainte de layout Flutter : la phrase mantra à mémoriser est « Constraints go down. Sizes go up. Parent sets position. » Le widget parent passe des contraintes (largeur min/max, hauteur min/max) à ses enfants. Chaque enfant choisit sa taille dans ces contraintes et la communique au parent. Le parent positionne ensuite ses enfants. Cette logique explique beaucoup d’erreurs de layout courantes : un widget qui ne s’affiche pas comme attendu est presque toujours dû à des contraintes mal comprises. Quand on bloque sur un layout, ouvrir le widget inspector des DevTools pour visualiser la contrainte exacte appliquée à chaque widget permet de débloquer rapidement.

Éviter les erreurs courantes de layout : une erreur fréquente pour les débutants est d’utiliser un Column dans une ListView ou un Row sans Expanded, ce qui produit des erreurs de overflow. La règle de base : dans une ListView, les enfants peuvent avoir une hauteur arbitraire car la ListView est scrollable. Dans un Column non scrollable, l’espace disponible est fini et il faut soit limiter explicitement les enfants, soit envelopper la Column dans un SingleChildScrollView pour autoriser le scroll vertical.


6. Navigation entre écrans

// Naviguer vers un nouvel écran
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => const PageDetail()),
);

// Revenir en arrière
Navigator.pop(context);

Pour des apps avec plusieurs écrans, utiliser un système de routes nommées :

MaterialApp(
  initialRoute: '/',
  routes: {
    '/': (context) => const Accueil(),
    '/detail': (context) => const Detail(),
    '/profil': (context) => const Profil(),
  },
)

// Navigation
Navigator.pushNamed(context, '/detail');

Pour des apps complexes, le package go_router (officiel) offre une navigation déclarative plus puissante.


7. Gestion d’état avec Provider

Pour partager un état entre plusieurs écrans (panier, utilisateur connecté, langue), setState ne suffit pas. Provider est la solution recommandée par défaut côté Flutter.

Ajouter dans pubspec.yaml :

dependencies:
  provider: ^6.1.0
flutter pub get

Définir un ChangeNotifier :

import 'package:flutter/foundation.dart';

class PanierStore extends ChangeNotifier {
  final List<String> _items = [];
  List<String> get items => _items;

  void ajouter(String item) {
    _items.add(item);
    notifyListeners();
  }

  void vider() {
    _items.clear();
    notifyListeners();
  }
}

Wrapper l’app avec Provider :

import 'package:provider/provider.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => PanierStore(),
      child: const MyApp(),
    ),
  );
}

Consommer dans un widget :

final panier = context.watch<PanierStore>();
return Text('Articles : ${panier.items.length}');

Alternatives populaires : Riverpod (plus puissant), Bloc (architecture plus stricte). Pour démarrer, Provider suffit largement.


8. Appel API REST avec http

dependencies:
  http: ^1.1.0
import 'package:http/http.dart' as http;
import 'dart:convert';

Future<List<dynamic>> chargerProduits() async {
  final url = Uri.parse('https://api.example.com/produits');
  final response = await http.get(url);

  if (response.statusCode == 200) {
    return jsonDecode(response.body) as List<dynamic>;
  } else {
    throw Exception('Erreur de chargement (${response.statusCode})');
  }
}

Affichage avec FutureBuilder :

FutureBuilder<List<dynamic>>(
  future: chargerProduits(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const CircularProgressIndicator();
    }
    if (snapshot.hasError) {
      return Text('Erreur : ${snapshot.error}');
    }
    final produits = snapshot.data!;
    return ListView.builder(
      itemCount: produits.length,
      itemBuilder: (context, i) => ListTile(
        title: Text(produits[i]['nom']),
        subtitle: Text('${produits[i]['prix']} FCFA'),
      ),
    );
  },
)

Pour des projets plus sérieux : dio offre plus de fonctionnalités (intercepteurs, retry, timeout fin).


9. Persistance locale avec shared_preferences

Pour stocker des préférences simples (token de session, langue choisie) :

dependencies:
  shared_preferences: ^2.2.0
import 'package:shared_preferences/shared_preferences.dart';

Future<void> sauverToken(String token) async {
  final prefs = await SharedPreferences.getInstance();
  await prefs.setString('auth_token', token);
}

Future<String?> lireToken() async {
  final prefs = await SharedPreferences.getInstance();
  return prefs.getString('auth_token');
}

Pour des données plus structurées : sqflite (SQLite local) ou hive (NoSQL local rapide).


10. Build APK pour Play Store

Préparer la signature :

  1. Générer une clé de signature :
keytool -genkey -v -keystore upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload

Garder ce fichier précieusement. Sa perte rend impossible la mise à jour de l’app sur Play Store.

  1. Créer android/key.properties (ne pas commiter) :
storePassword=motdepasse
keyPassword=motdepasse
keyAlias=upload
storeFile=../upload-keystore.jks
  1. Configurer android/app/build.gradle pour utiliser cette clé en mode release (suivre la doc officielle Flutter pour le détail exact).

Construire l’AAB (recommandé par Google) :

flutter build appbundle --release

Le fichier produit est dans build/app/outputs/bundle/release/app-release.aab. C’est ce fichier à uploader sur Play Console.

Construire un APK (pour tests directs) :

flutter build apk --release --split-per-abi

Cela génère plusieurs APK plus légers (un par architecture CPU).


11. Build IPA pour App Store

Pré-requis : Mac avec Xcode installé, compte développeur Apple actif (abonnement annuel).

flutter build ios --release

Ouvrir ios/Runner.xcworkspace dans Xcode. Configurer :
– Bundle Identifier (ex. : com.monentreprise.monapp)
– Team de signature
– Icônes et launch screen

Dans Xcode : Product > Archive. Une fois l’archive créée, utiliser l’Organizer pour distribuer vers App Store Connect.

Alternative cloud : Codemagic ou Bitrise permettent de faire les builds iOS sans Mac local. Configurer le projet dans leur interface, push sur Git, le build et l’upload App Store se font automatiquement.


FAQ

Faut-il connaître Java ou Kotlin pour développer en Flutter ?

Non. Flutter utilise Dart et abstrait les API natives via des plugins. Connaître quelques bases d’Android (cycles de vie, permissions) aide pour le débogage avancé mais n’est pas obligatoire pour démarrer.

Quelle différence entre flutter run et flutter build ?

flutter run lance l’app en mode debug sur un device connecté ou émulateur, avec Hot Reload. flutter build génère un binaire de production (AAB, APK, IPA) optimisé et signé pour distribution.

Comment tester sur un vrai téléphone Android ?

Activer le mode développeur sur le téléphone (tapoter 7 fois sur le numéro de build dans les paramètres), activer le débogage USB, brancher au PC. flutter devices doit lister le téléphone, puis flutter run lance dessus.

L’app Flutter consomme-t-elle plus de batterie qu’une app native ?

La différence est marginale en pratique pour la plupart des cas d’usage. Le moteur de rendu Flutter est performant. Les vraies causes de consommation excessive sont les mêmes que pour une app native : géolocalisation continue mal gérée, requêtes réseau en boucle, animations non optimisées.

Comment gérer plusieurs langues en Flutter ?

Utiliser le package flutter_localizations (officiel) avec des fichiers ARB ou JSON par langue. Le package intl complète pour le formatage des dates et nombres selon la locale. Pour des projets simples, une simple Map de chaînes traduites peut suffire.

Combien de temps pour devenir productif en Flutter ?

Pour un dev expérimenté venant d’un autre framework : 2-4 semaines de pratique pour produire des écrans propres. Pour un dev junior : compter 2-3 mois pour une vraie autonomie. La courbe est raisonnable comparée à du natif Android + iOS séparé.

Les apps Flutter sont-elles bien acceptées sur l’App Store ?

Oui, des centaines de milliers d’apps Flutter sont publiées sur l’App Store. Apple ne distingue pas le framework utilisé tant que les guidelines sont respectées. Soigner l’adaptation iOS (widgets Cupertino, transitions iOS, gestes) aide à passer la revue Apple.


Articles liés (cluster Mobile)

Voir aussi : Strapi headless CMS pour PME pour le backend de l’app, TypeScript JavaScript moderne pour les concepts de typage applicables à Dart.


Article mis à jour le 25 avril 2026. Pour signaler une erreur ou suggérer une amélioration, écrivez-nous.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité