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

Вы увидите множество папок и файлов: android, web, windows, lib, test и другие. Где хранится исходный код для написания? В папке android? Windows? На самом деле нет, исходный код находится в папке lib. Откройте lib, там вы найдёте файл main.dart.

Папка lib в дальнейшем будет хранить весь ваш исходный код. Вы будете писать код на языке Dart, не на Java или C++. Flutter использует язык Dart. Тогда почему в корне проекта есть папки android, web, windows и другие?
Всё легко понять: возможность Flutter компилироваться в приложения для разных платформ реализована именно за счёт этих папок.
Flutter — это фреймворк по принципу один набор кода Dart, запуск на множестве платформ. Папка lib содержит общий кроссплатформенный бизнес-код, который вы пишете; а папки android / windows / web / macos / linux — это нативные хост-проекты каждой платформы, они отвечают за встраивание движка Flutter в соответствующую операционную систему для запуска.
1. Папка android
Это нативный проект платформы Android
Он предоставляет контейнер для запуска Android-приложения и содержит движок рендеринга Flutter. Все низкоуровневые параметры, связанные с Android, настраиваются здесь: разрешения приложения, иконки, имя пакета и прочее. То есть здесь можно настроить специфичные для Android элементы и вызывать нативные API системы (камера, Bluetooth, уведомления, геолокация и т.д.)
2. Папка windows
Это нативный проект для настольной версии Windows
Это нативный проект C++ Win32, он создаёт окна Windows и инициализирует графический движок Skia. Skia — графическая библиотека Google, с её помощью Flutter отрисовывает окна и все элементы интерфейса десктопных приложений.
В папке windows хранятся низкоуровневые настройки для настольного ПО Windows: размер окна, заголовок окна, иконки, системный трей (значок в правом нижнем углу экрана Windows).
В итоге вы можете собрать проект в форматы exe, msix и опубликовать его в Microsoft Store.
3. Папка web
Проект статических веб-страниц (HTML/JS/CSS), содержит точку входа в веб index.html. Ваш исходный код Dart в итоге компилируется в веб-ресурсы.
Здесь настраиваются заголовок страницы, иконки, статические ресурсы и маршруты. При компиляции выводятся файлы HTML/CSS/JS, которые можно разместить на сервере и открыть в браузере.
Остальные папки
Мы не используем их сейчас, потому что при создании проекта не отметили пункты ios, macos, linux и другие, поэтому этих папок здесь нет. Но принцип их работы полностью одинаковый.
ios: Нативный проект Xcode для Apple iOS, используется для сборки ipa и публикации на iPhone
macos: Нативный проект Cocoa для настольной macOS, клиент для компьютеров Mac
linux: Настольный проект Linux на основе GTK
В правом верхнем углу Android Studio вы выбираете разные платформы, чтобы скомпилировать разные версии приложения. Также можно напрямую использовать командную строку; по сути, при выборе платформы и нажатии зелёного треугольника в Android Studio выполняются команды Flutter.
# Запустить Android, читает конфигурации из папки android
flutter run -d android
# Запустить десктоп Windows, читает C++ проект из папки windows
flutter run -d windows
# Запустить веб-версию, читает html из папки web
flutter run -d chromeCode language: PHP (php)

Откройте файл runner / main.cpp внутри папки windows
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <windows.h>
#include "flutter_window.h"
#include "utils.h"
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
_In_ wchar_t *command_line, _In_ int show_command) {
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
CreateAndAttachConsole();
}
// Initialize COM, so that it is available for use in the library and/or
// plugins.
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
flutter::DartProject project(L"data");
std::vector<std::string> command_line_arguments =
GetCommandLineArguments();
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.Create(L"myproject", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);
::MSG msg;
while (::GetMessage(&msg, nullptr, 0, 0)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
::CoUninitialize();
return EXIT_SUCCESS;
}
Code language: PHP (php)
Если вы компилируете для Windows Desktop, то этот main.cpp является настоящей точкой входа программы: сначала выполняется этот файл C++, затем управление переходит в ваш lib/main.dart
Аналогично, если открыть папку android, вы увидите структуру, почти полностью совпадающую с проектами Android, разрабатываемыми на Kotlin или Java.

Там также есть папка src, файл AndroidManifest.xml, MainActivity и другие элементы, знакомые всем, кто разрабатывал Android-приложения. По сути, при разработке Android на Flutter запуск начинается именно из этой папки android.
Точно так же, открыв папку web, вы найдёте точку входа для веб index.html

Файлы Dart
Файл main.dart внутри папки lib — это место, где вы будете вести основную разработку. В папке lib можно создавать подпапки и добавлять другие Dart-файлы.
Откройте main.dart
// Подключение библиотеки компонентов Material
import 'package:flutter/material.dart';
// Точка входа в программу
void main() {
runApp(const MyApp());
}
// Корневой компонент приложения (без состояния)
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
// Глобальные настройки темы
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
// Главная страница
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
// Главная страница (компонент с состоянием)
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// Параметр заголовка страницы
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
// Класс управления состоянием главной страницы
class _MyHomePageState extends State<MyHomePage> {
// Переменная счётчика
int _counter = 0;
// Метод увеличения счётчика
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
// Базовый шаблон макета страницы
return Scaffold(
// Верхняя панель навигации
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
// Основное содержимое страницы
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('You have pushed the button this many times:'),
Text(
'$_counter', // Отображение числовой переменной
style: Theme.of(context).textTheme.headlineMedium, // Стиль текста
),
],
),
),
// Плавающая кнопка в правом нижнем углу: onPressed — действие по клику, tooltip — подсказка, child — иконка
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}Code language: JavaScript (javascript)
1. Блок входа
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
Code language: JavaScript (javascript)
- Подключаем официальный набор UI-компонентов Material (кнопки, страницы, текст и т.д.), у Apple есть собственный UI-фреймворк
main— единственная точка входа программы Dart;runApp()запускает приложение и монтирует корневой компонентMyApp
2. MyApp — глобальный корневой компонент
Это StatelessWidget (компонент без состояния), мы разберём это позже, сейчас достаточно просто запомнить.
class MyApp extends StatelessWidget {
const MyApp({super.key});
// Корневой компонент вашего приложения
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
Code language: JavaScript (javascript)
- Глобальные настройки: название приложения, общая тема, главная страница
MaterialApp: обёртка приложения в стиле Material, едино управляет маршрутами, темами, заголовкамиhomeзадаёт страницу, открывающуюся по умолчанию —MyHomePage
3. MyHomePage — главная страница
Страница, отображающаяся по умолчанию при запуске окна или приложения, это StatefulWidget (компонент с состоянием), мы подробно разберём далее.
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}Code language: JavaScript (javascript)
- Содержит изменяемые данные (число счётчика), поэтому используется компонент с состоянием
- Заголовок
titleпередаётся снаружи, внутри класса состояния читается черезwidget.title - Обязательно сопутствует класс
_MyHomePageState, предназначенный для хранения переменных страницы и логики взаимодействия
4. _MyHomePageState
Класс логики состояния, отвечает за обработку логики страницы, отрисовку и обновление интерфейса
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('You have pushed the button this many times:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}Code language: JavaScript (javascript)
int _counter = 0: изменяемая переменная страницы — значение счётчика_incrementCounter(): событие нажатия кнопкиsetState()уведомляет Flutter об изменении данных, требуется перерисовать интерфейс страницы- Увеличение счётчика на единицу
build(): выполняется при каждом обновлении страницы, возвращает готовый макет страницы
5. Scaffold — шаблон страницы
Шаблон макета страницы, принадлежит классу _MyHomePageState
appBar: верхняя панель заголовкаbody: основное содержимое страницыCenterвыравнивает элементы по центру,Columnрасполагает текст вертикально
floatingActionButton: круглая кнопка с плюсом в правом нижнем углу, привязана к методу увеличения по клику
Общий порядок запуска
- Запуск программы → выполнение
main→ загрузкаMyApp MyAppотрисовываетMaterialApp→ загружает главную страницуMyHomePage- На странице отображается панель заголовка, центрированный текст и кнопка с плюсом
- Нажатие кнопки → запуск
_incrementCounter+ вызовsetStateперерисовывает страницу → число обновляется
Разбираемся с первым Flutter-проектом