Claude Code für Flutter/Dart: Projektkarte, State, Tests und Builds
Praxisleitfaden für Claude Code mit Flutter/Dart: pubspec, Widgets, State, Tests, Builds und Geräteprüfung.
Claude Code ist in Flutter/Dart am stärksten, wenn es nicht als Einmal-Generator für Widgets genutzt wird, sondern als projektkundiger Coding-Partner. Eine echte Änderung betrifft oft nicht nur lib/, sondern auch pubspec.yaml, Assets, Tests, Android- und iOS-Konfiguration, Web-Einschränkungen, Emulatoren und Build-Kommandos. Ein Widget ist ein Baustein der Oberfläche, State ist der veränderliche Datenstand der Anzeige, und pubspec ist die Datei für SDK-Grenzen, Abhängigkeiten und Ressourcen.
Dieses Tutorial nutzt einen kleinen Warenkorb. Der Code passt in ein frisches flutter create Projekt, zeigt aber typische Produktionsfehler: State in build erzeugen, Pakete ohne Grund hinzufügen, Widget-Tests vergessen oder Android, iOS und Web gleich behandeln.
Nutze beim Anpassen die offiziellen Quellen: Flutter CLI, Flutter testing, Widget testing, Flutter pubspec options, Dart pubspec, Platform channels und Claude Code common workflows. Passend dazu helfen der React Native Guide, Testing-Strategien und CLAUDE.md Best Practices.
Erst die Projektkarte
Beginne nicht mit “baue einen Warenkorb”. Lass Claude Code zuerst nur lesen. Dieses Harness, also der sichere Arbeitsrahmen, enthält erlaubte Dateien, Verbote, Prüfkommandos und Review-Kriterien.
Lies zuerst dieses Flutter-Projekt.
Bearbeite noch keine Dateien.
Berichte:
1. SDK-Grenzen, Dependencies und Assets in pubspec.yaml
2. Struktur für UI, State und Data unter lib/
3. Teststil in test/ und integration_test/
4. Aktive Targets in android/, ios/, web/, macos/, windows/ und linux/
5. Ob flutter analyze, flutter test und Build-Kommandos dokumentiert sind
Liste am Ende sicher editierbare Dateien und Dateien, die unangetastet bleiben sollen.
| Bereich | Claude Code übernimmt | Mensch entscheidet |
|---|---|---|
| Projektkarte | Konventionen, Dependencies, Tests | Editiergrenzen |
| Widget | Komponente, Accessibility, Responsive Details | Produkttext und Design |
| State | An setState, ChangeNotifier, Riverpod, Bloc oder lokalen Stil anpassen | Globale State-Strategie |
| pubspec | Dependencies und Assets vorschlagen | Neue Pakete akzeptieren |
| Plattform | Android/iOS/Web/Desktop Unterschiede | Unterstützte Targets |
| Tests/Build | Widget-Test, Integration-Test, Kommandos | Merge und Release |
pubspec bewusst ändern
pubspec.yaml steuert Dependencies, Assets, SDK-Grenzen und Testpakete. Claude Code sollte vor jeder Änderung Begründung, Alternativen, betroffene Dateien und Prüfkommandos nennen.
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/
Für einen neuen Sandbox-Check reicht diese Basis. In bestehenden Repos soll Claude Code die aktuellen Kommandos ableiten.
flutter create cart_ai_demo
cd cart_ai_demo
flutter pub get
flutter analyze
flutter test
Häufige Fehler sind kaputte Einrückung unter assets, unnötiger Lockfile-Churn und ein State-Management-Paket für eine simple Interaktion. Ein guter Prompt:
Prüfe pubspec.yaml und entscheide, ob die Warenkorbänderung eine neue Dependency braucht.
Zeige vor dem Editieren Begründung, Alternativen, betroffene Dateien und Prüfkommandos.
Ändere pubspec.yaml und pubspec.lock erst nach Freigabe.
Widget und State klein halten
Dieser Code kann lib/main.dart in einem frischen flutter create cart_ai_demo Projekt ersetzen. Er nutzt nur das Flutter SDK. CartController kapselt State-Änderungen, das Widget rendert.
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),
],
),
),
);
}
}
Der Auftrag an Claude Code sollte diese Grenze festhalten:
Aktualisiere die Warenkorb-UI, aber lasse State-Änderungen in CartController.
Erzeuge CartController nicht in build. Füge kein Paket hinzu.
Ergänze einen Widget-Test für Plus, Minus und die Gesamtsumme.
Tests und Gerät prüfen
Bei Projektname cart_ai_demo gehört dieser Test nach 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
Für Emulator oder echtes Gerät ergänzt du einen 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>
Use Cases und Plattformfallen
Use Case 1 ist ein Mengen-, Filter- oder Sortierzustand in einer bestehenden Liste. Use Case 2 ist das Aufräumen von pubspec.yaml und Assets. Use Case 3 ist ein Fehler nur auf Android, iOS oder Web, etwa Berechtigungen, Benachrichtigungen, Standort oder externe Links. Use Case 4 ist Regressionstest-Abdeckung für eine Legacy-Seite. Jeder Prompt braucht Ziel-Dateien, erwartete Kommandos und Fehlerbericht.
Flutter teilt die Dart-Schicht, nicht alle Deployment-Regeln. Android braucht oft Manifest-Rechte, iOS Info.plist, CocoaPods und Signing, Web scheitert an CORS oder Browser-APIs, Desktop an Dateirechten oder nativen Plugins.
flutter analyze
flutter test
flutter build apk --debug
flutter build web --release
iOS Release-Prüfung braucht macOS und Xcode. Schreibe im Prompt, welche Checks ausführbar sind und welche offen bleiben.
Sichere Prompts und Praxisnotiz
Recherche: Lies lib/, test/, pubspec.yaml und Plattformordner. Nichts editieren. Karte und Risiken ausgeben.
Implementierung: Nur lib/features/cart ändern. Bestehenden State-Stil nutzen. Keine Dependencies hinzufügen.
pubspec: Bei nötiger Dependency pausieren und Begründung, Alternativen, Impact und Kommandos zeigen.
Verifikation: Widget-Test ergänzen. flutter analyze und flutter test ausführen. Fehler mit Dateien melden.
Review: dispose, async, build-Seiteneffekte, Plattform, Accessibility, Paketänderungen und fehlende Tests prüfen.
Masas Praxisnotiz: Die besten Flutter-Ergebnisse kamen mit “erst Karte, dann kleiner Diff, am Ende Tests und Build”. Der schwache Prompt war “baue einen schönen Flutter-Screen”; er lieferte plausible UI, aber auch State in build, unnötige Pakete und keine Plattformprüfung. Teams können mit dem kostenlosen Cheatsheet starten und die Einführung über Claude Code Training und Beratung strukturieren. Für wiederholbare Leitplanken ist Harness Engineering relevant.
Die Snippets zielen auf flutter create cart_ai_demo. In dieser Schreibumgebung ist kein Flutter SDK installiert, daher muss die Endprüfung in einer echten Flutter-Umgebung mit flutter analyze, flutter test, Zielplattform-Build und Emulator oder Gerät erfolgen.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Workflow von Obsidian zu CLAUDE.md
Obsidian-Arbeitsnotizen in CLAUDE.md-Betriebsnotizen verwandeln und Kontext nicht ständig neu erklären.
Claude Code Revenue CTA Routing: Artikel zu PDF, Gumroad und Beratung führen
Ein Claude-Code-Ablauf, der Leser nach Absicht zu Gratis-PDF, Gumroad oder Beratung führt.
Claude-Code-Team-Handoff-Regeln: Belege, Berechtigungen, Rollback und Umsatzpfade
Ein praktisches Claude-Code-Handoff für Review-Belege, Berechtigungen, Rollback, Gratis-PDF, Gumroad und Beratung.