В проекте с 50+ сервисами и репозиториями ручная регистрация зависимостей через GetIt превращается в хаос. injection_container.dart разрастается до 500+ строк, порядок регистрации сбивается, а при рефакторинге забывают обновлять регистрацию. Результат — StateError: No instance of type ApiService found в рантайме. Мы сталкивались с этим десятки раз и научились решать проблему автоматически. На одном из проектов ручная регистрация отнимала до 3 дней работы на каждую новую фичу.
Настройка injectable — кодогенератора поверх GetIt — сокращает ручной код на 70% и исключает ошибки регистрации. Вы просто пишете аннотации @injectable или @lazySingleton, запускаете build_runner, и он генерирует файл injection.config.dart. Всё, DI чистый и декларативный. Это снижает трудозатраты на поддержку до 80%.
Как injectable упрощает управление зависимостями?
Ручная регистрация в GetIt не масштабируется: при 50+ зависимостях легко запутаться в порядке, забыть обновить при рефакторинге, а чужой injection_container часто превращается в "чёрный ящик". injectable устраняет этот ручной труд — добавил аннотацию к классу, запустил build_runner, файл обновился автоматически. Экономия времени — до 2 часов в неделю на поддержке DI. На практике это означает, что разработчик не отвлекается на рутину и реже допускает ошибки.
Как настроить injectable в проекте?
Базовая настройка занимает 10–15 минут. Добавьте зависимости в pubspec.yaml:
dependencies: get_it: ^7.6.0 injectable: ^2.3.0 dev_dependencies: injectable_generator: ^2.4.0 build_runner: ^2.4.0 Создайте точку входа — файл с функцией инициализации:
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); } Запустите генерацию: dart run build_runner build --delete-conflicting-outputs. Для постоянной генерации используйте build_runner watch — он автоматически обновляет код при каждом изменении аннотаций.
Как работать с окружениями?
injectable поддерживает @Environment аннотации — встроенная поддержка dev, staging, production без ручных условий. Пример:
@dev @LazySingleton(as: ApiService) class MockApiService implements ApiService { ... } @prod @LazySingleton(as: ApiService) class RealApiService implements ApiService { ... } // Инициализация с окружением: await configureDependencies(environment: Environment.prod); В тестах передаёте Environment.dev — моки подключаются автоматически. Никаких if в injection_container.
Как обрабатывать async-зависимости?
Для асинхронной инициализации используйте @factoryMethod:
@singleton class DatabaseService { late final Database _db; @factoryMethod static Future<DatabaseService> create() async { final service = DatabaseService(); service._db = await openDatabase('app.db'); return service; } } injectable сгенерирует registerSingletonAsync, а configureDependencies() вернёт Future. Не забудьте await перед runApp.
Почему возникает ошибка 'No instance of type'?
Самая частая причина — разработчик добавил новый класс с аннотацией, но забыл запустить build_runner. Приложение компилируется со старым injection.config.dart, новый класс остаётся незарегистрированным. Решение: добавьте build_runner watch в процесс разработки или настройте CI-шаг для проверки актуальности сгенерированного кода.
Совет по ускорению разработки
Используйте `build_runner watch` в отдельном терминале. Он автоматически перегенерирует код при изменении файлов с аннотациями. Это экономит время и предотвращает ошибки.Сравнение: ручной GetIt vs Injectable
| Параметр | Ручной GetIt | Injectable |
|---|---|---|
| Объём кода | 1 файл на 300+ строк | ~10 строк + аннотации |
| Риск ошибок регистрации | Высокий (забыли порядок) | Низкий (кодогенерация) |
| Поддержка окружений | Ручная логика | Встроенная через @Environment |
| Рефакторинг | Нужно править injection_container |
Достаточно изменить аннотацию |
| Тестирование | Дополнительные моки вручную | Легко переключить окружение |
Типичные ошибки при DI и их решения
| Ошибка | Причина | Решение |
|---|---|---|
| No instance of type | Не запущен build_runner | Запустить build_runner или watch |
| Duplicate registration | Дважды зарегистрирован один тип | Использовать @singleton или @lazySingleton |
| Circular dependency | Неправильная архитектура | Разделить сервисы, использовать фабрики |
| Environment mismatch | Неправильное окружение | Указать Environment при инициализации |
Как мы настраиваем DI в вашем проекте
Настройка Dependency Injection — часть нашей стандартной архитектуры Flutter-проектов. Мы выполняем её под ключ: устанавливаем и конфигурируем зависимости (get_it, injectable, build_runner), создаём точку входа с поддержкой окружений, аннотируем все сервисы, репозитории и фабрики, настраиваем async-зависимости и фабричные методы, интегрируем кодогенерацию в CI/CD (автоматический запуск build_runner), мигрируем существующий ручной injection_container на аннотации и документируем архитектуру DI. После настройки команда получает чёткую структуру, которую легко масштабировать при добавлении новых фич. Новый разработчик разбирается в DI-слое за 30 минут вместо нескольких часов.
Наш опыт — 5+ лет разработки на Flutter, более 30 завершённых мобильных проектов. Гарантируем, что DI-слой будет стабильным и легко расширяемым. Свяжитесь с нами, чтобы обсудить задачу и получить консультацию по архитектуре вашего приложения. Закажите настройку DI — и мы подберём оптимальное решение для вашего проекта.
Работа занимает 1–3 дня в зависимости от размера проекта. На новом проекте — быстрее, на существующем с ручным DI — дольше из-за миграции и тестирования корректности порядка регистраций. Результат: чистая, масштабируемая архитектура DI. Оценим ваш проект бесплатно — просто напишите.
Официальная документация Injectable: pub.dev/packages/injectable







