ru:https://highload.today/blogs/kak-sozdat-prilozhenie-na-flutter-web-i-obojti-podvodnye-kamni/ ua:https://highload.today/uk/blogs/kak-sozdat-prilozhenie-na-flutter-web-i-obojti-podvodnye-kamni/
logo
Mobile app      08/09/2021

Как создать приложение на Flutter Web и обойти подводные камни без вреда для проекта

Елена Бойко BLOG

Android & Flutter Developer в NIX

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

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

На сегодня Flutter Web уже вышел в стабильной версии, а это дает бóльшие гарантии как для разработчиков, так и для продукта. Обычно в продакшне мы не используем библиотеки и фреймворки в бете. А в случае с Flutter Web уже есть стабильная версия инструментария.

Flutter интуитивно понятен и довольно легок в освоении: и в этой статье я покажу это на практике. Мы выясним, как с его помощью всего за один день можно создать веб-приложение при уже имеющихся мобильных приложениях. Также выясним, какие подводные камни таит в себе Flutter Web и как их обойти без вреда для проекта.

С чего начать

Чтобы приступить к разработке веб-приложения на Flutter Web, нужно выполнить несколько команд: 

flutter config --enable-web // добавление поддержки веба в файл настроек
flutter create . //  добавление поддержки веба в текущем проекте
flutter build web // создание релизного билда

В этой статье детально разберем команду flutter build web, отвечающую за создание папки web, которую затем можно разместить на веб-сервере. Это основная команда для создания проекта. Также выясним, что из себя представляет папка web.

Структура Flutter Web 

Папка web, которая создается через команду flutter build web, имеет следующий вид:

Папка web

Папка web

Давайте заострим внимание на трех ключевых файлах и поймем, за что они отвечают: 

  • index.html — простая html-страница, к которой подключаются другие файлы;
  • flutter_service_worker.js — скрипт, который способен перехватывать и изменять команды по запросу ресурсов, а также выполнять кэширование данных;
  • Онлайн-курс Frontend-разробник від Powercode academy.
    Курс на якому ти напишеш свій чистий код на JavaScript, попрацюєш із різними видами верстки, а також адаптаціями проектів під будь-які екрани. .
    Зарееструватися
  • main.dart.js — сердце нашего веб-приложения, основной файл, ответственный за работу приложений на Flutter Web.

Генерацию main.dart.js можно увидеть на примере компиляции его кода с языка Dart в JavaScript:

Генерация main.dart.js

Генерация main.dart.js

Любое приложение, созданное на Flutter Web, обрабатывается при помощи движка Flutter Web Engine. Он содержит библиотеки и API, которые преобразовывают код в более низкоуровневый (для работы с html, CSS и Canvas). Компилятор Dart2js преобразовывает код с Dart в JavaScript.

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

Подводные камни Flutter Web

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

Отсюда следует правило:

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

Дополнительный список официальных плагинов для работы с Firebase также есть на сайте. Здесь можно увидеть, какие именно платформы поддерживают плагины: мобильные, web или desktop.

Где хранить данные и как реализовать сохранение на Flutter Web

Во Flutter Web существует четыре варианта, где можно хранить данные: Cookies, Local Storage, Session Storage и IndexedDB. Давайте сравним их и выделим сильные и слабые стороны каждого.

Курс English For IT: Communication від Enlgish4IT.
Почни легко працювати та спілкуватися з мультикультурними командами та міжнародними клієнтами. Отримайте знижку 10% за промокодом ITCENG.
Інформація про курс

Сравнение вариантов для хранения данных

Cookies Local Storage Session Storage IndexedDB
 

Тип данных

Пары ключ-значение, строковые Пары ключ-значение, строковые Пары ключ-значение, строковые Пары ключ-значение, разные типы данных
Отправка вместе с запросом Да Нет Нет Нет
Размер 4 Кб 5 Мб 5 Мб Зависит от браузера и свободного места на диске
Время хранения Expiry time / не ограничено Не ограничено До закрытия вкладки Не ограничено
 

 

Назначение

Персонализации и отслеживания действий пользователя Локальное хранилище небольших объемов данных между сессиями Локальное хранилище небольших объемов данных в пределах одной вкладки Локальное хранилище больших объемов данных между сессиями

Давайте разберем подробнее:

  • Cookies — небольшие фрагменты данных (весом 4 Кб), которые отправляются сервером и хранятся на устройстве веб-пользователя. По типу данных Cookies являются строковыми парами ключ-значение. Срок их хранения задается свойством expiry time или не ограничивается по времени.
  • Local Storage — свойства глобального объекта браузера window. Данные здесь, как и в Сookies, хранятся в виде строковых пар ключ-значение, а время их хранения не ограничено. Для каждого домена браузер создает свой Local Storage. Доступ к данным в происходит гораздо быстрее, чем в Cookies. 
  • Session Storage похож на Local Storage за исключением одного принципиального отличия — времени хранения данных. Session Storage существует только в рамках текущей вкладки браузера. Используется он намного реже, нежели Local Storage.
  • IndexedDB представляет собой встроенную базу данных с индексами. Не имеет срока хранения, поэтому отлично подходит как локальное хранилище больших объемов данных между сессиями.

Сохранение данных на Flutter Web может быть реализовано такими способами:

  • Ручная реализация — используя библиотеки dart:html, dart:js, dart:indexed_db.
  • Реализация при помощи готовых плагинов, поддерживаемых Flutter Web. Сегодня существует множество плагинов, которые охватывают типичные кейсы сохранения данных на вебе.
  • Курс Frontend від Mate academy.
    Frontend розробник може легко створити сторінки вебсайту чи вебдодаток. Тому після курсу ви станете затребуваним фахівцем у сфері, що розвивається.
    Інформація про курс

Отличия в сохранении данных на мобильной и веб-версиях Flutter

Разберем этот кейс на примере Shared Preferences. Наиболее подходящим способом хранения данных здесь является Local Storage. Сохранение легко реализовывается вручную посредством библиотеки dart:html:

import ‘dart:html’;
window.localStorage[‘selected_id’] = id;

Как видите, мы обращаемся к свойству localStorage объекта window и сохраняем туда необходимые нам значения. Сложность этого подхода в том, что нужно писать две различные версии кода — для мобильной и для веб-версии приложения.

Так было до лета 2020 года, пока на сайте не появился плагин Shared_Preferences. Он добавил поддержку веба и способность сохранять данные в Local Storage для браузера, в NSUserDefaults — для iOS, в Shared Preferences — для Android.

SharedPreferenced prefs = await SharedPreferences.getInstance();
prefs.setInt(“selected_id”, id);

Сохранение локальных баз данных во Flutter Web

В этом случае можно использовать Local Storage, IndexedDB или же прибегнуть к помощи библиотеки sql.js. Но наиболее удобным выбором здесь станет использование готового ORM-решения. Сегодня одним из самых лучших ORM-плагинов является moor. Его функционал охватывает практически все типичные кейсы работы с базами данных, за исключением некоторых (пока еще здесь не реализована поддержка сущностей embedded). 

Moor

Создание БД для мобильный и веб-версий происходит по-разному:

import ‘package:moor_flutter/moor_flutter.dart’;
MyDatabase createDb() {
        return MyDatabase(FlutterQueryExecutor.inDatabaseFolder(path: ‘db.sqlite’));
}

import ‘package:moor/moor_web.dart’;
MyDatabase createDb() {
        return MyDatabase(WebDatabase(‘db’));
}

Используются разные импорты (moor_flutter и moor_web). Именно здесь и таится первый подводный камень — невозможно одновременно импортировать данные из разных библиотек. Для веб-приложения нельзя использовать мобильную версию и наоборот. Чем обусловлено такое ограничение и как его обойти?

Дело в том, что во Flutter Web невозможен импорт библиотеки dart:io, которая используется для работы с файлами, сокетами и другими io-составляющими.

Но мы можем воспользоваться особой фичей языка Dart — условным импортом, который позволяет импортировать библиотеки при наличии заданного условия. 

Пример условного импорта библиотеки выглядит так:

Курс English For Tech: Speaking&Listening від Enlgish4IT.
Після курсу ви зможете найкраще презентувати свої досягнення, обговорювати проекти та вирішувати повсякденні завдання англійською мовою. Отримайте знижку 10% за промокодом TCENG.
Дізнатись про курс
import ‘src/stub_impl.dart’
    if (dart.library.io) ‘src/io_impl.dart’
    if (dart.library.html) ‘src/web_impl.dart’
    as some_lib;

Как видно из примера, импорт будет совершен при условии, что текущая версия приложения поддерживает библиотеки dart.library.io или dart.library.html соответственно.

Кэширование ресурсов в браузере и Assets

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

Ситуацию можно исправить несколькими способами:

  • Cache-busting — основная идея в том, чтобы добавлять к URL-адресу ресурса информацию, связанную с версией приложения, хеша содержимого или же временными метками. Вы можете модифицировать название файла или добавлять новые параметры (через «?»), благодаря чему ресурс будет восприниматься как новый, и браузер загрузит его обновленную версию.
  • Service worker — скрипт, который способен перехватывать запрос на ваши ресурсы и модифицировать их. В нем можно прописать стратегию, по которой будет реализовано кэширование.

 На практике оба подхода применяются одинаково успешно. 

Responsive UI 

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

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

Нужно самостоятельно проверить какое-либо условие (например, размер экрана), а затем — используя if и else, указать параметр, который нужно применить для выбранной ширины экрана:

Курс Job Interview Crash Course від Enlgish4IT.
Отримайте 6 шаблонів відповідей на співбесіді, які ви зможете використовувати для структурування своїх відповідей. Отримайте знижку 10% за промокодом ITCENG.
Приєднатися
@override
Widget build(BuildContext context) {
    final screenWidth = MediaQuery.of(context) .size.width;
        
    return (screenWidth < 500)
        ? NarrowWidget()
        : WideWidget();
}

Но как узнать, какие начальные данные нужно указать для if и else? Можно прибегнуть к помощи MediaQuery — особому виджету, содержащему информацию о размере и ориентации экрана.

Еще один способ — использование константы kIsWeb. Метод покажет, было ли приложение скомпилировано для работы в вебе или нет. Таким образом можно понять, где именно открыто приложение — на мобильном устройстве или в браузере. Также можно использовать плагины platform_detect и web_browser_detect.

ResponsiveWidget и альтернативные варианты написания UI для веб-приложений

Чтобы постоянно не прописывать if и else в местах, где необходимо получить разный дизайн экрана, можно использовать ResponsiveWidget:

class MainScreen extends StatelessWidget {

    @override
    Widget build(BuildContext context) {
        return ResponsiveWidget.of(context).resolve(
            xLarge: (_) => MainWebScreen(),
            mobile: (_) => MainMobileScreen(),
        )(context);
    }
}

Здесь виден основной экран приложения (MainScreen). В его методе build используется ResponsiveWidget, который затем передал в метод resolve варианты виджетов для разных типов экрана. В методе resolve реализована логика получения информации об экране. Затем resolve возвращает виджет, предназначенный для текущего размера экрана.

Существуют и альтернативные варианты создания UI для веб-приложений:

  • Bootstrap-подход: экран условно разбивается на сетку, а элементы интерфейса размещаются в одну или несколько колонок в зависимости от ширины экрана. Скачать плагин можно по ссылке.
  • Scaling-подход: элементы интерфейса увеличиваются или уменьшаются в зависимости от размера экрана. К этому варианту часто прибегают, когда дизайн для мобильного приложения и его веб-версии отличаются незначительно (размером или масштабируемостью элементов). Ознакомиться с плагином можно здесь.

Навигация во Flutter Web

Навигация во Flutter Web может быть реализована тремя способами:

  1. Использование вместо простых методов навигатора их Named-версий. Строчные параметры, которые вы туда передадите, и будут частью вашего URL после имени домена: Navigator.push -> Navigator.pushNamed.
  2. Курс Fullstack Web Development від Mate academy.
    Стань універсальним розробником, який може створювати веб-рішення з нуля.
    Дізнатись про курс
  3. Использование плагинов, подходящих под ваши решения в реализации навигации. Здесь отметим fluro и flutter modular.
  4. Использование API: Navigator 2.0 — в нем содержится класс RouteInformationParser, который можно унаследовать и написать свой URL Parser для перехода на нужный скрин.

Описанные методы навигации на Flutter далеки от идеала, но они активно обновляются, так что советую следить за новинками и читать патчноуты. 

Нереализованные свойства и недостатки 

Среди распространенных «болячек», от которых до сих пор не излечился Flutter Web, часто выделяют следующие:

  • отсутствует hot reload  — реализован только hot restart; 
  • не все браузеры поддерживают стандартные шрифты;
  • отсутствует поддержка SEO;
  • довольно низкая производительность в мобильных браузерах.

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

Курс UX/UI дизайнер сайтів і застосунків з Alice K.
Курс від практикуючої UI/UX дизайнерки, після якого ви знатимете все про UI/UX дизайн .
Реєстрація на курс

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

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Англійська для IT від Englishdom.
В межах курсу можна освоїти ключові ІТ-теми та почати без проблем говорити з іноземними колегами.
Дійзнайтеся більше

Этот материал – не редакционный, это – личное мнение его автора. Редакция может не разделять это мнение.

Топ-5 самых популярных блогеров марта

PHP Developer в ScrumLaunch
Всего просмотровВсего просмотров
2229
#1
Всего просмотровВсего просмотров
2229
Founder at Shallwe, Python Software Engineer (Django/React)
Всего просмотровВсего просмотров
111
#2
Всего просмотровВсего просмотров
111
Career Consultant в GoIT
Всего просмотровВсего просмотров
93
#3
Всего просмотровВсего просмотров
93
CEO & Founder в Trustee
Всего просмотровВсего просмотров
92
#4
Всего просмотровВсего просмотров
92
Рейтинг блогеров

Ваша жалоба отправлена модератору

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: