Перейти к основному содержимому

5.22. Flutter

Разработчику Архитектору

Flutter

Что такое Flutter

Flutter — это открытый фреймворк для разработки кроссплатформенных приложений, созданный компанией Google. Он позволяет писать одно приложение и развертывать его на множестве платформ: Android, iOS, Windows, macOS, Linux, а также в виде веб-приложения. Все эти версии работают из одного и того же кода без необходимости поддерживать отдельные кодовые базы для каждой операционной системы.

Основная цель Flutter — обеспечить высокую производительность, выразительный пользовательский интерфейс и быстрый цикл разработки. Приложения, написанные на Flutter, компилируются в нативный машинный код, что исключает использование промежуточных слоёв или виртуальных машин. Это делает их быстрыми и отзывчивыми, сравнимыми по скорости с приложениями, написанными на нативных языках.

Flutter не является обёрткой над системными UI-компонентами. Вместо этого он рисует каждый элемент интерфейса самостоятельно с помощью собственного движка рендеринга, основанного на Skia — библиотеке двумерной графики с открытым исходным кодом. Такой подход гарантирует одинаковый внешний вид и поведение приложения на всех платформах, устраняя различия, вызванные особенностями реализации нативных компонентов.


Flutter SDK

Flutter SDK — это программный пакет, содержащий всё необходимое для разработки, тестирования и сборки приложений. Он включает в себя:

  • Компилятор Dart-to-native (AOT) и JIT-компилятор для режима разработки.
  • Инструмент командной строки flutter, который управляет жизненным циклом проекта: создание, запуск, сборка, анализ, обновление зависимостей.
  • Библиотеки фреймворка, включая наборы виджетов Material Design и Cupertino.
  • Инструменты отладки и профилирования, интегрированные в DevTools.
  • Движок рендеринга на основе Skia.
  • Плагины для взаимодействия с нативными API устройств.

SDK распространяется как архив, который распаковывается в любую директорию файловой системы. После добавления пути к исполняемому файлу flutter в переменную окружения PATH разработчик получает доступ к полному набору команд через терминал.

Установка Flutter не требует установки дополнительных сред разработки, но для запуска приложений на мобильных устройствах рекомендуется использовать Android Studio или Xcode. Эти IDE предоставляют эмуляторы, средства подписи приложений и доступ к системным SDK, необходимым для сборки.

Ключевой особенностью Flutter SDK является его автономность. Большинство компонентов поставляются внутри самого SDK, что минимизирует зависимость от внешних инструментов и упрощает воспроизводимость сборки на разных машинах.


Основные компоненты Flutter

Архитектура Flutter строится вокруг нескольких ключевых концепций, которые определяют его поведение и возможности.

Dart — язык программирования, используемый во Flutter. Dart разработан Google специально для создания клиентских приложений. Он сочетает в себе статическую типизацию, современный синтаксис и мощные возможности асинхронного программирования. Dart поддерживает JIT-компиляцию (для горячей перезагрузки в процессе разработки) и AOT-компиляцию (для высокой производительности в релизной версии).

Виджеты — основная строительная единица пользовательского интерфейса в Flutter. Каждый элемент экрана, будь то кнопка, текст, контейнер или даже сам экран, представлен в виде виджета. Виджеты неизменяемы (immutable), и их дерево перестраивается при каждом изменении состояния. Flutter автоматически определяет, какие части дерева изменились, и обновляет только нужные участки экрана.

Существует два типа виджетов:

  • StatelessWidget — используется для статического интерфейса, который не меняется после создания.
  • StatefulWidget — содержит внутреннее состояние, которое может изменяться во время работы приложения. Изменение состояния вызывает повторную сборку соответствующего поддерева виджетов.

Фреймворк Flutter предоставляет два готовых набора виджетов:

  • Material — реализация рекомендаций Google по дизайну Material Design, подходящая для Android и веб-приложений.
  • Cupertino — имитация нативного стиля iOS, позволяющая создавать приложения, визуально соответствующие экосистеме Apple.

Движок рендеринга отвечает за преобразование дерева виджетов в пиксели на экране. Он работает на низком уровне, используя Skia для отрисовки графики. Движок управляет компоновкой, анимациями, событиями ввода и другими аспектами взаимодействия с пользователем.

Плагины и пакеты расширяют функциональность Flutter. Пакеты — это чисто Dart-библиотеки, добавляющие новые классы и функции. Плагины содержат Dart-код, связанный с нативным кодом (Java/Kotlin для Android, Swift/ObjC для iOS), что позволяет обращаться к аппаратным возможностям устройства: камере, геолокации, датчикам и другим системным сервисам.


Как работает Flutter

Процесс работы Flutter начинается с запуска функции main(), которая вызывает runApp(). Эта функция принимает корневой виджет и инициализирует дерево виджетов. С этого момента начинается цикл отрисовки, управляемый движком.

Когда состояние приложения изменяется — например, пользователь нажимает кнопку или приходят новые данные с сервера — Flutter создаёт новое дерево виджетов. Затем выполняется сравнение нового дерева со старым (алгоритм diffing). На основе этого сравнения формируется минимальный набор изменений, которые необходимо применить к текущему экрану.

Этот подход, известный как реактивное программирование, позволяет избежать ручного управления DOM или View-иерархией, как это принято в других фреймворках. Разработчик описывает, как должен выглядеть интерфейс в зависимости от текущего состояния, а Flutter сам заботится о том, как и когда обновить экран.

Режим разработки использует JIT-компиляцию, что позволяет мгновенно отображать изменения в коде без перезапуска приложения — эта функция называется Hot Reload. Она сохраняет текущее состояние приложения, применяя только изменения в логике и интерфейсе. Это значительно ускоряет итерации при проектировании UI и отладке поведения.

В релизной сборке используется AOT-компиляция, при которой весь Dart-код преобразуется в нативный машинный код. Это обеспечивает максимальную производительность и предсказуемость выполнения, без накладных расходов на интерпретацию или JIT.

Архитектурно Flutter состоит из трёх слоёв:

  1. Уровень фреймворка — Dart-код, с которым взаимодействует разработчик.
  2. Уровень движка — C++-код, управляющий рендерингом, событиями, сетью, анимациями.
  3. Уровень платформы — нативные обёртки, обеспечивающие взаимодействие с операционной системой.

Эти слои тесно интегрированы, но чётко разделены, что упрощает поддержку и расширение функциональности.


Возможности Flutter

Flutter предоставляет широкий спектр возможностей для создания современных приложений любого уровня сложности.

Он поддерживает полноценную кроссплатформенность: один и тот же код работает на мобильных устройствах, настольных компьютерах и в браузере. Это особенно ценно для стартапов и небольших команд, которые хотят охватить максимальную аудиторию с минимальными затратами на разработку.

Flutter отлично подходит для сложных пользовательских интерфейсов. Благодаря декларативному подходу и богатой системе компоновки можно создавать нестандартные, анимированные, адаптивные экраны, которые трудно реализовать с помощью нативных средств. Анимации в Flutter описываются декларативно и выполняются с частотой 60 или даже 120 кадров в секунду.

Фреймворк имеет мощную экосистему. Репозиторий pub.dev содержит десятки тысяч пакетов и плагинов, охватывающих почти все аспекты разработки: работа с базами данных, авторизация, навигация, локализация, тестирование, интеграция с облачными сервисами и многое другое.

Flutter поддерживает адаптивный и отзывчивый дизайн. Приложения могут автоматически подстраиваться под размер экрана, ориентацию устройства, тему системы (светлая/тёмная) и другие параметры. Это достигается за счёт условной логики в виджетах и использования специальных адаптивных компонентов, таких как LayoutBuilder, MediaQuery, Flexible.

Тестирование в Flutter организовано на трёх уровнях:

  • Unit-тесты проверяют отдельные функции и классы.
  • Widget-тесты моделируют взаимодействие с виджетами без запуска реального устройства.
  • Интеграционные тесты запускают приложение на устройстве и проверяют сквозные сценарии.

Благодаря этому можно достичь высокого уровня покрытия кода и уверенности в стабильности приложения.

Flutter активно развивается. Команда Google регулярно выпускает обновления, добавляя новые функции, улучшая производительность и расширяя поддержку платформ. Сообщество разработчиков огромно, документация подробна, а примеры кода доступны в официальных репозиториях.


Написание приложений на Flutter

Разработка приложений на Flutter начинается с установки Flutter SDK — программного набора, содержащего компилятор, инструменты командной строки, библиотеки и движок рендеринга. Установка выполняется однократно: достаточно распаковать архив в удобную директорию и добавить путь к исполняемому файлу flutter в переменную окружения PATH. После этого в терминале становится доступна команда flutter, управляющая всеми этапами жизненного цикла проекта.

Для комфортной работы рекомендуется использовать редактор кода с поддержкой Dart и Flutter. Наиболее популярные варианты — Visual Studio Code и Android Studio. Обе среды поддерживают автодополнение, навигацию по коду, рефакторинг, отладку и горячую перезагрузку. В VS Code требуется установка двух расширений: Dart и Flutter. В Android Studio плагины устанавливаются автоматически при первом запуске мастера настройки Flutter.

Перед началом разработки следует выполнить команду:

flutter doctor

Она проверяет наличие всех необходимых компонентов: SDK, эмуляторов, лицензий, переменных окружения. Если система сообщает об отсутствующих элементах, например, о том, что не установлен Xcode или не настроен Android SDK, разработчик получает чёткие инструкции по устранению проблемы. Эта команда — основной инструмент диагностики среды разработки.

Создание проекта

Новый проект создаётся одной командой:

flutter create my_app

Эта команда генерирует стандартную структуру каталогов, включая файлы конфигурации, шаблонный код и метаданные для каждой платформы. Основной исполняемый файл находится по пути lib/main.dart. Именно в нём определяется точка входа в приложение — функция main().

Простейшее приложение выглядит так:

import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Мое приложение')),
body: Center(child: Text('Hello, Flutter!')),
),
));
}

Здесь:

  • runApp() запускает дерево виджетов.
  • MaterialApp задаёт базовые параметры темы, маршрутизации и локализации в соответствии с рекомендациями Material Design.
  • Scaffold предоставляет каркас экрана: панель навигации, тело, нижнюю панель и другие стандартные элементы.
  • AppBar — заголовок экрана.
  • Center и Text — элементы контента.

Такой подход позволяет сразу получить рабочее приложение с корректным внешним видом и поведением на любой поддерживаемой платформе.

Запуск и отладка

После создания проекта его можно запустить командой:

flutter run

Команда автоматически обнаруживает подключённые устройства: физические смартфоны (в режиме отладки), эмуляторы Android или симуляторы iOS. Если устройств несколько, разработчик может выбрать одно из них или указать явно через флаг --device-id.

Одна из ключевых возможностей Flutter — Hot Reload. При сохранении изменений в файле кода интерфейс мгновенно обновляется без перезапуска приложения. Состояние (например, введённый текст в поле или текущая позиция в списке) сохраняется. Это радикально ускоряет итерации при проектировании UI и отладке логики.

В отличие от Hot Reload, Hot Restart полностью перезапускает приложение, сбрасывая всё состояние. Он используется, когда изменения затрагивают инициализацию (main()) или глобальные переменные.

Структура проекта

Стандартная структура проекта Flutter включает следующие ключевые элементы:

  • lib/ — основная директория исходного кода. Все Dart-файлы размещаются здесь.
  • pubspec.yaml — файл конфигурации проекта. В нём указываются название, версия, зависимости, ресурсы (шрифты, изображения), поддерживаемые платформы.
  • android/, ios/, windows/, macos/, linux/, web/ — платформенные обёртки. Они содержат нативные файлы, необходимые для сборки и подписи приложения. Обычно их не нужно редактировать вручную.
  • test/ — директория для unit- и widget-тестов.
  • assets/ — папка для хранения медиафайлов, если они подключены в pubspec.yaml.

Файл pubspec.yaml играет центральную роль. Пример его содержимого:

name: my_app
description: Простое приложение на Flutter
version: 1.0.0+1

environment:
sdk: '>=3.0.0 <4.0.0'

dependencies:
flutter:
sdk: flutter
http: ^0.19.0
shared_preferences: ^2.2.0

dev_dependencies:
flutter_test:
sdk: flutter

flutter:
uses-material-design: true
assets:
- assets/images/

Здесь подключены два сторонних пакета: http для сетевых запросов и shared_preferences для хранения данных между запусками. Все пакеты устанавливаются автоматически при выполнении flutter pub get.

Виджеты — основа всего

Во Flutter каждый элемент интерфейса — это виджет. Даже сам экран, приложение и отступы представлены виджетами. Такой подход обеспечивает единообразие и предсказуемость.

Существует два основных типа виджетов:

  • StatelessWidget — не содержит изменяемого состояния. Используется для статического контента: иконок, надписей, фиксированных форм.
  • StatefulWidget — содержит внутреннее состояние, которое может меняться во время работы. Примеры: кнопки с переключением, формы ввода, анимации.

Состояние StatefulWidget хранится в отдельном объекте State, который переживает перестроение виджета. Метод setState() уведомляет фреймворк об изменении состояния и инициирует повторную сборку части дерева.

Пример StatefulWidget:

class CounterApp extends StatefulWidget {
@override
_CounterAppState createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {
int _count = 0;

void _increment() {
setState(() {
_count++;
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('Счётчик: $_count')),
floatingActionButton: FloatingActionButton(
onPressed: _increment,
child: Icon(Icons.add),
),
);
}
}

Здесь _count — изменяемое состояние. При нажатии на кнопку вызывается _increment(), который через setState() обновляет значение и перерисовывает текст.

Компоновка и стилизация

Flutter не использует CSS или XML-разметку. Всё оформление и расположение элементов задаётся программно через вложенные виджеты.

Основные виджеты компоновки:

  • Column и Row — вертикальное и горизонтальное выравнивание дочерних элементов.
  • Stack — наложение элементов друг на друга.
  • Container — универсальный блок с возможностью задать отступы, рамки, фон, размеры.
  • Padding, SizedBox, Expanded, Flexible — вспомогательные элементы для точного контроля пространства.

Стилизация достигается через параметры виджетов: цвет, шрифт, тень, радиус скругления. Например:

Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue.shade100,
borderRadius: BorderRadius.circular(8),
),
child: Text('Стилизованный блок'),
)

Такой подход исключает разрыв между логикой и внешним видом, делая код самодокументируемым.

Навигация и маршрутизация

Переход между экранами осуществляется через систему навигатора. Каждый экран — это отдельный виджет, называемый маршрутом.

Простой переход:

Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);

Возврат:

Navigator.pop(context);

Для сложных сценариев (вкладки, боковое меню, вложенные навигаторы) используются готовые виджеты: TabBarView, Drawer, Navigator с кастомной стековой логикой.

Современные приложения часто применяют императивную или декларативную навигацию. Начиная с Flutter 3.0, рекомендуется использовать пакет go_router или встроенный Router API для декларативного управления маршрутами, особенно в крупных проектах.

Управление состоянием

Для малых приложений достаточно setState(). Однако по мере роста сложности возникает необходимость в более продуманных решениях:

  • Provider — официально рекомендуемый способ. Позволяет передавать данные через дерево виджетов без промежуточных зависимостей.
  • Riverpod — улучшенная версия Provider с лучшей композицией и тестированием.
  • Bloc / Cubit — подход, основанный на потоках событий и состояний. Подходит для бизнес-логики с чёткими переходами.
  • GetX — минималистичный фреймворк, совмещающий управление состоянием, навигацию и зависимостями.

Выбор зависит от масштаба проекта, командных соглашений и предпочтений разработчика. Flutter не навязывает единую архитектуру, предоставляя гибкость.

Работа с пакетами

Экосистема Flutter строится вокруг pub.dev — централизованного репозитория пакетов. Там размещены тысячи решений: от работы с камерой и геолокацией до интеграции с Firebase, GraphQL, WebSocket.

Подключение пакета сводится к добавлению строки в pubspec.yaml и выполнению flutter pub get. После этого пакет становится доступен через import.

Пример использования HTTP-клиента:

final response = await http.get(Uri.parse('https://api.example.com/data'));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
// обработка данных
}

Пакеты значительно сокращают время разработки, позволяя сосредоточиться на уникальной логике приложения.

Тестирование

Flutter поддерживает три уровня тестирования:

  1. Unit-тесты — проверяют отдельные функции и классы без UI.
  2. Widget-тесты — моделируют взаимодействие с виджетами, проверяя их поведение в изолированной среде.
  3. Интеграционные тесты — запускают приложение на реальном устройстве и проверяют сквозные сценарии.

Тесты пишутся на Dart и запускаются командой flutter test. Для интеграционных тестов используется flutter drive или новый integration_test пакет.

Сборка и публикация

Готовое приложение собирается в релизную версию командами:

  • Для Android: flutter build apk или flutter build appbundle
  • Для iOS: flutter build ios
  • Для веба: flutter build web
  • Для десктопа: flutter build windows (и аналогично для macOS/Linux)

Результат — готовый к распространению артефакт: APK, IPA, папка с HTML/CSS/JS или исполняемый файл. Дальнейшая публикация выполняется через Google Play Console, App Store Connect или собственный веб-сервер.