- Android app on dart
- Три относительно честных способа создания Flutter проекта
- Теперь за дело. Сейчас мы сделаем следующее
- Устанавливаем Flutter и создаём проект из командной строки
- Устанавливаем JDK , Android Studio (вместе с Android SDK) и необходимые плагины
- И наконец, устанавливаем VS Code, расширения, и создаём третий Flutter проект
- Миграция мобильного приложения на Dart 2.12 (Flutter 2)
- Кто такой и зачем нужен Flutter?
- Что появилось во Flutter 2?
- Подготовка к миграции кода
- Миграция кода
- Автоматическая миграция
- Впечатления от миграции
- P.S. Об «Инфосфере»
Android app on dart
Для разработки под Flutter нередко выбирается такая среда разработки как Android Studio . Хотя мы можем набирать код и в простейшем текстовом редакторе и компилировать его в консоли, но среда разработки существенно позволяет упостить процесс написания и построения приложения. Причем Android Studio позволяет создать приложения на Flutter не только собственно под Android, но и под другие поддерживаемые платформы.
Для работы с Android Studio ее естественно вначале надо установить. Инсталлятор можно загрузить по ссылке https://developer.android.com/studio.
По умолчанию Android Studio не поддерживает Flutter, поэтому нам надо установить соответствующий плагин. Для этого в Android Studio на стартовом экране выберем пункт Plugins (либо в открытой студии перейдем в меню File -> Settings и далее в открывшемся окне также выберем пункт Plugins ). И в панели плагинов найдем плагин Flutter :
Для упрощения поиска нужного плагина мы можем ввести в поисковую стоку слово «Flutter», и первый результат будет как раз тем, который надо установить. При установке плагина также отобразится окно с предложением установить плагин для Dart. Также нажмем на ОК для его установки:
После установки плагина необходимо будет перезагузить Android Studio.
После перезагрузки на стартовом экране в Android Strudio мы можем увидеть кнопку New Flutter Project :
Нажмем на эту кнопку для создания проекта под Flutter.
В качестве альтернативы для создания проекта в студии можно перейти в меню к пункту File -> New -> New Flutter Project :
Далее нам откроется окно создания нового проекта. В левой части выберем пункт Flutter , а в центре в поле Flutter SDK path укажем путь к Flutter SDK:
На следующем окне укажем ряд настроек проекта:
В поле Project name дадим проекту какое-либо имя. Так, в моем случае он называется hello_app .
В поле Project location можно изменить расположение проекта, если предложенное расположение по умолчанию не устраивает.
В поле Description можно указать описание проекта
В поле Project type указывается тип проекта. По умолчанию он имеет значение Application (то есть проект предназначен для создания приложения). Оставим это значение по умолчанию.
В поле Organization можно задать название для пакета приложения. Можно оставить по умолчанию, а можно и изменить. Например, в моем случае это com.metanit .
В поле Android language указывается язык для Android. Можно оставить значение по умолчанию — Kotlin .
В поле iOS language указывается язык для платфомы iOS. Можно оставить значение по умолчанию — Swift .
В поле Organization можно задать название для пакета приложения. Можно оставить по умолчанию, а можно и изменить. Например, в моем случае это com.metanit .
В поле Platforms можно указать платформы, под которые будет создаваться проект. По умолчанию отмечены пункты Android и iOS, но можно выбрать и другие доступные платформы. Так, как видно выше на скриншоте, я также выбрал пункт «Web» для создания проекта под веб.
И затем после установки всех настроек нажмем на кнопку «Finish» для непосредственного создания проекта. Сразу после создания Android Studio откроет созданный проект:
Созданный проект будет иметь ту же самую структуру, что был создан в прошлой теме в консоли с помощью команды flutter create . В центре студии будет открыт файл main.dart , который содержит собственно код приложения.
Подключим к компьютеру устройство Android (или воспользуемся эмуляторами) и в панели Android Studio нажмем на зеленую стрелочку для запуска приложения.
Подобным образом в Android Studio можно запускать проект и под другие «устройства», например, под web. Для этого лишь нужно выбрать соответствующее устройство в панели инструментов:
Источник
Три относительно честных способа создания Flutter проекта
Итак, с презентацией Google первой стабильной версии Flutter, которая случилась 4 декабря 2018 г. начался процесс изменения ландшафта на полях мобильного программирования. Появился новый игрок, способный изменить правила самой игры. Теперь из одной базы кода можно создавать сразу два нативных (т.е. «родных» для среды выполнения) приложения — для iOS и Android. В отличие от т.н. гибридных приложений, которые под капотом используют JavaScript, приложения созданные на Flutter работают быстро и плавно, поскольку код написанный на языке программирования Dart (для тех кто знаком с Java или C# с этим языком будет комфортно) затем компилируется (AoT , т.е. предварительно) в машинный код: отдельно для Android, и отдельно для iOS.
Поэтому, если вы изучите Dart и Flutter, вы сможете писать нативные приложения для двух самых популярных мобильных операционных систем, т.е. быть одновременно Android и iOS разработчиком. И это, вероятно, ещё не предел, поскольку было объявлено, что Google ведёт работу по расширению Flutter на предмет возможности создания с его помощью приложений для Windows, Mac и Web (проект Flutter для Web носит название Hummingbird — Колибри). В итоге может получиться так, что зная Dart и Flutter вы сможете писать всё очень многое. Поэтому многие IT эксперты назвали 2018 год — годом Flutter.
Теперь за дело. Сейчас мы сделаем следующее
Устанавливаем Flutter и создаём проект из командной строки
Переходим на страницу установки Flutter, выбираем свою операционную систему — Windows, Mac или Linux (здесь будет описано для Windows 10, как наиболее популярной ОС), и скачиваем zip файл, содержащий Flutter SDK . Затем распаковываем zip, например, в папку текущего пользователя, как показано на скриншоте:
Сейчас пропишем путь к flutter\bin в переменную Path среды пользователя Windows (Этот компьютер -> Свойства -> Дополнительные параметры системы -> Переменные среды):
Можно создавать проект из командной строки Windows:
Готово! Файлы проекта можно редактировать любым текстовым редактором, хоть в блокноте. Но это хорошо разве что для мелких правок. Поэтому мы…
Устанавливаем JDK , Android Studio (вместе с Android SDK) и необходимые плагины
Теперь скачиваем Android Studio. Запускаем процесс установки, следуя за мастером установки, и обращаем внимание на путь, куда будет установлен Android SDK . Создаём системную переменную среды ANDROID_SDK_TOOLS с указанием пути к папке \tools в Android SDK, примерно так:
Когда всё готово — запускаем Android Studio, и устанавливаем плагины Flutter и Dart. Для этого в начальном экране Android Studio справа внизу жмём на значок шестерёнки и выбираем Plugins:
В открывшемся окне внизу нажимаем кнопку Browse repositories.
В поисковую строку вводим flutter, выбираем и устанавливаем (у меня уже установлен, поэтому не видно соответствующей кнопки):
Android Studio предложит также установить плагин Dart от которого зависит работа плагина Flutter. Соглашаемся. В итоге у вас должно быть установлено как минимум два плагина:
Перезапускаем Android Studio, и теперь давайте убедимся, что всё идёт хорошо. Для этого в командной строке выполним команду:
Сканирование займёт десяток секунд, и затем вы можете увидите примерно такой результат:
Вот мы и готовы создать Flutter проект в Android Studio. После установки плагинов Flutter и Dart в начальном экране Android Studio должна появится опция Start a new Flutter project. Выбираем её:
Далее соглашаемся с выбранной по умолчанию опцией Flutter Application и нажимаем кнопку Next:
Наконец, указываем доменное имя (которое в реверсивном порядке будит использовано как ID Android приложения), а также опционально — поддержку языков Kotlin и Swift (если не указать — по умолчанию будут поддерживаться только Java и Objective-C). Нажимаем кнопку Finish.
В зависимости от производительности компьютера, ждём несколько минут пока проект будет создан… Готово! Он должен выглядеть примерно так:
Обратите внимание на стрелку, указывающую на вкладку Flutter Inspector. В этом инспекторе имеется функционал, позволяющий делать ряд очень полезных во время разработки вещей, в т.ч. просмотр приложения на девайсе Android в режиме представления на iOS!
И наконец, устанавливаем VS Code, расширения, и создаём третий Flutter проект
Скачиваем последнюю версию Visual Studio Code для своей операционной системы, устанавливаем на свой компьютер, следуя за мастером установки, и запускаем VS Code. Затем на боковой панеле нажимаем на кнопку Extensions (показана стрелкой) или на клавиатуре — Ctrl+Shift+X:
С помощью поиска ищем расширение Flutter.
VS Code, как и в случае с Android Studio, предложит установить необходимое дополнительное расширение Dart. Устанавливаем и его. В итоге должны иметь два (или более) активированных расширения:
А теперь создаём Flutter проект. Нажимаем на значок шестерёнки в левом нижнем углу, и выбираем Command Pallete. (или на клавиатуре — Ctr+Shift+P). В командной строке Command Pallete начинаем печатать flutter, и из появившегося списка выбираем Flutter: New Project:
Даём проекту название и нажимаем клавишу Enter:
Появится диалоговое окно, предлагающее выбрать папку, в которой необходимо создать Flutter проект. Выбираем и нажимаем кнопку с длинным названием Select a folder to create the project in:
Источник
Миграция мобильного приложения на Dart 2.12 (Flutter 2)
3 марта 2021 года разработчики Google представили Flutter 2. Что появилось в новой версии языка Dart? Как теперь быть с разработкой и поддержкой приложений, созданных с использованием Flutter предыдущих версий? И, самое главное, насколько сложно будет мигрировать на версию 2? В этой статье подробно опишем опыт миграции приложения на новую версию Flutter и проблемы, которые могут возникнуть в процессе миграции.
Кто такой и зачем нужен Flutter?
Для тех, кто набрел на статью случайно и понятия не имеет, что такое Flutter — это технология от Google для разработки кроссплатформенных мобильных приложений — да, да приложения будут работать и на Android, и на iOS устройствах. Flutter активно завоевывает сердца разработчиков и очень быстро идет от только мобильной разработки к Web и Desktop. Он достаточно прост в освоении, позволяет отказаться от одновременной разработки двух приложений для Android и iOS, он показывает высокую производительность и значительно ускоряет разработку приложений. Ну не прелесть ли? Первая версия была представлена в начале 2018, а спустя два года мы уже видим Flutter 2 с весьма серьезными доработками и нововведениями.
Что появилось во Flutter 2?
Наиболее громкие изменения:
Новая версия языка Dart 2.12 c «Sound null safety»;
Выход «Flutter for web»;
Большой шаг к мультиплатформенности с «Flutter for desktop».
Разработчики обещают, что миграция существующих решений на Flutter 2 должна пройти просто и быстро, есть гайды по миграции с примерами простых приложений, но можем ли мы им доверять, имея на руках приложение с множеством экранов, общающееся с сервером по api и использующее внешние библиотеки?
Если изменения по части Web и Desktop не затрагивают существующие приложения, то «sound null safety» может потребовать доработок. Почему и зачем «sound null safety» вообще нужна? «Sound null safety» — это фича, которая появилась в новой версии языка Dart 2.12, вышедшей вместе с Flutter 2.0. На просторах сети уже довольно много сказано о нововведениях и о «null safety», поэтому очень подробно на этом останавливаться не будем. Но для целостности картины происходящего немного все же нужно сказать.
До появления «Sound null safety» все переменные в языке Dart могли принимать значение null. Если разработчик забывал добавить проверку на null перед использованием переменной, то во время работы приложения внезапно можно было получить экран со следующим содержанием:
Не самые приятные события. Разработчики понимают, что такую проверку легко забыть сделать, и, если вместо ссылки на экземпляр определенного типа мы получаем null, который «ничего не знает» о методах и состояниях экземпляра, мы имеем красный экран смерти с «NoSuchMethodError».
Решить эту проблему призван «Sound null safety», основные принципы которого:
Безопасность кода по умолчанию — все переменные, которые мы создаем, по умолчанию будут non-nullable, пока мы не разрешим им другого поведения.
Простота написания кода — с этим все понятно: не хотелось бы в обмен на безопасность получать сложности в написании и понимании кода.
Непротиворечивость кода — если мы определяем какую-то переменную как переменную non-nullable типа, то она абсолютно точно никогда не будет равна null. Как сказал Евгений Сатуров в своем подкасте, это самый главный принцип «Sound null safety», и загадочное «sound» переводится именно как «непротиворечивость».
Итак, в языке Dart иерархия типов претерпевает некоторые изменения:
Null больше не является подтипом для всех типов, а существует по соседству с ними. Если у нас есть переменная типа String, то она всегда будет содержать строку. Но на практике, конечно, случаются ситуации, когда нужно использовать null в качестве значения для переменной.
В таком случае можно воспользоваться соседом-компаньоном типа, допускающим значение null. В нашем случае этот тип — String?. Мы как будто заранее заставляем себя и других разработчиков сомневаться в том что в этой переменной будет строка: может, будет, а может, и нет.
Ниже пример использования этого типа в деле приготовления бургеров:
Пользоваться переменными с «?» небезопасно, поэтому нужно прибегать к дополнительным проверкам на null или специальным операторам .
Более подробно о новой иерархии типов можно почитать в официальной документации здесь.
В изменениях типов по умолчанию кроются сложности и страхи миграции проекта на Flutter 2. Второй момент, вызывающий опасения, — это сторонние пакеты из pub.dev. На момент написания статьи более 85% пакетов из топ-250 на pub.dev уже поддерживают «null safety». Никто, конечно, не застрахован от того, что нужный пакет и вовсе больше не поддерживается, поэтому перед использованием стоит проверить нужный пакет на pub.dev.
Подготовка к миграции кода
Начнем переезжать на Flutter 2, подсматривая в официальный гайд с использованием мигратора.
Первым делом, конечно же, обновляем Dart и Flutter до последних версий с помощью команды:
Вместе с Flutter’ом обновляется и Dart до версии 2.12.
Помимо SDK, нужно обновить плагины Flutter и Dart, сделать это можно в среде разработки. В AndroidStudio откроем Settings->Plugins. Там нас уже ждут кнопочки “Update”. Для применения апдейта обязательно потребуется перезапуск среды.
Далее проверяем, что все пакеты, которые мы используем в своем проекте, обновлены до версии с поддержкой «null safety». Сделать это можно с помощью команды:
Выполнять ее нужно из директории проекта, оттуда, где лежит файл pubspec.yaml, который как раз анализируется на присутствие устаревших пакетов. Если такие пакеты в проекте есть, в консоли будет подсказка с информацией, кому из них требуется обновление, с какой версии пакета начата поддержка «null safety», и какая версия наиболее свежая. У нас целых 5 таких пакетов.
Здесь Dart подсказывает нам, что для автоматической смены версий пакетов можно воспользоваться командой:
Пробуем, не получается…
Кажется, пакет device_id все еще не может в «null safety». На pub.dev выясняется, что все еще хуже: обновляли его последний раз в апреле 2019. Но есть и хорошие новости, этот пакет в проекте используется только в одном месте при формировании http запросов к серверу для определения ID устройства. Уходит некоторое время на поиски и тестирование альтернативы, удается найти «null safety» пакет, в котором есть методы для определения ID устройства, — platform_device_id. Если бы такой альтернативы не нашлось, пришлось бы делать форк и допиливать пакет самостоятельно. Добавляем platform_device_id актуальной версии в pubspec.yaml вместо device_id. Пробуем выполнить апгрейд пакетов еще раз.
Теперь все сработало отлично, пакеты обновлены!
Другой путь обновления пакетов: поправить версии руками в pubspec.yaml, а потом выполнить команды:
Результат будет таким же.
Сразу переходить к миграции кода в нашем случае не получается: в проекте появились ошибки. Методы post() и get() пакета http в новой версии поменяли тип аргумента uri, вместо String теперь нужен Uri. Эта проблема тоже довольно быстро решается с помощью метода Uri.parse().
После обновления SDK, плагинов и пакетов проект все еще собирается и работает, но остается самый главный шаг — миграция кода.
Миграция кода
Ее можно осуществить вручную или воспользоваться мигратором, вызвав команду:
Мигратор проводит анализ нашего проекта и, если все хорошо, отдает ссылку, перейдя по которой можно найти “предложения по миграции”, в которых мы видим файлы исходного кода нашего проекта с автоматически внесенными изменениями, поддерживающими «null safety».
Напротив каждого файла — цифра с количеством изменений, которые мигратор внес в него. Есть нетронутые файлы, но есть и те, в которых достаточно много правок.
Рассмотрим более подробно предлагаемые изменения. Где-то мигратор добавил «?» к типу поля или переменной, сделав его nullable.
Появились комментарии /* no valid migration */ как в примере к строчке, где метод возвращает null, а принимающая сторона этого не ждет.
В окошке справа от кода можно найти подробности о причинах внесения тех или иных изменений, например, такие причины для приведения к nullable поля title:
поле не является final, значит его значение может измениться после определения в конструкторе;
его значение задается другой переменной, которая может быть не инициализирована при создании.
Здесь же можно воспользоваться кнопочками «Add…», чтобы добавить к типу String /*!*/, сообщив мигратору, что мы уверены, что это поле должно быть non-nullable, перезапустить миграцию и понаблюдать, как меняется код, использующий это поле. Вот, например, при передаче «meter.customName» в конструктор ButtonItem появился «!».
Пробежавшись по коду, можно заметить, что везде, где есть использование nullable, но требуется non-nullable переменная, мигратор добавил оператор «!». Он «уговаривает» метод или выражение, которое ждет только non-nullable, взять из наших рук nullable. Оператор «!» относится к null-aware операторам, таким как «?.», «??», «!.» (подробно про их использование можно почитать здесь).
Мигратор часто использует оператор «!» в коде, но, так как это может быть небезопасно, нужно обязательно проверить каждое появление «!» и проанализировать, можно ли как-то это избежать.
Вместо «!» подойдет простая проверка на null, но не всегда. Можно встретить, например, вот такую ситуацию с полем meters:
Проверка есть, но мигратор все равно добавляет «!».
Оказывается, проверка на null перед использованием «перетаскивает» на светлую non –nullable сторону только локальные переменные и не работает с полями класса. На простых примерах это выглядит так:
Такое поведение объясняется тем, что обращение к полю класса может скрывать за собой обращение к геттеру, а внутри геттера может быть реализована какая-то функция, меняющая свое поведение в зависимости от ситуации. При сохранении значения поля в локальную переменную и работе с ней мы уже не беспокоимся о том, что значение самого поля могло поменяться.
Оператор «?.» – равнозначен проверке на null, но с ним тоже лучше быть осторожнее. В примере ниже метод addIce() просто не вызовется.Приложение не упадет, но что, если для дальнейшей работы приложения выполнение этого метода было критично?
Еще обойти опасный «!» там, где это возможно, хорошо помогает оператор «??», позволяющий заменить возможный null на значение по умолчанию.
Перед некоторыми полями классов мигратор добавил слово late.
Ключевое слово late позволяет обойти использование nullable типов для полей класса, когда они не инициализируется сразу, но и значение null не является для них необходимым. В примере ниже получим ошибку компиляции, так как поле «burgerName» не может быть nullable и не инициализируется сразу либо в конструкторе.
Следующий фрагмент кода будет работать, но для поля «burgerName» значение null бесполезно и скрывает за собой возможность получить ошибку при неаккуратном обращении.
Ключевое слово late позволяет избежать необходимости делать это поле nullable.
Здесь стоит обратить внимание на то, что такая инициализация все равно не является абсолютно безопасной. Если поменять местами последние две строки кода из примера выше, то ошибки компиляции не будет, но произойдет ошибка «LateInitializationError» во время работы приложения, так как поле «burgerName» не было проинициализировано.
Еще одним применением ключевого слова late является «ленивая» инициализация полей класса.
В нашем случае поле «burgerName» будет инициализировано не при создании экземпляра класса «ComboMeal», а при первом обращении к нему. Такой прием может быть полезен, когда мы уверены в том, что инициализация потребует много ресурсов, но не обязательно будет вызвана.
Автоматическая миграция
Насколько долго придется дорабатывать код после миграции? В нашем проекте около 1200 строк кода. Я потратила на внесение изменений немного времени — около одного рабочего дня. Предлагаю оставить этап несогласия с мигратором и правок за кадром и нажать кнопку “Apply Migration”, чтобы понять, насколько работоспособен код после автоматической миграции.
Предложения по миграции приняты, в исходном коде проекта появились все изменения. Пробуем собрать проект, получаем ошибки компиляции.
В первую очередь, видим ошибки там, где были комментарии /* no valid migration */. Это те места, где в методах возвращается или передается null. Правим.
Второй тип ошибок компиляции после миграции связан с удалением конструктора по умолчанию для списка в языке Dart. То есть нельзя больше объявить список таким образом:
Это решение было принято разработчиками из-за того, что конструктор по умолчанию создает список определенного размера, но не инициализирует его элементы, то есть все они имеют значение null. Такой конструктор теперь нельзя применить даже для списка, допускающего содержание nullable элементов. Для разрешения этой проблемы в зависимости от ситуации можно воспользоваться инструментами создания фиксированного или нефиксированного списка – List.empty(), List.generate(), List.fill(), []. Правим места с использованием конструктора по умолчанию.
Ошибки компиляции закончились, приложение собирается, запускается. Согласитесь, довольно быстро.
На этом миграцию приложения можно считать успешной, но с небольшими оговорками.
Впечатления от миграции
Автоматическая миграция не отдает 100% рабочего кода. Но, справедливости ради, стоит признать — так получается из-за того, что исходный код не обеспечивает «null safety». Возможно, если провести какую-то предварительную подготовку, то таких проблем не будет. С другой стороны, правки после миграции были не сложными, заняли не так уж много времени, и вдобавок список ошибок акцентирует внимание на проблемах, которые можно было и не заметить при подготовке.
Выбор мигратора делать переменную/поле nullable или non-nullable, судя по всему, полностью зависит от их использования в коде. Это хорошо прослеживается в окошке с причинами добавления nullable к типу в «предложениях по миграции». Понятно, что нельзя полностью уйти от использования null. Например, при получении данных от сервера и декодировании json-ответов в классы невозможно гарантировать, что все поля будут заполнены, как мы ожидаем. Мигратор, конечно, сам не догадается о контексте и не сделает все поля response-класса nullable. Разработчику придется уделить время на доработку, чтобы получить хороший код.
Встречались еще странные моменты с использованием ключевого слова «late» для полей класса, которые инициализируются в конструкторе. Часть из этих полей мигратор отмечал как «late», а часть делал nullable, как, например, ниже:
Но все это опять же легко поправилось.
Документация по «null-safety» языка Dart и вообще вся документация Dart и Flutter отлично написана, в ней можно найти ответы на большинство возникших вопросов, связанных с работой nullable или non-nullable. Ну и конечно, когда при написании нового кода на Dart 2.12 встает вопрос — делать переменную nullable или non-nullable, лучше выбирать non-nullable и работать с этой концепцией пока не станет очевидно, что без nullable не обойтись.
В целом, процесс миграции оказался довольно простым. Думаю, потраченное время стоит того, чтобы в будущем не ловить красные экраны во время работы приложения. Всем успехов в миграции и разработке!
P.S. Об «Инфосфере»
В завершение стоит немного рассказать о мобильном приложение, которое было героем этой статьи и переживало миграцию на Flutter 2. Оно является частью платформы «Инфосфера», которая разработана центром проектирования программного обеспечения компании «Миландр».
«Инфосфера» представляет собой целый комплекс приложений для мониторинга и управлениями различными умными устройствами. Сейчас наша платформа используется в разных отраслях промышленности и городской среды: ЖКХ, энергетике, спортивно-развлекательных комплексах. Само мобильное приложение предоставляет пользователю информацию о его устройствах и позволяет управлять ими удаленно.
Источник