Claude Code pour Flutter/Dart : cartographie, état, tests et builds
Guide pratique Claude Code avec Flutter/Dart : pubspec, widgets, état, tests, builds et vérification device.
Claude Code est surtout utile en Flutter/Dart quand il travaille comme un partenaire qui comprend le projet, pas comme un générateur de widget isolé. Une modification réelle peut toucher lib/, pubspec.yaml, les assets, les tests, Android, iOS, le Web, les émulateurs et les commandes de build. Un widget est une brique d’interface, le state est la donnée qui change l’affichage, et le pubspec est le fichier qui déclare les dépendances, ressources et contraintes de SDK.
L’exemple de cet article est un petit écran de panier. Il est assez court pour être collé dans un projet flutter create, mais il expose des erreurs courantes : créer l’état dans build, ajouter un package sans nécessité, oublier les widget tests, ou supposer qu’Android, iOS et Web ont les mêmes contraintes.
Gardez les références officielles ouvertes : Flutter CLI, Flutter testing, Widget testing, Flutter pubspec options, Dart pubspec, Platform channels et Claude Code common workflows. À lire aussi : React Native, stratégies de test et bonnes pratiques CLAUDE.md.
Cartographier avant de modifier
Ne commencez pas par “construis un écran panier”. Demandez d’abord à Claude Code d’inspecter le dépôt sans modifier. Ce harness, ou cadre de travail sûr, précise les fichiers autorisés, les limites, les commandes et les critères de revue.
Lis d'abord ce projet Flutter.
Ne modifie aucun fichier pour l'instant.
Rapporte :
1. Contraintes SDK, dépendances et assets dans pubspec.yaml
2. Organisation UI, état et couche data sous lib/
3. Style de tests existant dans test/ et integration_test/
4. Targets actifs dans android/, ios/, web/, macos/, windows/ et linux/
5. Présence de flutter analyze, flutter test et commandes de build
Termine par les fichiers modifiables et ceux à éviter.
| Zone | Claude Code peut faire | Décision humaine |
|---|---|---|
| Carte projet | Conventions, dépendances, tests | Limites de modification |
| Widget | Composant, accessibilité, responsive | Texte produit et design |
| État | Respecter setState, ChangeNotifier, Riverpod, Bloc ou le style existant | Stratégie d’état globale |
| pubspec | Proposer dépendances et assets | Accepter ou refuser un package |
| Plateforme | Différences Android/iOS/Web/Desktop | Cibles supportées |
| Tests/build | Widget test, integration test, commandes | Décision de merge et release |
Garder pubspec maîtrisé
pubspec.yaml contrôle les dépendances, assets, contraintes SDK et packages de test. Avant toute édition, Claude Code doit justifier le changement, proposer une alternative, nommer les fichiers touchés et donner les commandes de vérification.
name: cart_ai_demo
description: A small Flutter cart screen used to verify Claude Code prompts.
publish_to: "none"
environment:
sdk: ">=3.4.0 <4.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
integration_test:
sdk: flutter
flutter_lints: ^6.0.0
flutter:
uses-material-design: true
assets:
- assets/images/
Pour un sandbox neuf, créez une base propre. Dans un dépôt existant, demandez à Claude Code d’adapter ces commandes au projet.
flutter create cart_ai_demo
cd cart_ai_demo
flutter pub get
flutter analyze
flutter test
Les erreurs fréquentes sont l’indentation cassée sous assets, le changement inutile de pubspec.lock, et l’ajout d’une bibliothèque d’état pour une interaction simple. Utilisez un prompt strict :
Inspecte pubspec.yaml et détermine si le changement panier exige une nouvelle dépendance.
Avant d'éditer, donne raison, alternatives, fichiers affectés et commandes de vérification.
Ne modifie pas pubspec.yaml ni pubspec.lock sans validation.
Modifier widget et état ensemble
Le code suivant peut remplacer lib/main.dart dans un projet flutter create cart_ai_demo. Il n’utilise que le SDK Flutter. CartController porte les mutations d’état, tandis que le widget affiche l’état courant.
import 'package:flutter/material.dart';
void main() => runApp(const CartDemoApp());
class CartDemoApp extends StatelessWidget {
const CartDemoApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Cart AI Demo',
theme: ThemeData(colorSchemeSeed: Colors.teal, useMaterial3: true),
home: const CartSummaryPage(),
);
}
}
class CartLine {
const CartLine({required this.name, required this.price, required this.quantity});
final String name;
final int price;
final int quantity;
CartLine copyWith({int? quantity}) =>
CartLine(name: name, price: price, quantity: quantity ?? this.quantity);
}
class CartController extends ChangeNotifier {
final List<CartLine> _lines = const [
CartLine(name: 'Dart notebook', price: 1800, quantity: 1),
CartLine(name: 'Flutter sticker', price: 500, quantity: 2),
].toList();
List<CartLine> get lines => List.unmodifiable(_lines);
int get total => _lines.fold(0, (sum, line) => sum + line.price * line.quantity);
void increment(int index) {
final line = _lines[index];
_lines[index] = line.copyWith(quantity: line.quantity + 1);
notifyListeners();
}
void decrement(int index) {
final line = _lines[index];
if (line.quantity == 1) return;
_lines[index] = line.copyWith(quantity: line.quantity - 1);
notifyListeners();
}
}
class CartSummaryPage extends StatefulWidget {
const CartSummaryPage({super.key});
@override
State<CartSummaryPage> createState() => _CartSummaryPageState();
}
class _CartSummaryPageState extends State<CartSummaryPage> {
late final CartController controller;
@override
void initState() {
super.initState();
controller = CartController();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Cart summary')),
body: AnimatedBuilder(
animation: controller,
builder: (context, _) => ListView(
padding: const EdgeInsets.all(16),
children: [
for (final entry in controller.lines.indexed)
ListTile(
title: Text(entry.$2.name),
subtitle: Text('JPY ${entry.$2.price} x ${entry.$2.quantity}'),
trailing: Wrap(
spacing: 8,
children: [
IconButton(
tooltip: 'Decrease ${entry.$2.name}',
onPressed: () => controller.decrement(entry.$1),
icon: const Icon(Icons.remove_circle_outline),
),
IconButton(
tooltip: 'Increase ${entry.$2.name}',
onPressed: () => controller.increment(entry.$1),
icon: const Icon(Icons.add_circle_outline),
),
],
),
),
const Divider(),
Text('Total: JPY ${controller.total}',
style: Theme.of(context).textTheme.headlineSmall),
],
),
),
);
}
}
Les pièges sont clairs : créer le controller dans build, oublier notifyListeners(), disperser le calcul du total dans plusieurs widgets ou ne pas appeler dispose.
Ajouter tests et vérification device
Avec le nom de projet cart_ai_demo, placez ceci dans test/cart_summary_test.dart.
import 'package:cart_ai_demo/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('updates the cart total when quantity changes', (tester) async {
await tester.pumpWidget(const CartDemoApp());
expect(find.text('Total: JPY 2800'), findsOneWidget);
await tester.tap(find.byIcon(Icons.add_circle_outline).first);
await tester.pump();
expect(find.text('Total: JPY 4600'), findsOneWidget);
await tester.tap(find.byIcon(Icons.remove_circle_outline).first);
await tester.pump();
expect(find.text('Total: JPY 2800'), findsOneWidget);
});
}
flutter analyze
flutter test
Pour un émulateur ou appareil réel, ajoutez un integration test.
import 'package:cart_ai_demo/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('cart can be changed on a real device', (tester) async {
await tester.pumpWidget(const CartDemoApp());
await tester.tap(find.byIcon(Icons.add_circle_outline).last);
await tester.pumpAndSettle();
expect(find.text('Total: JPY 3300'), findsOneWidget);
});
}
flutter devices
flutter test integration_test -d <device_id>
Cas d’usage et pièges plateforme
Cas 1 : ajouter quantité, filtre ou tri à une liste existante. Cas 2 : nettoyer pubspec.yaml et les assets. Cas 3 : diagnostiquer un bug limité à Android, iOS ou Web, comme permissions, notifications, localisation ou liens externes. Cas 4 : ajouter des tests de régression à un écran legacy. Dans chaque cas, donnez les fichiers cibles, la commande attendue et le format de rapport en cas d’échec.
Flutter partage la couche Dart, pas tout l’environnement de déploiement. Android peut demander des permissions manifest, iOS des textes Info.plist, CocoaPods et signature, Web peut échouer sur CORS ou des API navigateur, Desktop a ses propres permissions et plugins.
flutter analyze
flutter test
flutter build apk --debug
flutter build web --release
Ne demandez pas une vérification iOS release sur une machine sans macOS ni Xcode. Le prompt doit indiquer ce qui peut être exécuté et ce qui reste à vérifier.
Prompts sûrs et note terrain
Investigation : lis lib/, test/, pubspec.yaml et les dossiers plateforme. N'édite rien. Retourne carte et risques.
Implémentation : change seulement lib/features/cart. Respecte le style d'état existant. N'ajoute pas de dépendance.
pubspec : si une dépendance est nécessaire, arrête-toi et donne raison, alternatives, impact et commandes.
Vérification : ajoute un widget test. Lance flutter analyze et flutter test. Rapporte les échecs avec fichiers.
Revue critique : vérifie dispose, async, effets dans build, plateforme, accessibilité, packages et tests manquants.
La note de terrain de Masa : les meilleurs résultats Flutter viennent du rythme “carte d’abord, petit diff ensuite, tests et build à la fin”. Le mauvais prompt était “fais un bel écran Flutter” : interface plausible, mais état créé dans build, packages inutiles et aucune revue plateforme. Les équipes peuvent commencer par la fiche gratuite puis structurer l’adoption avec formation et conseil Claude Code. Pour concevoir des garde-fous réutilisables, lisez harness engineering.
Ces extraits ciblent un projet flutter create cart_ai_demo. Cet environnement de rédaction n’a pas Flutter SDK installé, donc la vérification finale doit être faite dans un vrai environnement Flutter avec flutter analyze, flutter test, le build de la plateforme cible et un test émulateur ou appareil.
PDF gratuit: cheatsheet Claude Code
Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.
Nous protégeons vos données et n'envoyons pas de spam.
À propos de l'auteur
Masa
Ingénieur spécialisé dans les workflows pratiques avec Claude Code.
Articles liés
Workflow Obsidian vers CLAUDE.md avec Claude Code
Transformer des notes Obsidian en notes CLAUDE.md concises pour reprendre les sessions sans réexpliquer.
Claude Code Revenue CTA Routing : relier articles, PDF, Gumroad et consultation
Un workflow Claude Code pour orienter les lecteurs vers PDF gratuit, Gumroad ou consultation selon l'intention.
Règles de handoff Claude Code en équipe: preuves, permissions, rollback et revenus
Un format concret pour transmettre un travail Claude Code avec preuves, permissions, rollback, PDF gratuit, Gumroad et consultation.