1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-base-ai.md 22 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

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

1. Одностраничное приложение

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

Что такое одностраничное приложение? Это значит, что для нативных Android и iOS, вся кросс-платформенная пользовательская интерфейсная система обычно работает внутри одного Activity / ViewController, по умолчанию существует всего один Activity / ViewController. Такие фреймворки, как Flutter, React Native, Weex и Ionic, также работают таким образом. Поэтому маршруты фреймворка обычно не связаны напрямую с маршрутами нативных систем.

Например, рассмотрим следующий пример:

  • В текущем стеке маршрутов Flutter есть две страницы Flutter: FlutterA и FlutterB;
  • Когда открывается новый Activity / ViewController, запускается нативная страница X, которая затем добавляется в стек маршрутов нативной системы, закрывая FlutterActivity / FlutterViewController, то есть скрывая FlutterA и FlutterB;
  • Если открыть новую страницу Flutter FlutterC, она тоже будет скрыта за счет нативной страницы X;image

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

Конечно, слово "по умолчанию" используется несколько раз, так как действительно возможно создание пользовательских смешанных стеков маршрутов, таких как официальный FlutterEngineGroup, а также сторонние фреймворки flutter_boost, mix_stack, flutter_thrio и т.д.

2. Логика рендера

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

На уровне рендера Flutter значительно отличается от других кросс-платформенных фреймворков. Ниже приведена сравнительная диаграмма современных моделей рендера:image - Для нативной Android системы процесс рендеринга состоит из нативного кода, прошедшего через Skia, до оконечной отрисовки на GPU, так как сама система Android включает в себя библиотеку Skia;

  • В случае с Flutter, контролы, написанные на Dart, проходят через Skia, а затем рендерятся и отображаются на GPU, используя Skia из операционной системы Android, а на iOS — встроенный в проект Skia;
  • Для проектов типа React Native/Weex и подобных им, они выполняются в своих JavaScript движках, а затем отображаются путём маппинга в нативные контролы с использованием нативных возможностей рендера;
  • Для гибридных кросс-платформенных фреймворков типа Ionic, используется возможность рендера WebView;

Skia в Android может использовать либо OpenGL, либо Vulkan в зависимости от ситуации, а в iOS — если есть поддержка Metal, то используется Metal для ускоренного рендера.Из вышеописанного можно сделать вывод:

ReactNative/Weex такие кросс-платформенные технологии имеют значительную связь с нативными платформами:

  • Преимуществом является то, что использование компонентов нативной платформы требует относительно низкого входного порога;
  • Недостатком же является высокая зависимость от компонентов нативной платформы, что приводит к большому количеству проблем при поддержании совместимости между различными версиями операционных систем и их компонентами.

Например: стили, отлаженные на iOS, могут работать некорректно на Android; стили, работающие на Android, могут не поддерживаться на iOS; эффекты компонентов на iOS могут отличаться от аналогичных на Android, например, при реализации плавающего меню или кнопки "Обновления".

Flutter отличается тем, что использует Skia и GPU для рендера, создавая платформенно-независимые компоненты как на Android, так и на iOS. Другими словами, большинство widgets в Flutter не связано ни с Android, ни с iOS.

Основная идея заключается в том, что нативные платформы предоставляют поверхность для рендера, а Flutter берёт на себя задачу создания соответствующих компонентов.

Обычно FlutterView используется для рендера, который внутри Android может быть представлен через SurfaceView, TextureView или FlutterImageView; в iOS это UIView, использующий layer для рендера.Поэтому компоненты Flutter демонстрируют единое поведение на различных платформах, но объединение их с нативными компонентами требует значительных усилий. Flutter предлагает механизм PlatformView для интеграции с нативными компонентами, однако сам этот механизм может вызывать проблемы с использованием памяти и клавиатурой, что увеличивает затраты на интеграцию.

3. Проектная структура

image

Как показано на рисунке выше, по умолчанию структура проекта Flutter выглядит следующим образом:

  • android каталог проекта для native Android, где можно конфигурировать имя приложения (appName), логотип (logo), splash screen, AndroidManifest, и т.д.;
  • ios каталог проекта для iOS, где можно конфигурировать splash screen, логотип (logo), название приложения, файл Info.plist, и т.д.;
  • build каталог, который создается после компиляции, обычно игнорируется в .gitignore. Процесс сборки и выходные данные находятся здесь, а также вывод процесса сборки для native Android;
  • lib каталог, используемый для написания кода на Dart, основной файл — это main.dart;
  • pubspec.yaml файл, один из ключевых файлов Flutter-проекта, где указываются ссылки на статические ресурсы (картинки, шрифты), зависимости от сторонних библиотек и версия Dart. Ниже приведена структура файла pubspec.yaml.

image> Важно отметить, что при изменении этого файла необходимо выполнить команду flutter pub get, а также остановить приложение и запустить проект заново, вместо использования hotload.

Ниже представлен пример плагина Flutter. В Flutter различаются два типа проектов:

  • Проект типа Package относится к пакетам Flutter и не включает в себя native код;
  • Проект типа Plugin относится к плагинам Flutter и включает в себя код для Android и iOS.

image

Четвертый раздел: сборка и отладка

Перед запуском Flutter необходимо выполнить команду flutter pub get для синхронизации и загрузки сторонних зависимостей. Сторонние зависимости обычно находятся в директории (Mac) /Users/ваш_пользователь/.pub-cache.

После успешной загрузки зависимостей можно запустить проект Flutter через команду flutter run или нажав кнопку запуска в среде разработки (IDE). Этот процесс требует синхронизации некоторых данных на уровне native проекта, таких как:

  • На Android это может быть синхронизация Gradle и aar зависимостей;
  • На iOS это может быть синхронизация зависимостей через pod install;

Если вы хотите следить за прогрессом синхронизации:

  • Для Android выполните команду ./gradlew assembleDebug в директории android/;
  • Для iOS выполните команду pod install в директории ios/;Если ваш проект использует плагины, содержащие native логику, то в корневой директории проекта будут находиться файлы .flutter_plugins и .flutter-plugins-dependencies. Эти файлы игнорируются системой контроля версий Git, но используются Android и iOS для ссылок на локальные пути плагинов. При запуске Flutter эти пути используются для динамической загрузки зависимостей.image

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

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

Также стоит отметить, что на реальном устройстве iOS 14 запуск приложения в режиме отладки после разрыва соединения невозможен.

Если в проекте возникают проблемы с кэшированием, можно очистить кэш, выполнив команду flutter clean. Почему Flutter не поддерживает горячую перезагрузку?

Ранее мы говорили о том, что React Native и Weex используют JavaScript для преобразования компонентов в нативные контролы, поэтому фактически JavaScript является просто текстом, который можно отправлять с помощью code-push, что не противоречит требованиям платформ.

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

При сборке для Android создаются два динамических библиотеки — app.so и flutter.so; при сборке для iOS создаются два файла — App.framework и Flutter.framework.

V. Краткое введение в FlutterКратко рассмотрим основные моменты Dart в контексте Flutter. Для нативных разработчиков важно понять три ключевых аспекта Flutter: реактивное программирование, компоненты (Widgets) и управление состоянием.### Реактивное программирование

Реактивное программирование также известно как декларативное программирование, это современный подход к фронтенд-разработке, который также становится популярным в мобильной разработке, например, Jetpack Compose и SwiftUI.

Jetpack Compose и SwiftUI имеют много общего на поверхности.

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

На уровне кода нет XML-разметки или storyboard, вся разметка создаётся полностью через код, то есть "что видишь, то и получаешь". Также нет необходимости работать с объектами интерфейса для присваивания значений или обновления; достаточно настроить связи между данными и представлением.

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

Компоненты (Widgets)

Widget — это базовая концепция в Flutter, с которой вы будете взаимодействовать напрямую при написании кода. **Все в Flutter — это Widgets, они являются неизменяемыми (immutable) и каждое состояние Widget представляет собой кадр.**Поэтому Widget как неизменяемый объект не может быть настоящим объектом UI. Настоящими объектами уровня View в Flutter являются Element и RenderObject, где абстракция Element представляет собой часто используемый BuildContext.

Пример:

// Пример использования одного Text в трех местах
class TestPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Hello World'),
        Text('Hello World'),
        Text('Hello World')
      ],
    );
  }
}

Если бы Text был реальным объектом View, он не смог бы использоваться одновременно в нескольких местах внутри одного экрана.изображение

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

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

Как реактивная платформа, Flutter в принципе не стремится к какому-либо конкретному паттерну проектирования, такому как MVC, MVP или MVVVM. Вместо этого он сосредоточен на управлении состоянием интерфейса.

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

В Flutter важнее всего управлять потоками данных, например:- Откуда берутся данные и куда они направляются;

  • Односторонний или двусторонний поток данных;
  • Какие промежуточные преобразования необходимы;
  • С какой слоёной структурой начинается передача данных;
  • Где данные связаны;
  • Как обеспечивается частичное обновление нескольких мест;

Интерфейсу достаточно просто реагировать на изменения данных, поэтому в Flutter существует множество фреймворков для управления и совместного использования данных, такие как provider, getx, flutter_redex, flutter_mobx и другие.

Интересный вопрос

Наконец, хочу затронуть один интересный вопрос, который часто возникает — передаются ли значения или ссылки в Flutter? Этот вопрос вызывает много путаницы в интернете, но на самом деле всё довольно просто:

В Flutter все являются объектами, даже типы данных int, double, bool. Вы думаете, что передаются при работе с объектами?

Однако есть различия в работе с этими объектами. Например, операции над числами типа int и double, такие как +, -, *, /, выполняют методы класса operator, а затем возвращают новый объект типа num.

изображение

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

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master