<!-- skill: Flutter Multiplatform | version: 1.0.0 | description: Build Flutter apps for iOS+Android with Riverpod and flavors | category: Mobile -->
## Instructions
- Widgets over inheritance: small `StatelessWidget/ConsumerWidget` pieces, `const` constructors everywhere, themes via `ThemeData(colorSchemeSeed:)` + `useMaterial3: true`.
- State with Riverpod: `StateNotifierProvider/AsyncNotifierProvider` for features, `ref.watch` in UI, `ref.read(notifier).method()` for events; UI states as `AsyncValue` (`when(data/loading/error)`).
- Navigation: `go_router` with typed routes (`GoRoute(path: "/detail/:id")`), `redirect` for auth guard, deep-link `initialLocation`; bottom nav via `StatefulShellRoute`.
- Project layout: `lib/{app.dart, router.dart, features/<name>/{view,controller,service}, core/{theme,api,storage}}`; `pubspec.yaml` deps pinned (`^` ranges), `flutter_lints` enforced.
- Networking: `dio` with interceptors (auth header + logging in debug only) + `json_serializable`/`freezed` models; repository maps DTO→domain; offline cache with `hive` where needed.
- Storage: `flutter_secure_storage` for tokens, `shared_preferences` for flags, `sqflite/drift` for relational data; never store tokens in prefs.
- Platform channels: `MethodChannel("com.app/x")` + matching Kotlin/Swift handlers for native-only APIs (battery, sensors); prefer existing plugins (`url_launcher`, `share_plus`) before custom channels.
- Flavors: `--flavor dev/prod` + `--dart-define=API_URL=...` for endpoints; separate `android:applicationIdSuffix .dev`, iOS schemes/bundle IDs, Firebase projects per flavor.
- Assets: `flutter_native_splash` for splash, `flutter_launcher_icons` for icons, `Assets/` with `2.0x/3.0x` variants; localization via `flutter_localizations + intl` from day one if multi-language.
- Builds: `flutter build appbundle --flavor prod --release` (Play) + `flutter build ipa --flavor prod --release` (TestFlight/Store); bump `version: 1.2.0+34` (name+code) per release.
- Testing: `flutter test` unit/widget (`testWidgets`, pump + expect), `mocktail` for repos, golden tests for key screens, `integration_test` on Firebase Test Lab for release builds.
- Errors: `AsyncValue.when` error views with retry, `FlutterError.onError` + `PlatformDispatcher` handler → Crashlytics; user message + logged stack, never red-screen in release.
## Examples
- Notes app: `notesProvider` AsyncNotifier + sqflite repo, list/detail via go_router, secure token storage, dev/prod flavors.
- API client: dio service + freezed models, `AsyncValue` Loading/Error/Success, auth redirect guard, pull-to-refresh + search delegate.
- Store release: icons/splash regen, `appbundle` + `ipa` builds, internal track + TestFlight beta, staged rollout.
## Workflows
1. `flutter create` → lints + router + theme + flavor defines.
2. Feature slice: model (freezed) → service (dio) → provider → views.
3. Navigation (go_router) + auth guard + deep-link test (`adb`/xcrun).
4. Storage + platform channels (only if plugin missing) + error states.
5. Icons/splash → release builds (appbundle + ipa) → beta tracks.
6. Promote: version bump, notes, rollout, Crashlytics watch.
## Templates
- Riverpod widget:
```dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// provider
final notesProvider = AsyncNotifierProvider<NotesCtl, List<Note>>(NotesCtl.new);
class NotesCtl extends AsyncNotifier<List<Note>> {
  @override
  Future<List<Note>> build() => ref.read(notesRepoProvider).fetchAll();
  Future<void> refresh() async {
    state = const AsyncLoading();
    state = await AsyncValue.guard(() => ref.read(notesRepoProvider).fetchAll());
  }
}
// view
class NotesView extends ConsumerWidget {
  const NotesView({super.key});
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final notes = ref.watch(notesProvider);
    return Scaffold(
      appBar: AppBar(title: const Text('Notes')),
      body: notes.when(
        data: (list) => RefreshIndicator(
          onRefresh: () => ref.read(notesProvider.notifier).refresh(),
          child: ListView.builder(
            itemCount: list.length,
            itemBuilder: (_, i) => ListTile(
              title: Text(list[i].title),
              onTap: () => context.push('/detail/${list[i].id}'),
            ))),
        loading: () => const Center(child: CircularProgressIndicator()),
        error: (e, _) => Center(child: Column(children: [
          Text('Error: $e'),
          ElevatedButton(onPressed: () => ref.invalidate(notesProvider),
            child: const Text('Retry')),
        ])),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.push('/new'), child: const Icon(Icons.add)),
    );
  }
}
```
- go_router + flavors:
```dart
// router.dart
import 'package:go_router/go_router.dart';
final router = GoRouter(
  initialLocation: '/notes',
  redirect: (ctx, state) {
    final loggedIn = true; // watch auth provider
    if (!loggedIn && state.matchedLocation != '/login') return '/login';
    return null;
  },
  routes: [
    GoRoute(path: '/notes', builder: (_, __) => const NotesView()),
    GoRoute(path: '/detail/:id', builder: (_, s) => DetailView(id: s.pathParameters['id']!)),
  ],
);
// run: flutter run --flavor dev --dart-define=API_URL=https://dev.api.example.com
```
## Tools
- SARAH shell_run for `flutter create/pub get/test/build/analyze`, adb/xcrun installs.
- SARAH file_write for features/providers/router scaffolds; web_fetch for pub.dev docs.
## Advanced
- Perf: `RepaintBoundary` on animating widgets, `ListView.builder` (never Column for long lists), `flutter build --profile` + DevTools timeline; images via `cached_network_image`.
- FFI/plugins: `pigeon` for type-safe channels, federated plugin layout for custom native code; background work via `workmanager` with OS constraints.
- CI: `flutter analyze + flutter test + build appbundle/ipa` on tags; flavors as matrix; auto-upload to Play internal + TestFlight with fastlane/supply.
## Documentation
- https://docs.flutter.dev/
- https://riverpod.dev/
- https://pub.dev/packages/go_router
- https://pub.dev/packages/dio
- https://pub.dev/packages/freezed
