Настройка Dependency Injection (Injectable) во Flutter-приложении
injectable — это кодогенератор поверх GetIt. Пишешь аннотации, build_runner генерирует registration-код. Вместо ручного injection_container.dart на 300 строк — чистый декларативный код с @injectable, @singleton, @lazySingleton.
Зачем нужен injectable, если есть GetIt
Ручная регистрация в GetIt не масштабируется: при 50+ зависимостях нужно следить за порядком регистрации, не забывать обновлять injection_container при рефакторинге, разбираться в чужих кастомных файлах. injectable устраняет этот ручной труд — добавил аннотацию к классу, запустил build_runner, файл *.config.dart обновился автоматически.
Базовая настройка
pubspec.yaml:
dependencies:
get_it: ^7.6.0
injectable: ^2.3.0
dev_dependencies:
injectable_generator: ^2.4.0
build_runner: ^2.4.0
Точка входа:
// injection.dart
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
import 'injection.config.dart';
final sl = GetIt.instance;
@InjectableInit()
Future<void> configureDependencies() => sl.init();
Аннотация сервиса:
@lazySingleton
class ApiService {
final Dio _dio;
ApiService(this._dio); // injectable разберётся с Dio автоматически
}
Запуск генерации: dart run build_runner build --delete-conflicting-outputs.
Environments: dev, staging, production
injectable поддерживает @Environment аннотации — одна из главных причин выбирать его над чистым GetIt:
@dev
@LazySingleton(as: ApiService)
class MockApiService implements ApiService { ... }
@prod
@LazySingleton(as: ApiService)
class RealApiService implements ApiService { ... }
Инициализация с окружением:
await configureDependencies(environment: Environment.prod);
В тестах — Environment.dev с моками. Не нужно городить условия в injection_container.
Async dependencies
@singleton
class DatabaseService {
late final Database _db;
@factoryMethod
static Future<DatabaseService> create() async {
final service = DatabaseService();
service._db = await openDatabase('app.db');
return service;
}
}
@factoryMethod на static async-конструкторе — injectable сгенерирует registerSingletonAsync. configureDependencies() вернёт Future, нужно await перед runApp.
Типичная проблема при кодогенерации
После добавления нового @injectable-класса разработчик забывает запустить build_runner — приложение компилируется (старый .config.dart не удалён), но новый класс не зарегистрирован. При первом обращении — StateError: No instance of type XxxService found. Решение: добавить build_runner watch в процесс разработки или настроить CI-шаг проверки актуальности сгенерированного кода.
Что входит в настройку
Добавляем зависимости → создаём точку входа с @InjectableInit → расставляем аннотации по существующим сервисам и репозиториям → настраиваем environments для dev/prod → конфигурируем build_runner в CI → проверяем async-зависимости. При необходимости — рефакторинг ручного injection_container на аннотации.
Работа занимает 1–3 дня в зависимости от размера проекта. На новом проекте — быстрее, на существующем с ручным DI — дольше из-за миграции.







