Разработка мобильных приложений на Flutter

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

1. Введение в экосистему Flutter и основы языка Dart

Введение в экосистему Flutter и основы языка Dart

Добро пожаловать в курс «Разработка мобильных приложений на Flutter». Мы начинаем наше путешествие с фундаментальных основ. Прежде чем мы напишем наше первое приложение, необходимо понять, что такое Flutter, почему он изменил мир мобильной разработки и какую роль в этом играет язык программирования Dart.

Что такое Flutter и зачем он нужен?

До появления современных кроссплатформенных фреймворков, мобильная разработка делилась на два лагеря: нативная разработка под iOS (Swift/Objective-C) и под Android (Kotlin/Java). Это означало, что бизнесу требовалось две команды разработчиков, два бюджета и двойное время на поддержку продукта.

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

Ключевые особенности Flutter:

  • Кроссплатформенность: Вы пишете код один раз, а работает он везде.
  • Высокая производительность: Flutter не использует «мосты» (bridges) для общения с нативными компонентами, как это делают некоторые другие фреймворки. Вместо этого он рисует весь интерфейс самостоятельно, используя графический движок.
  • Hot Reload (Горячая перезагрузка): Эта функция позволяет разработчикам видеть изменения в коде практически мгновенно, без потери состояния приложения. Это колоссально ускоряет процесс разработки и экспериментов с дизайном.
  • !Упрощенная архитектура Flutter: от высокоуровневого кода на Dart до низкоуровневого взаимодействия с платформой.

    Как видно из схемы выше, Flutter состоит из трех слоев. Мы, как разработчики, взаимодействуем в основном с верхним слоем — Framework, написанным на языке Dart. Именно он управляет виджетами, анимацией и жестами.

    Язык программирования Dart

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

    Почему Dart идеален для Flutter?

    JIT (Just-In-Time) компиляция: Во время разработки Dart использует JIT-компиляцию, что обеспечивает работу функции Hot Reload*. * AOT (Ahead-Of-Time) компиляция: При сборке релизной версии приложения (для публикации в App Store или Google Play), код компилируется в нативные машинные инструкции (ARM или x86). Это обеспечивает высокую скорость запуска и плавную работу анимаций (60 или 120 кадров в секунду).

    Основы синтаксиса Dart

    Dart — это строгий типизированный объектно-ориентированный язык. Если вы знакомы с Java, C# или JavaScript, синтаксис Dart покажется вам очень знакомым.

    Переменные и типы данных

    В Dart все является объектом, даже числа и функции. Рассмотрим базовые типы:

    Логические операции и математика

    Поскольку программирование тесно связано с логикой, важно понимать, как работают булевы выражения. В Dart, как и в математической логике, результат операции сравнения — это истина или ложь.

    Рассмотрим логическое выражение:

    Где: * — результат выражения (Result). * — булевы переменные (истина или ложь). * — логическое ИЛИ (в Dart обозначается как ||). * — логическое И (в Dart обозначается как &&). * — логическое НЕ (отрицание, в Dart обозначается как !).

    В коде Dart это выглядит так:

    Концепция «Всё есть Виджет»

    Главная мантра Flutter: Everything is a Widget (Всё есть виджет).

    В отличие от других фреймворков, где есть разделение на контроллеры, представления и макеты, во Flutter виджетом является практически всё:

    * Видимый элемент интерфейса (кнопка, текст, иконка). * Элемент макета (отступы Padding, выравнивание Center, строки Row, колонки Column). * Даже само приложение (MaterialApp) — это тоже виджет.

    Виджеты образуют иерархию, называемую Деревом виджетов (Widget Tree). Вы строите интерфейс, вкладывая одни виджеты в другие.

    !Пример дерева виджетов простого приложения: от корня до конкретных элементов на экране.

    Stateless и Stateful виджеты

    Все виджеты делятся на два основных типа:

  • StatelessWidget (Бесстатейные): Виджеты, которые не меняют своего состояния после создания. Они статичны. Пример: Icon, Text (если текст не меняется).
  • StatefulWidget (Имеющие состояние): Виджеты, которые могут изменяться в процессе работы приложения. Например, Checkbox (галочка ставится/убирается) или TextField (пользователь вводит текст).
  • Null Safety (Безопасность null)

    Современный Dart (начиная с версии 2.12) поддерживает Sound Null Safety. Это означает, что переменные по умолчанию не могут принимать значение null. Это защищает приложение от целого класса ошибок, связанных с попыткой обратиться к несуществующему объекту.

    Если вы хотите, чтобы переменная могла быть пустой, вы должны явно пометить её знаком вопроса ?:

    Экосистема пакетов

    Flutter обладает огромной библиотекой готовых решений. Сайт pub.dev — это официальный репозиторий пакетов для Dart и Flutter. Если вам нужно добавить карты, работу с камерой, HTTP-запросы или сложные анимации, скорее всего, для этого уже есть готовый пакет.

    Управление зависимостями происходит через файл pubspec.yaml, который находится в корне вашего проекта. Это конфигурационный файл, где вы указываете название проекта, версию и необходимые библиотеки.

    Заключение

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

    В следующей статье мы перейдем от теории к практике: настроим окружение разработки и создадим наше первое приложение «Hello World», детально разобрав его структуру.

    2. Построение пользовательского интерфейса: базовые виджеты и компоновка

    Построение пользовательского интерфейса: базовые виджеты и компоновка

    В предыдущей статье мы познакомились с языком Dart и узнали, что во Flutter «всё есть виджет». Теперь пришло время перейти от теории к практике. Мы научимся собирать красивые и функциональные экраны из базовых кирпичиков, которые предоставляет фреймворк.

    Создание интерфейса во Flutter напоминает сборку конструктора LEGO. У вас есть детали разной формы и назначения (виджеты), и ваша задача — соединить их правильным образом, чтобы получить желаемую структуру.

    Анатомия экрана: Scaffold

    Прежде чем размещать кнопки и текст, нам нужен «холст». В приложениях, использующих Material Design (стандарт дизайна от Google), таким холстом выступает виджет Scaffold (строительные леса).

    Scaffold реализует базовую визуальную структуру макета Material Design. Он предоставляет слоты для стандартных элементов интерфейса:

    * appBar: Верхняя панель приложения (заголовок, кнопки действий). * body: Основное содержимое экрана. * floatingActionButton: Плавающая кнопка действия (обычно в правом нижнем углу). * drawer: Боковое выдвижное меню. * bottomNavigationBar: Нижняя панель навигации.

    Пример базовой структуры:

    Базовые виджеты контента

    Рассмотрим виджеты, которые отображают информацию или создают визуальные блоки.

    Text (Текст)

    Самый простой, но важный виджет. Он позволяет стилизовать строки, меняя шрифт, цвет, размер и начертание через свойство style.

    Container (Контейнер)

    Container — это универсальный инструмент. Если вам нужно нарисовать прямоугольник с фоном, добавить отступы (padding), внешние поля (margin), рамку или тень, вы используете Container.

    !Визуализация блочной модели Container: контент, внутренние отступы, границы и внешние отступы.

    Важно понимать разницу между padding и margin: Padding: Отступ внутри* контейнера (между границей и контентом). Margin: Отступ снаружи* контейнера (между контейнером и соседними элементами).

    Image (Изображение) и Icon (Иконка)

    Для работы с графикой используются:

  • Icon: Векторные глифы, которые не теряют качества при масштабировании. Flutter включает в себя огромный набор иконок Material Design.
  • Image: Растровые изображения. Чаще всего используются конструкторы:
  • * Image.asset: Для картинок, хранящихся внутри приложения. * Image.network: Для загрузки картинок из интернета по URL.

    Виджеты компоновки (Layout Widgets)

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

    Row и Column

    Это два самых часто используемых виджета во Flutter. Они позволяют выстраивать дочерние элементы в линию.

    * Row (Строка): Располагает элементы горизонтально. * Column (Колонна): Располагает элементы вертикально.

    У обоих виджетов есть две ключевые оси:

  • Main Axis (Главная ось):
  • * Для Row — горизонтальная (слева направо). * Для Column — вертикальная (сверху вниз).
  • Cross Axis (Поперечная ось):
  • * Для Row — вертикальная. * Для Column — горизонтальная.

    !Направление осей для Row и Column: главная ось определяет направление укладки элементов.

    Управление выравниванием

    Свойства mainAxisAlignment и crossAxisAlignment позволяют управлять распределением элементов.

    Пример выравнивания в колонке:

    Expanded и Flexible

    Часто возникает задача: «Пусть этот элемент займет всё оставшееся свободное место». Для этого дочерний виджет внутри Row или Column оборачивают в Expanded.

    Представим, что мы рассчитываем ширину элементов в строке. Если мы используем Expanded с параметром flex, пространство распределяется пропорционально.

    Математически долю ширины элемента можно выразить так:

    Где: * — итоговая ширина -го элемента. * — общая доступная ширина родительского контейнера. * — значение flex для текущего элемента (коэффициент гибкости). * — сумма значений flex всех элементов в строке.

    Если у вас есть два виджета Expanded, один с flex: 1, а другой с flex: 2, то второй займет в два раза больше места, чем первый (2/3 от общей ширины).

    Stack (Стопка)

    Если Row и Column располагают элементы рядом, то Stack накладывает их друг на друга (как слои в Photoshop). Это полезно, когда нужно разместить текст поверх картинки или иконку уведомления поверх аватара.

    Порядок отрисовки важен: первый виджет в списке children будет самым нижним (фон), а последний — самым верхним.

    Для точного позиционирования внутри стека используется виджет Positioned, который позволяет задать отступы от краев (top, bottom, left, right).

    Правило компоновки во Flutter

    Чтобы избежать популярных ошибок (например, надписи «RenderFlex overflowed» с желто-черными полосами), нужно запомнить главное правило компоновки во Flutter:

    > Constraints go down. Sizes go up. Parent sets position. > (Ограничения спускаются вниз. Размеры поднимаются вверх. Родитель задает позицию.) > — Flutter Documentation

    Как это работает:

  • Родитель сообщает ребенку свои ограничения (Constraints): «Ты можешь быть шириной от 0 до 300 пикселей».
  • Ребенок (Child) решает, какого размера он хочет быть в этих пределах: «Хорошо, я буду шириной 150 пикселей».
  • Родитель размещает ребенка (Position): «Тогда я поставлю тебя по центру».
  • Если ребенок попытается стать шире, чем разрешил родитель (например, 350 пикселей при максимуме 300), произойдет ошибка переполнения (overflow).

    Практический пример: Карточка профиля

    Давайте соберем знания воедино и создадим простую карточку профиля.

    В этом примере мы использовали: * Container для фона, скругления углов и тени. * Row для горизонтального размещения аватара, текста и стрелки. * SizedBox для создания фиксированного пустого пространства (отступа). * Expanded для того, чтобы колонка с текстом заняла всё свободное место между аватаром и стрелкой. * Column для вертикального размещения имени и должности.

    Заключение

    Мы рассмотрели фундамент построения интерфейсов во Flutter. Scaffold создает структуру страницы, Row и Column управляют сеткой, а Container и Text наполняют её содержанием. Понимание того, как работают оси (Main/Cross) и как передаются ограничения (Constraints), позволит вам верстать макеты любой сложности.

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

    3. Управление состоянием и интерактивность приложения

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

    В предыдущих статьях мы научились верстать красивые экраны, используя Scaffold, Row, Column и Container. Однако наши приложения пока напоминают красивые статуи: они выглядят отлично, но совершенно неподвижны. Они не реагируют на действия пользователя и не меняют свой внешний вид.

    В этой статье мы вдохнем жизнь в наши интерфейсы. Мы разберем, как обрабатывать нажатия, что такое состояние (State), чем отличаются StatelessWidget от StatefulWidget и как работает магия метода setState.

    Что такое интерактивность?

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

    Обработка нажатий

    Самый простой способ сделать элемент интерактивным — использовать готовые кнопки, такие как ElevatedButton, TextButton или IconButton. У всех них есть параметр onPressed.

    Если вы передадите в onPressed значение null, кнопка автоматически станет неактивной (серой) и перестанет реагировать на нажатия.

    GestureDetector и InkWell

    Но что, если вы хотите сделать кликабельным обычный Container, картинку или текст? Для этого существуют виджеты-обертки:

  • GestureDetector: Распознает множество жестов (нажатие, двойное нажатие, долгое нажатие, перетаскивание). Он не добавляет визуальных эффектов при нажатии.
  • InkWell: Добавляет эффект «чернильной кляксы» (ripple effect) при нажатии, что соответствует гайдлайнам Material Design.
  • Понятие Состояния (State)

    Прежде чем мы перейдем к коду, давайте разберемся с теорией. Что такое состояние?

    > Состояние — это любые данные, которые нужны для восстановления пользовательского интерфейса в конкретный момент времени.

    Это может быть текст в поле ввода, положение переключателя (включен/выключен), список загруженных товаров или счетчик нажатий.

    Во Flutter интерфейс является функцией от состояния. Это можно выразить математической формулой:

    Где: * — (User Interface) то, что пользователь видит на экране. * — функция построения интерфейса (в нашем случае это метод build). * — (State) текущее состояние приложения (данные).

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

    Stateless vs Stateful виджеты

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

    StatelessWidget (Бесстатейный виджет)

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

    Примеры: Icon, Text (статичный), Container.

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

    StatefulWidget (Виджет с состоянием)

    Это виджет, который может изменять свой вид в процессе работы. Он «знает», что происходит внутри него, и хранит данные в памяти.

    Примеры: Checkbox, TextField, Slider, Scaffold.

    StatefulWidget устроен сложнее. Он состоит не из одного класса, а из двух:

  • Сам Виджет (Widget): Является неизменяемым (immutable). Содержит только конфигурацию.
  • Объект Состояния (State): Является изменяемым. Хранит данные и логику.
  • !Схема разделения ответственности: виджет создает состояние, а объект состояния хранит данные и строит интерфейс.

    Почему такое разделение? Потому что виджеты во Flutter пересоздаются очень часто (при каждом обновлении кадра или родителя), а состояние должно сохраняться между перерисовками.

    Жизненный цикл State

    У объекта State есть свой жизненный цикл — последовательность методов, которые вызываются в определенные моменты:

  • createState(): Вызывается фреймворком для создания объекта состояния.
  • initState(): Вызывается один раз при инициализации. Здесь удобно подписываться на потоки данных или инициализировать контроллеры.
  • build(): Вызывается каждый раз, когда нужно отрисовать интерфейс.
  • dispose(): Вызывается перед тем, как объект состояния будет уничтожен навсегда. Здесь нужно отписываться от потоков и освобождать ресурсы (например, закрывать контроллеры).
  • Метод setState()

    Как сообщить Flutter, что данные изменились и нужно перерисовать экран? Для этого используется метод setState.

    setState принимает функцию, внутри которой вы изменяете переменные состояния. После выполнения этой функции Flutter помечает виджет как «грязный» (dirty) и планирует вызов метода build в ближайшем кадре.

    Рассмотрим классический пример счетчика:

    Поднятие состояния (Lifting State Up)

    Часто бывает так, что состояние нужно одному виджету, а управляет им другой (например, кнопка в одном углу экрана меняет текст в другом).

    Во Flutter данные передаются сверху вниз (от родителя к ребенку через конструктор). Если дочернему виджету нужно изменить состояние родителя, он использует колбэки.

    Представьте, что у вас есть переключатель. Сам переключатель не должен хранить состояние «включено/выключено», он должен получать его от родителя и сообщать родителю о желании переключиться.

    Этот паттерн называется «Поднятие состояния вверх». Состояние хранится в ближайшем общем предке всех виджетов, которым нужны эти данные.

    Заключение

    Мы сделали огромный шаг вперед. Теперь ваши приложения могут реагировать на действия пользователя, запоминать данные и обновлять интерфейс. Понимание работы setState и жизненного цикла StatefulWidget — это фундамент, на котором строятся все динамические приложения во Flutter.

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

    4. Навигация, маршрутизация и работа с сетью

    Навигация, маршрутизация и работа с сетью

    В предыдущих статьях мы научились создавать пользовательский интерфейс и управлять состоянием внутри одного экрана. Но большинство современных приложений состоят из множества страниц: списка товаров, детального просмотра, профиля пользователя и настроек. Кроме того, эти приложения редко работают в вакууме — им нужно получать данные с сервера, будь то прогноз погоды или лента новостей.

    В этой статье мы объединим эти концепции. Мы узнаем, как переключаться между экранами, передавать данные и взаимодействовать с внешним миром через интернет.

    Навигация во Flutter: Теория Стека

    Навигация во Flutter основана на концепции стека (Stack). Представьте себе стопку тарелок. Когда вы открываете новый экран, вы кладете новую тарелку сверху (операция push). Когда вы нажимаете кнопку «Назад», вы снимаете верхнюю тарелку, открывая ту, что была под ней (операция pop).

    !Принцип работы навигационного стека: добавление (push) и удаление (pop) экранов.

    Этот механизм управляется классом Navigator. Это виджет, который накладывает экраны друг на друга.

    Базовая навигация (Navigator.push)

    Чтобы перейти на новый экран, мы используем метод Navigator.push. Он принимает два аргумента: текущий context и Route (маршрут).

    Самый распространенный тип маршрута в Material Design — это MaterialPageRoute. Он обеспечивает стандартную анимацию перехода (слайд снизу вверх на iOS или выцветание/слайд на Android).

    Возврат назад (Navigator.pop)

    Чтобы закрыть текущий экран и вернуться к предыдущему, используется метод Navigator.pop.

    В Scaffold виджет AppBar автоматически добавляет кнопку «Назад» (стрелочку), если в стеке есть предыдущий экран. Вам не нужно добавлять её вручную.

    Передача данных между экранами

    Часто при переходе нужно передать информацию, например, ID выбранного товара.

    Передача данных вперед

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

    Состояния snapshot

    Объект snapshot внутри builder содержит информацию о текущем статусе: * snapshot.connectionState: Состояние подключения (none, waiting, active, done). * snapshot.hasData: Истина, если данные успешно загружены. * snapshot.hasError: Истина, если произошла ошибка.

    Заключение

    Сегодня мы сделали наше приложение по-настоящему функциональным. Мы научились:

  • Использовать Navigator для перемещения между экранами, управляя стеком навигации.
  • Передавать данные через конструкторы виджетов.
  • Использовать именованные маршруты для лучшей организации кода.
  • Выполнять асинхронные HTTP-запросы, не блокируя интерфейс.
  • Использовать FutureBuilder для отображения индикаторов загрузки и полученных данных.
  • Эти навыки являются базовыми для любого мобильного разработчика. В следующих статьях мы углубимся в архитектуру приложений и узнаем, как хранить данные на устройстве, чтобы приложение работало даже без интернета.

    5. Хранение данных, архитектура и публикация приложения

    Хранение данных, архитектура и публикация приложения

    Поздравляю! Вы прошли долгий путь от написания первой строчки кода на Dart до создания многостраничных приложений, умеющих общаться с сервером. Но наше приложение пока имеет один существенный недостаток: оно полностью зависит от интернета и «забывает» все данные при перезапуске, если они не пришли с сервера.

    В этой завершающей статье курса мы решим эту проблему. Мы научимся сохранять данные на устройстве, структурировать код так, чтобы в нем не запутаться, и, наконец, подготовим наше творение к публикации в Google Play и App Store.

    Локальное хранение данных

    Мобильные устройства не всегда имеют стабильное подключение к сети. Хорошее приложение должно работать в режиме offline (офлайн) или хотя бы сохранять настройки пользователя. Во Flutter для этого есть несколько инструментов.

    1. Shared Preferences: Для простых данных

    Представьте, что вам нужно запомнить, включил ли пользователь темную тему или отключил ли он уведомления. Это простые пары «ключ-значение». Для таких задач идеально подходит пакет shared_preferences.

    Он работает как словарь (Map), который сохраняется на диск.

    Когда использовать: Настройки, флаги, небольшие кусочки информации. Когда НЕ использовать: Большие списки данных, сложные объекты.

    2. Базы данных: SQLite и sqflite

    Если вам нужно хранить список задач, кэшировать ленту новостей или сохранять сложные связи между объектами, вам нужна полноценная база данных. Стандартом в мобильной разработке является SQLite.

    SQLite — это реляционная база данных. Это значит, что данные хранятся в таблицах, и мы можем делать к ним запросы, используя язык SQL.

    Почему базы данных так эффективны? Представьте, что вы ищете книгу в библиотеке. Если книги свалены в кучу (как в текстовом файле), вам придется перебирать каждую. В базе данных используются индексы (как картотека), что позволяет находить данные мгновенно.

    Эффективность поиска в индексированной базе данных можно описать логарифмической зависимостью:

    Где: * — примерное количество операций (шагов), необходимых для нахождения записи. * — знак приблизительного равенства. * — логарифм по основанию 2. * — общее количество записей в таблице.

    Это означает, что даже если у вас миллион записей (), поиск займет всего около 20 шагов (), в то время как простой перебор занял бы 500,000 шагов в среднем.

    Для работы с SQLite во Flutter используется пакет sqflite.

    3. Современные альтернативы: Hive и Isar

    В мире Flutter набирают популярность NoSQL базы данных, такие как Hive или Isar. Они написаны на чистом Dart, работают очень быстро и не требуют знания SQL-запросов. Данные в них хранятся в виде объектов (боксов), что часто удобнее для разработчика.

    Архитектура приложения

    Когда вы пишете маленькое приложение, можно писать весь код в одном файле. Но когда проект растет, такой код превращается в «спагетти». Чтобы этого избежать, нужно использовать правильную архитектуру.

    Принцип разделения ответственности

    Главное правило: UI не должен знать, откуда берутся данные.

    Виджет (экран) должен только отображать информацию и реагировать на нажатия. Он не должен делать HTTP-запросы или писать в базу данных напрямую.

    !Слоистая архитектура: UI отображает данные, Логика обрабатывает их, а Репозиторий решает, брать данные из сети или из базы.

    Паттерн Repository (Репозиторий)

    Репозиторий — это класс-посредник между вашим кодом и источниками данных. Он скрывает сложность получения информации.

    Пример:

    Благодаря этому подходу, если вы решите сменить базу данных с SQLite на Hive, вам придется переписать только код внутри WeatherRepository. Весь остальной код приложения (UI, логика) даже не заметит подмены.

    Публикация приложения

    Ваше приложение готово, протестировано и имеет отличную архитектуру. Пора показать его миру.

    Подготовка ассетов

    Первое, что видит пользователь — это иконка. Во Flutter не нужно вручную нарезать иконки разных размеров для iOS и Android. Используйте пакет flutter_launcher_icons. Вы просто кладете исходную картинку в папку проекта, запускаете команду, и пакет генерирует все необходимые файлы.

    Сборка для Android

  • Подпись приложения (Signing): Android требует, чтобы каждое приложение было подписано цифровым ключом. Вы создаете файл хранилища ключей (.jks), который является вашим «паспортом» разработчика. Никогда не теряйте этот ключ! Без него вы не сможете обновить приложение в Google Play.
  • App Bundle (.aab): Раньше мы собирали .apk файлы. Сейчас стандартом является Android App Bundle (.aab). Это архив, который содержит все ресурсы для всех типов устройств. Google Play сам «нарезает» из него оптимизированные APK для конкретного телефона пользователя, что экономит место.
  • Команда для сборки: flutter build appbundle

    Сборка для iOS

    Для публикации в App Store вам обязательно понадобится компьютер Mac с установленным Xcode.

  • Apple Developer Account: Вам нужно оплатить участие в программе разработчиков Apple.
  • Archive: Процесс сборки происходит через Xcode (Product -> Archive).
  • TestFlight: Перед релизом приложение обычно загружают в TestFlight — сервис для бета-тестирования, где вы и ваши друзья могут проверить работу приложения на реальных устройствах.
  • Заключение курса

    Мы прошли большой путь. Вы узнали, что Flutter — это мощный инструмент, позволяющий рисовать пиксели на экране с высокой производительностью. Вы изучили язык Dart, поняли философию «Всё есть виджет», научились управлять состоянием, ходить в сеть и сохранять данные.

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

    Удачи в ваших проектах, и пусть ваш код всегда компилируется без ошибок!