Use Cases (Diperbarui: 2/6/2026)

Claude Code untuk Flutter/Dart: peta proyek, state, test, dan build

Alur praktis memakai Claude Code di Flutter/Dart: pubspec, widget, state, test, build, dan verifikasi perangkat.

Claude Code untuk Flutter/Dart: peta proyek, state, test, dan build

Claude Code paling berguna dalam Flutter/Dart saat dipakai sebagai partner yang memahami proyek, bukan generator widget sekali pakai. Perubahan nyata sering menyentuh lib/, pubspec.yaml, assets, test, konfigurasi Android dan iOS, batasan Web, emulator, serta perintah build. Widget adalah bagian UI, state adalah data yang mengubah tampilan, dan pubspec adalah file untuk dependency, assets, serta batasan SDK.

Contoh di artikel ini adalah layar cart kecil. Kodenya cukup sederhana untuk ditempel ke proyek flutter create, tetapi tetap memperlihatkan kesalahan produksi: membuat state di dalam build, menambah package tanpa alasan, lupa widget test, atau menganggap Android, iOS, dan Web punya aturan runtime yang sama.

Saat menyesuaikan contoh, pakai dokumentasi resmi: Flutter CLI, Flutter testing, Widget testing, Flutter pubspec options, Dart pubspec, Platform channels, dan Claude Code common workflows. Bacaan terkait: React Native, strategi testing, dan praktik CLAUDE.md.

Buat peta proyek dulu

Jangan mulai dengan “buat layar cart”. Minta Claude Code membaca repo tanpa mengedit. Harness, atau kerangka kerja aman, berisi file yang boleh disentuh, larangan, perintah verifikasi, dan kriteria review.

Baca proyek Flutter ini terlebih dahulu.
Jangan edit file dulu.
Laporkan:
1. SDK constraint, dependency, dan assets di pubspec.yaml
2. Struktur UI, state, dan data layer di lib/
3. Gaya test yang sudah ada di test/ dan integration_test/
4. Target aktif di android/, ios/, web/, macos/, windows/, dan linux/
5. Apakah flutter analyze, flutter test, dan build command terdokumentasi
Akhiri dengan daftar file yang aman diedit dan file yang tidak boleh disentuh.
AreaClaude Code bisa mengerjakanKeputusan manusia
Peta proyekKonvensi folder, dependency, gaya testBatas edit
WidgetKomponen UI, aksesibilitas, responsiveCopy produk dan desain
StateMengikuti setState, ChangeNotifier, Riverpod, Bloc, atau pola lamaStrategi state aplikasi
pubspecUsulan dependency dan assetsApakah package baru diterima
PlatformPerbedaan Android/iOS/Web/DesktopTarget yang didukung
Test/buildWidget test, integration test, commandMerge dan release

Perlakukan pubspec sebagai kontrak

pubspec.yaml mengatur dependency, assets, SDK, dan package test. Sebelum diedit, Claude Code harus menjelaskan alasan, alternatif, file terdampak, dan command verifikasi.

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/

Untuk sandbox baru, buat baseline berikut. Untuk repo lama, minta Claude Code menyesuaikan dengan konfigurasi saat ini.

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

Kesalahan umum: indentasi assets rusak, pubspec.lock berubah tanpa kebutuhan, dan package state-management ditambahkan untuk interaksi kecil.

Periksa pubspec.yaml dan putuskan apakah perubahan cart benar-benar butuh dependency baru.
Sebelum mengedit, tampilkan alasan, alternatif, file terdampak, dan command verifikasi.
Jangan ubah pubspec.yaml atau pubspec.lock sebelum disetujui.

Ubah widget dan state secara kecil

Kode ini dapat mengganti lib/main.dart di proyek flutter create cart_ai_demo. Hanya memakai Flutter SDK. CartController memegang perubahan state, sedangkan widget merender UI.

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

Jaga batasnya dengan prompt berikut:

Update UI cart, tetapi semua perubahan state tetap di CartController.
Jangan membuat CartController di dalam build. Jangan tambah package.
Tambahkan widget test yang membuktikan total berubah setelah tap plus dan minus.

Tambahkan test dan verifikasi perangkat

Jika nama proyek cart_ai_demo, letakkan ini di 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

Untuk emulator atau device nyata, tambahkan 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 case dan jebakan platform

Use case 1: menambah quantity, filter, atau sort pada list lama. Use case 2: merapikan pubspec.yaml dan assets. Use case 3: menelusuri bug yang hanya muncul di Android, iOS, atau Web, misalnya permission, notification, location, atau external link. Use case 4: menambahkan regression test untuk layar lama yang belum punya coverage. Setiap prompt perlu menyebut target file, command yang diharapkan, dan format laporan gagal.

Flutter berbagi layer Dart, tetapi aturan deploy tetap berbeda. Android mungkin butuh permission manifest, iOS butuh Info.plist, CocoaPods, dan signing, Web bisa kena CORS atau API browser, Desktop punya permission file dan perilaku plugin native.

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

Build release iOS membutuhkan macOS dan Xcode. Tulis di prompt mana yang bisa dijalankan di mesin ini dan mana yang masih pending.

Prompt aman dan catatan lapangan

Investigasi: baca lib/, test/, pubspec.yaml, dan folder platform. Jangan edit. Beri peta dan risiko.
Implementasi: ubah hanya lib/features/cart. Ikuti pola state lama. Jangan tambah dependency.
pubspec: jika dependency dibutuhkan, berhenti dan beri alasan, alternatif, impact, dan command.
Verifikasi: tambahkan widget test. Jalankan flutter analyze dan flutter test. Laporkan gagal dengan nama file.
Review: cek dispose, async, side effect di build, config platform, aksesibilitas, package churn, dan test yang hilang.

Catatan praktik Masa: hasil Flutter terbaik muncul dari urutan “peta dulu, diff kecil, lalu test dan build”. Prompt lemah adalah “buat layar Flutter yang bagus”; UI terlihat masuk akal, tetapi state dibuat di build, package bertambah, dan platform tidak direview. Tim bisa mulai dari cheatsheet gratis lalu merapikan adopsi lewat training dan konsultasi Claude Code. Untuk guardrail berulang, baca harness engineering.

Snippet ini menargetkan flutter create cart_ai_demo. Lingkungan penulisan ini tidak memiliki Flutter SDK, jadi verifikasi final harus dijalankan di environment Flutter nyata dengan flutter analyze, flutter test, build target platform, dan test emulator atau device.

#Claude Code #Flutter #Dart #pengembangan mobile #cross-platform
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.