| name | developing-with-flutter |
| description | Flutter SDK for cross-platform development targeting iOS, Android, and Web. Use for widget architecture, state management, platform channels, and multi-platform deployment. |
Flutter SDK Skill
Quick Reference
Flutter is Google's UI toolkit for building natively compiled applications for mobile (iOS, Android), web, and desktop from a single Dart codebase.
Table of Contents
- Critical: Avoiding Interactive Mode
- Prerequisites
- CLI Decision Tree
- Project Structure
- State Management
- Widget Patterns
- Navigation (GoRouter)
- Platform-Specific Code
- Web-Specific Considerations
- Testing
- Error Handling
- CI/CD Integration
- Auto-Detection Triggers
- Agent Integration
- Sources
Critical: Avoiding Interactive Mode
Flutter CLI can enter interactive mode which will hang Claude Code. Always use flags to bypass prompts:
| Command | WRONG (Interactive) | CORRECT (Non-Interactive) |
|---|---|---|
| Create project | flutter create (prompts) |
flutter create my_app --org com.example |
| Run app | flutter run (prompts for device) |
flutter run -d <device_id> |
| Build | flutter build (may prompt) |
flutter build apk --release |
| Emulators | flutter emulators --launch |
flutter emulators --launch <emulator_id> |
Always include:
-d <device_id>for device selection (useflutter devicesto list)- Explicit build targets (
apk,appbundle,ios,web) --no-pubwhen pub get is not needed--suppress-analyticsin CI/CD environments
Never use in Claude Code:
- Commands that open GUI (Android Studio, Xcode)
- Interactive device selection prompts
- Commands without explicit targets
Prerequisites
flutter --version # Expected: Flutter 3.x.x
flutter doctor # Check all requirements
flutter devices # List available devices
flutter emulators # List available emulators
CLI Decision Tree
Project Setup
├── Create new project ────────────────► flutter create <name> --org <org>
├── Get dependencies ──────────────────► flutter pub get
├── Upgrade dependencies ──────────────► flutter pub upgrade
├── Clean build artifacts ─────────────► flutter clean
└── Check project health ──────────────► flutter doctor
Development
├── Run on device ─────────────────────► flutter run -d <device_id>
├── Run in release mode ───────────────► flutter run --release -d <device_id>
├── Attach to running app ─────────────► flutter attach -d <device_id>
└── View logs ─────────────────────────► flutter logs -d <device_id>
Building
├── Build Android APK ─────────────────► flutter build apk --release
├── Build Android App Bundle ──────────► flutter build appbundle --release
├── Build iOS ─────────────────────────► flutter build ios --release
├── Build iOS (no codesign) ───────────► flutter build ios --release --no-codesign
└── Build Web ─────────────────────────► flutter build web --release
Testing
├── Run all tests ─────────────────────► flutter test
├── Run specific test file ────────────► flutter test test/widget_test.dart
├── Run with coverage ─────────────────► flutter test --coverage
└── Run integration tests ─────────────► flutter test integration_test/
Code Quality
├── Analyze code ──────────────────────► flutter analyze
├── Format code ───────────────────────► dart format .
└── Fix lint issues ───────────────────► dart fix --apply
See REFERENCE.md for complete CLI options, flavors, and advanced build configurations.
Project Structure
my_app/
├── lib/
│ ├── main.dart # Entry point
│ ├── app.dart # App widget
│ ├── features/ # Feature modules
│ │ └── auth/
│ │ ├── data/ # Repositories, data sources
│ │ ├── domain/ # Entities, use cases
│ │ └── presentation/ # Widgets, providers
│ ├── core/ # Shared utilities
│ └── l10n/ # Localization
├── test/ # Unit and widget tests
├── integration_test/ # Integration tests
├── android/ # Android platform code
├── ios/ # iOS platform code
├── web/ # Web platform code
├── pubspec.yaml # Dependencies
└── analysis_options.yaml # Lint rules
See REFERENCE.md for complete pubspec.yaml and analysis_options.yaml configurations.
State Management
Riverpod (Recommended)
// Provider definition
@riverpod
class Counter extends _$Counter {
@override
int build() => 0;
void increment() => state++;
void decrement() => state--;
}
// Usage in widget
class CounterWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('Count: $count');
}
}
Provider (Simple apps)
class CartNotifier extends ChangeNotifier {
final List<Item> _items = [];
List<Item> get items => List.unmodifiable(_items);
void addItem(Item item) {
_items.add(item);
notifyListeners();
}
}
// Usage
final cart = context.watch<CartNotifier>();
Bloc (Enterprise apps)
// Events and States
sealed class AuthEvent {}
class LoginRequested extends AuthEvent {
final String email, password;
LoginRequested(this.email, this.password);
}
sealed class AuthState {}
class AuthLoading extends AuthState {}
class AuthSuccess extends AuthState { final User user; AuthSuccess(this.user); }
// Bloc
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc() : super(AuthInitial()) {
on<LoginRequested>(_onLoginRequested);
}
}
See REFERENCE.md for complete Riverpod architecture, Bloc patterns, and provider types.
Widget Patterns
StatelessWidget
class UserCard extends StatelessWidget {
final User user;
final VoidCallback? onTap;
const UserCard({required this.user, this.onTap, super.key});
@override
Widget build(BuildContext context) {
return Card(
child: ListTile(
leading: CircleAvatar(backgroundImage: NetworkImage(user.avatarUrl)),
title: Text(user.name),
subtitle: Text(user.email),
onTap: onTap,
),
);
}
}
StatefulWidget
class SearchField extends StatefulWidget {
final ValueChanged<String> onChanged;
const SearchField({required this.onChanged, super.key});
@override
State<SearchField> createState() => _SearchFieldState();
}
class _SearchFieldState extends State<SearchField> {
final _controller = TextEditingController();
Timer? _debounce;
@override
void dispose() {
_debounce?.cancel();
_controller.dispose();
super.dispose();
}
void _onSearchChanged(String value) {
_debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 300), () {
widget.onChanged(value);
});
}
@override
Widget build(BuildContext context) {
return TextField(controller: _controller, onChanged: _onSearchChanged);
}
}
See REFERENCE.md for compound widgets, builder patterns, and hook widgets.
Navigation (GoRouter)
final router = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomeScreen(),
routes: [
GoRoute(
path: 'user/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return UserScreen(userId: id);
},
),
],
),
],
errorBuilder: (context, state) => ErrorScreen(error: state.error),
);
// Usage
context.go('/user/123');
context.push('/user/123');
context.pop();
See REFERENCE.md for deep linking, shell routes, and platform-specific configuration.
Platform-Specific Code
Platform Checks
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart' show kIsWeb;
Widget build(BuildContext context) {
if (kIsWeb) return WebSpecificWidget();
if (Platform.isIOS) return CupertinoWidget();
if (Platform.isAndroid) return MaterialWidget();
return DefaultWidget();
}
Platform Channels (Native Integration)
class BatteryLevel {
static const platform = MethodChannel('com.example.app/battery');
Future<int> getBatteryLevel() async {
try {
return await platform.invokeMethod('getBatteryLevel');
} on PlatformException catch (e) {
throw Exception('Failed: ${e.message}');
}
}
}
See REFERENCE.md for iOS/Android native code, conditional imports, and event channels.
Web-Specific Considerations
Build Renderers
flutter build web --web-renderer canvaskit # Better fidelity, larger
flutter build web --web-renderer html # Smaller size
flutter build web --web-renderer auto # Auto-detect
Best for: Internal tools, dashboards, PWAs, authenticated apps Note: Flutter web renders to canvas - limited SEO by default
Testing
Widget Tests
void main() {
testWidgets('Counter increments', (tester) async {
await tester.pumpWidget(const MyApp());
expect(find.text('0'), findsOneWidget);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('1'), findsOneWidget);
});
}
Golden Tests
testWidgets('Button matches golden', (tester) async {
await tester.pumpWidget(MaterialApp(home: MyButton(label: 'Submit')));
await expectLater(find.byType(MyButton), matchesGoldenFile('goldens/my_button.png'));
});
// Update: flutter test --update-goldens
See REFERENCE.md for integration tests, provider testing, and complete test patterns.
Error Handling
| Error | Solution |
|---|---|
No connected devices |
Run flutter devices, start emulator |
Gradle build failed |
Run flutter doctor, check Android Studio |
CocoaPods not installed |
sudo gem install cocoapods |
pub get failed |
Check pubspec.yaml, run flutter clean |
Debug Commands
flutter run -v # Verbose output
flutter doctor -v # Check for issues
flutter clean && flutter pub get # Clean rebuild
See REFERENCE.md for complete troubleshooting guide and CI/CD issues.
CI/CD Integration
- uses: subosito/flutter-action@v2
with:
flutter-version: "3.24.0"
channel: stable
cache: true
- run: flutter pub get
- run: flutter analyze
- run: flutter test --coverage
- run: flutter build apk --release
See REFERENCE.md for complete GitHub Actions workflows and multi-platform builds.
Auto-Detection Triggers
This skill auto-loads when Flutter context is detected:
File-based triggers:
pubspec.yamlwithflutterdependencylib/main.dartpresent.dartfiles in projectandroid/andios/directories
Context-based triggers:
- User mentions "Flutter"
- User runs flutter CLI commands
- Widget development discussions
Agent Integration
| Agent | Use Case |
|---|---|
mobile-developer |
Primary agent for Flutter development |
deep-debugger |
Performance profiling, crash analysis |
code-reviewer |
Dart code review, accessibility audit |
deployment-orchestrator |
App store submissions |
Handoff to Deep-Debugger:
- Performance profiling needed
- Crash analysis required
- Memory leak investigation
- Platform-specific bugs