Use Cases (Atualizado: 02/06/2026)

Claude Code com Flutter/Dart: mapa do projeto, estado, testes e builds

Fluxo prático para Claude Code em Flutter/Dart: pubspec, widgets, estado, testes, builds e verificação.

Claude Code com Flutter/Dart: mapa do projeto, estado, testes e builds

Claude Code ajuda mais em Flutter/Dart quando é usado como parceiro que entende o projeto, não como gerador isolado de widget. Uma mudança real pode tocar lib/, pubspec.yaml, assets, testes, configuração de Android e iOS, restrições web, emuladores e comandos de build. Widget é uma peça da interface, state é o dado que altera o que o usuário vê, e pubspec é o arquivo que declara dependências, assets e restrições de SDK.

O exemplo deste guia é uma tela pequena de carrinho. Ela cabe em um projeto criado com flutter create, mas mostra os erros que aparecem em produção: criar estado dentro de build, adicionar pacote sem motivo, esquecer widget tests ou assumir que Android, iOS e Web têm as mesmas regras.

Use a documentação oficial ao adaptar os exemplos: Flutter CLI, Flutter testing, Widget testing, Flutter pubspec options, Dart pubspec, Platform channels e Claude Code common workflows. Leia também React Native, estratégias de teste e boas práticas de CLAUDE.md.

Faça o mapa antes de editar

Não comece com “crie uma tela de carrinho”. Peça que Claude Code leia o repositório sem editar. Esse harness, ou estrutura segura de trabalho, define arquivos permitidos, proibições, comandos de verificação e critérios de revisão.

Leia primeiro este projeto Flutter.
Ainda não edite arquivos.
Informe:
1. Restrições de SDK, dependências e assets em pubspec.yaml
2. Estrutura de UI, estado e camada data em lib/
3. Estilo de testes em test/ e integration_test/
4. Targets ativos em android/, ios/, web/, macos/, windows/ e linux/
5. Se flutter analyze, flutter test e comandos de build estão documentados
Finalize com arquivos seguros para editar e arquivos que não devem ser tocados.
ÁreaClaude Code pode fazerDecisão humana
MapaConvenções, dependências, estilo de testeLimite de edição
WidgetComponente, acessibilidade, responsividadeTexto e design
EstadoSeguir setState, ChangeNotifier, Riverpod, Bloc ou padrão existenteEstratégia global
pubspecPropor dependências e assetsAprovar pacote novo
PlataformaDiferenças Android/iOS/Web/DesktopTargets suportados
Testes/buildWidget test, integration test, comandosMerge e release

Trate pubspec como contrato

pubspec.yaml controla resolução de dependências, assets, SDK e pacotes de teste. Antes de editar, Claude Code deve explicar motivo, alternativas, arquivos afetados e comandos de verificação.

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/

Para um sandbox novo, crie a base. Em um projeto existente, peça adaptação aos comandos atuais.

flutter create cart_ai_demo
cd cart_ai_demo
flutter pub get
flutter analyze
flutter test

Os problemas comuns são quebrar a indentação de assets, mudar pubspec.lock sem necessidade e adicionar biblioteca de estado para uma interação simples.

Inspecione pubspec.yaml e decida se a mudança do carrinho precisa de nova dependência.
Antes de editar, mostre motivo, alternativas, arquivos afetados e comandos de verificação.
Não altere pubspec.yaml nem pubspec.lock sem aprovação.

Mude widget e estado em bloco pequeno

O código abaixo pode substituir lib/main.dart em um projeto flutter create cart_ai_demo. Ele usa apenas o SDK Flutter. CartController concentra mudanças de estado; o widget renderiza.

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),
          ],
        ),
      ),
    );
  }
}

Prompt seguro:

Atualize a UI do carrinho, mas mantenha mudanças de estado em CartController.
Não crie CartController dentro de build. Não adicione pacote.
Adicione widget test provando que o total muda ao tocar mais e menos.

Inclua testes e dispositivo

Com o projeto chamado cart_ai_demo, coloque isto em 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

Para emulador ou dispositivo real, use 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>

Casos de uso e armadilhas de plataforma

Caso 1: adicionar quantidade, filtro ou ordenação em lista existente. Caso 2: limpar pubspec.yaml e assets. Caso 3: investigar problema só em Android, iOS ou Web, como permissões, notificações, localização ou links externos. Caso 4: adicionar testes de regressão a uma tela antiga. Cada pedido deve incluir arquivos-alvo, comando esperado e como reportar falha.

Flutter compartilha Dart, não todas as regras de entrega. Android pode exigir permissões no manifest; iOS envolve Info.plist, CocoaPods e assinatura; Web pode falhar por CORS ou API de navegador; Desktop tem permissões e plugins nativos próprios.

flutter analyze
flutter test
flutter build apk --debug
flutter build web --release

Build iOS release exige macOS e Xcode. Escreva no prompt o que pode ser executado e o que fica pendente.

Prompts seguros e nota prática

Investigação: leia lib/, test/, pubspec.yaml e pastas de plataforma. Não edite. Retorne mapa e riscos.
Implementação: mude só lib/features/cart. Siga o estado existente. Não adicione dependências.
pubspec: se precisar de dependência, pause e mostre motivo, alternativas, impacto e comandos.
Verificação: adicione widget test. Rode flutter analyze e flutter test. Reporte falhas com arquivos.
Revisão: confira dispose, async, efeitos em build, plataforma, acessibilidade, pacotes e testes faltantes.

Nota prática de Masa: os melhores resultados em Flutter vieram de “mapa primeiro, diff pequeno depois, testes e build no fim”. O prompt fraco foi “faça uma tela Flutter bonita”; a UI parecia boa, mas havia estado criado em build, pacote desnecessário e falta de revisão de plataforma. Times podem começar com a cola gratuita e estruturar adoção com treinamento e consultoria Claude Code. Para criar guardrails repetíveis, leia harness engineering.

Os snippets miram flutter create cart_ai_demo. Este ambiente de escrita não tem Flutter SDK instalado, então a verificação final deve acontecer em um ambiente real com flutter analyze, flutter test, build da plataforma alvo e teste em emulador ou dispositivo.

#Claude Code #Flutter #Dart #desenvolvimento mobile #multiplataforma
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.