Flutter + Claude Code — одна кодовая база на все платформы
Flutter — это когда надо один раз написать и получить iOS, Android, Web и десктоп. Claude Code знает Dart достаточно хорошо, чтобы генерировать идиоматический код, если в CLAUDE.md зафиксировать современный стек: Riverpod 2.x, GoRouter, freezed.
Канал с гайдами и контентом по claude code, выкладываем новости (когда режут лимиты в 10 раз) и какие инструменты через claude реализуем для проектов, канал: https://t.me/claudedevolper
flutter create my_app cd my_app flutter pub add flutter_riverpod go_router dio freezed_annotation json_annotation flutter pub add --dev build_runner freezed json_serializable
CLAUDE.md
## Стек - Flutter 3.24+, Dart 3.5+ - Riverpod 2.x (flutter_riverpod, не provider) - go_router для навигации - dio для HTTP - freezed для моделей - flutter_test + integration_test ## Структура - lib/features/<name>/ — фича (UI + providers + модели) - lib/core/ — общее (theme, router, http client) - lib/main.dart — entry point ## Правила - Все модели через freezed, никаких ручных fromJson/toJson - State через Riverpod providers, не setState - Нет StatefulWidget где можно ConsumerWidget - Navigator.push запрещён — только GoRouter
Freezed-модель
// lib/features/product/product.dart
import 'package:freezed_annotation/freezed_annotation.dart';
part 'product.freezed.dart';
part 'product.g.dart';
@freezed
class Product with _$Product {
const factory Product({
required int id,
required String name,
required int priceCents,
}) = _Product;
factory Product.fromJson(Map<String, dynamic> json) =>
_$ProductFromJson(json);
}После flutter pub run build_runner build получаешь ==, copyWith, JSON-сериализацию бесплатно.
Riverpod-provider
// lib/features/product/products_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:dio/dio.dart';
import 'product.dart';
final dioProvider = Provider((ref) => Dio(BaseOptions(
baseUrl: 'https://api.example.com',
)));
final productsProvider = FutureProvider<List<Product>>((ref) async {
final dio = ref.read(dioProvider);
final res = await dio.get<List<dynamic>>('/products');
return res.data!.map((e) => Product.fromJson(e)).toList();
});UI с AsyncValue
// lib/features/product/products_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'products_provider.dart';
class ProductsPage extends ConsumerWidget {
const ProductsPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final async = ref.watch(productsProvider);
return Scaffold(
appBar: AppBar(title: const Text('Продукты')),
body: async.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => Center(child: Text('Ошибка: $e')),
data: (products) => RefreshIndicator(
onRefresh: () async => ref.invalidate(productsProvider),
child: ListView.separated(
itemCount: products.length,
separatorBuilder: (_, __) => const Divider(height: 0),
itemBuilder: (_, i) {
final p = products[i];
return ListTile(
title: Text(p.name),
subtitle: Text('${p.priceCents / 100} ₽'),
onTap: () => context.push('/product/${p.id}'),
);
},
),
),
),
);
}
}Маршрутизация через GoRouter
// lib/core/router.dart
import 'package:go_router/go_router.dart';
import '../features/product/products_page.dart';
import '../features/product/product_detail_page.dart';
final router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (_, __) => const ProductsPage(),
),
GoRoute(
path: '/product/:id',
builder: (_, state) => ProductDetailPage(
id: int.parse(state.pathParameters['id']!),
),
),
],
);Сборка
flutter build apk --release # Android APK flutter build appbundle --release # Play Store flutter build ios --release # iOS (нужен Mac) flutter build web --release --wasm # Web с WASM flutter build macos --release flutter build windows --release flutter build linux --release
Подводные камни
- Claude любит Provider (v4). В CLAUDE.md: «Riverpod 2.x, не provider package».
- build_runner после каждого @freezed класса. Без него
_$Productне существует. - iOS сборка только с Mac. Или через Codemagic/Bitrise.
- Hot reload ломается при изменении enum/freezed. Нужен full restart.
Как попробовать
1. flutter create + pub add зависимостей 2. CLAUDE.md 3. Попроси «список продуктов с Riverpod + Dio + Freezed» 4. flutter run — работает сразу на эмуляторе
Канал с гайдами и контентом по claude code, выкладываем новости (когда режут лимиты в 10 раз) и какие инструменты через claude реализуем для проектов, канал: https://t.me/claudedevolper