Flutter. Много
2.76K subscribers
333 photos
23 videos
258 links
Заказать мобильную разработку: https://amiga.agency/?utm_source=tg
Заказать рекламу в канале @amiga_agency_bot

Новости Flutter-разработки, дайджесты мероприятий, личный опыт.
Download Telegram
«Попали в сердечко»🥹

Hola, Amigos! Ради такой обратной связи мы готовы тратить 30 часов на подготовку докладов и 8 часов еще много-много раз.

Множество вопросов от аудитории после лекции — плюс еще одно доказательство, что нам удалось угадать с интересными и актуальными темами. Ес!💪🏼

Напомним, что Паша Гершевич, Flutter Team Lead выступал с докладом «Логирование на Flutter или какие метрики помогут в оптимизации».

А Артем Салеев, CTO Amiga — с темой «Перестройка процессов разработки при масштабировании агентства».

Смотрите фотки и ставьте 🔥, если ждете записи докладов!
🔥18👏2🤩1
Hola Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. Сегодня снова затронем тему автоматического тестирования, а точнее получение процента покрытия нашего кода тестами ⚙️

Первый шаг — запустить тесты с параметром coverage:


flutter test --coverage


Эта команда сгенерирует файл с информацией о покрытии, но для его расшифровки понадобится инструмент lcov, доступный только для Unix-систем.

Установка lcov

Для Linux (на примере Ubuntu):


sudo apt-get update -qq -y
sudo apt-get install lcov -y


Для macOS:


brew install lcov


Генерация отчета в HTML

Далее, конвертируем полученный файл в удобный для чтения HTML-формат:


genhtml coverage/lcov.info -o coverage/html


Теперь в папке coverage/html можно просматривать отчет по покрытию. Однако тут возникает проблема: отчет может не учитывать все файлы вашего проекта, так как покрываются только те файлы, которые явно были импортированы в тесты.

Решение проблемы с неполным покрытием

Чтобы охватить все файлы, нужно импортировать их в тесты через специальный файл, например, coverage_helper_test.dart. Этот процесс можно автоматизировать с помощью скрипта:


file=test/coverage_helper_test.dart
echo "// Helper file to make coverage work for all files\n" > $file
echo "// ignore_for_file: unused_import" > $file
find lib -name "*.dart" "!" -name "*.g.dart" | cut -c4- | awk -v package="my_package" '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file
echo "void main(){}" >> $file


Тут мы создаем файл coverage_helper_test.dart, ставим игнорирование определенного правила статического анализа на один файл и импортируем наши файлы.

⚙️ Важное правило: не импортировать файлы, которые были сгенерированы, можно дополнять такой скрипт файлами от freezed и других библиотек. В конце добавляем метод main, чтобы импорты попали в покрытие.

Автоматизация на CI/CD

Скрипт сохраняем в файл с расширением .sh и запускаем перед тестами.


./coverage_helper.sh


Все эти шаги можно интегрировать в ваш CI/CD процесс для автоматической проверки покрытия кода тестами.

А как вы подходите к тестированию? Какие используете методики? 🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍5🥰4
Никогда еще не был космос так близко

Hola, Amigos! Полетели в Санкт-Петербург на XII международную IT-конференцию «Стачка». 27 и 28 сентября в гостинице Cosmos вы сможете зарядиться атмосферой новых знаний, революционными идеями и вдохновением по направлениям:

⚪️ разработка
⚪️ дизайн и контент
⚪️ digital-маркетинг
⚪️ управление
⚪️ стартапы и технологии

Павел Гершевич, Team Lead Flutter от команды Amiga выступит с докладом «Это больше, чем биометрия. Или как сделать локальную аутентификацию в мобильном приложении».

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

Обязательно приходите 28 сентября в 17:25 в зал Разработка-2.

Специально для вас действует промокод «спикер_10». Покупайте билеты со скидкой! А с программой можно ознакомиться тут.

Взлетаеееем!⚙️
Please open Telegram to view this post
VIEW IN TELEGRAM
4👏42
Hola, Amigos! С вами Павел Гершевич, Mobile Team Lead в Amiga. В прошлый раз мы рассмотрели, как получить покрытие кода тестами в обычных проектах. Сегодня разберемся с многомодульными проектами ⚙️

Применив предыдущие команды, можно получить покрытие для каждого отдельного пакета. Однако, чтобы увидеть общую картину, нужно объединить результаты. Для этого мы используем Melos и специальные скрипты.

Начнем с обновления скрипта для генерации покрытия. Он должен работать с каждым пакетом отдельно. Добавим проверку на наличие папки test, и, если ее нет, создадим:

package=$1
if [ ! -d “test” ]; then
mkdir test
fi


Далее заменим в скрипте статическое название пакета на переменную:

package=$package


Теперь скрипт сможет корректно обрабатывать все модули.

Чтобы объединить результаты покрытия, создадим скрипт, который соберет все данные в один файл:

escapedPath=”$(echo pwd | sed ‘s/\//\\\//g’)”
if grep flutter pubspec.yaml > /dev/null; then
if [ -d “coverage” ]; then
if [ ! -d “$MELOS_ROOT_PATH/coverage_report” ]; then
mkdir “$MELOS_ROOT_PATH/coverage_report”!
fi
sed “s/^SF:lib:$escapedPath\/lib/g” coverage/lcov.info >> “$MELOS_ROOT_PATH/coverage_report/lcov.info”
rm -rf “coverage”
fi
fi


Этот скрипт ищет папки с покрытиями, объединяет файлы lcov.info в один общий и сохраняет его в папке coverage_report в корне проекта. После этого можно создать HTML-отчет о покрытии кода тестами ⚙️

А как вы обычно отслеживаете покрытие кода в своих проектах? Рассказывайте в чате.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👏5👍2
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. Сегодня расскажем, как заменять разные сервисы (Google Play Services, Huawei Mobile Services, RuStore и др.) в одном приложении на примере Push-уведомлений, используя многомодульность.

Создадим несколько пакетов:
mobile_services_interface
gps
hms

Теперь определим основные функции. В нашем случае это Push-уведомления: инициализация, получение токена и обработка открытия уведомлений. Для этого создадим в пакете mobile_services_interface абстрактный класс.


abstract interface class IPushService {
Future<void> init();
Future<String> getToken();
Future<void> onOpenPush();
}


Можно добавить свои функции или создать такие же классы для сервисов аналитики, Remote Config или др. Настроим зависимости для каждого пакета в pubspec.yaml.

🔵 Для Google Play Services:


mobile_services_interface:
path: ../mobile_services_interface
firebase_messaging: ^latest_version


🔵 Для Huawei Mobile Services:


mobile_services_interface:
path: ../mobile_services_interface
huawei_push: ^latest_version


Теперь напишем классы, расширяющие интерфейс. Помимо этого, можно вынести настройки сервисов в соответствующие пакеты.

Для сборок используем flavors, т.к. делать нам это нужно только для Android.

Перед публикацией заменяем пакет в pubspec.yaml и корректируем строку создания объекта в Dependency Injection. Затем выбираем необходимый flavor и собираем приложение с его конфигурацией.

А как вы решаете задачи с поддержкой разных платформ и сервисов в одном приложении? Расскажите о своем опытом в чате ⚙️
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7🥰3👍2
Hola, Amigos! На связи Михаил Чернецов, Flutter Dev в Amiga. Сегодня расскажем, как избавиться от написания шаблонного кода на проекте⚙️

Mason — набор для командной строки, позволяющий унифицировать процесс создания файлов с шаблонным кодом без надобности написания своих плагинов для IDE. Это ускоряет разработку и позволяет больше фокусироваться на написании фич.

Для установки выполним команду:

dart pub global activate mason_cli


Далее инициализируем Mason в нашем проекте:

mason init


Для создания первого шаблона, который в Mason называется brick, необходимо прописать команду:

mason add (имя шаблона)


Это создаст папку __bricks__/my_brick в корне проекта. Внутри можно настроить структуру, а для генерации классов — использовать переменные.

Шаблоны в Mason не ограничены один файлом. Можно создать шаблоны на генерацию кода для разных библиотек, репозитории, State Management и страницы для одной фичи.

vars:
name:
type: string
description: Name of your class


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

mason make (имя шаблона)


Создадим сам шаблон. В папку brick помещаем необходимые файлы {{name.snakeCase()}}.dart. И в нем же создаем шаблон для этого файла:

class {{name.snakeCase()}} {
final String {{name.camelCase()}}

{{name.snakeCase()}}(
this.{{name.camelCase()}},
);
}


При вызове mason make с флагом –name my-class будет создан файл my_class.dart, содержащий код:

class MyClass{
final String myClass;

MyClass(
this.myClass,
);
}


Готовые шаблоны можно найти на сайте.

Делитесь в чате используете ли вы Mason в своих проектах? 🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
👍54🔥3
Дайджест сентября

Hola, Amigos! Собрали в одну подборку все полезные посты и статьи сентября, которые вы могли пропустить. Выбирайте, что вам интересно, и переходите по ссылкам.

⚪️ Обзор виджета Draggable

⚪️ Как сделать динамические иконки для приложения

⚪️ Обзор пакета local_auth

⚪️ Обзор пакета bloc_concurrency

⚪️ Сборка приложения для Android

⚪️ Определение покрытия тестами для обычных проектов и для многомодульных

⚪️ Интеграция нескольких мобильных сервисов в Flutter приложение под Android

⚪️ Обзор инструмента Mason

Всем хорошего кода! 🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
👍51
Выиграй участие в конференции CrossConf!

Hola, amigos!

Вместе с организаторами конференции CrossConf дарим 2 билета на крупнейшее мероприятие по кросс-платформам с мощнейшим Flutter-потоком.
Встречаемся 08 ноября в Москве в Start Hub на Красном Октябре в режиме офлайн и онлайн.

В программе очень крутые доклады по 🦋Flutter от эффективного BDUI и работы с логами до Divkit и Flame.

Участвовать в розыгрыше просто:

1️⃣ Подпишись на нас @flutter_amiga и на @crossconf

2️⃣ Нажми “Участвую” под этим постом

3️⃣ Жди публикации результатов розыгрыша 10 октября

И скажем по секрету, Павел Гершевич, Mobile Team Lead в Amiga, тоже там выступит!

До встречи! 🙂
👍145🔥3🤩1
Hola, Amigos! Рассказываем, как для нас прошла XIII Международная IT-конференция «Стачка» в Санкт-Петербурге.

Наш Mobile Team Lead Павел Гершевич выступал с докладом “Это больше, чем биометрия. Или как сделать локальную аутентификацию в мобильном приложении”. Было мощно: реальные примеры, полезные советы и много вопросов от участников! Но еще больше получили благодарностей от слушателей. А вот и «спасибо» от самого Паши:

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


Смотрите фотки и ставьте 🔥, если ждете записи докладов!
🔥191
Hola, Amigos!

На связи Павел Гершевич, Mobile Team Lead агентства продуктовой разработки Amiga. Сегодня рассмотрим некоторые базовые концепции пакета rxdart. Он позволяет нам работать с потоками данных еще эффективнее, так как добавляет много всего полезного.

RxDart - пакет от компании ReactiveX, которые до него уже сделали много популярных библиотек для других языков программирования. Например, RxJava или RxSwift. Но так как в Dart уже есть стримы, их не добавляли, но дополнительно улучшили, добавив методы расширений и новые типы потоков данных.

Давайте посмотрим для начала на то, как мы можем добавить буферизацию к нашему Stream. Допустим, что у нас есть поток данных, который выдает информацию достаточно часто, а нам нужно получать ее не по одному, а сразу несколько штук. Для этого мы можем воспользоваться добавлением еще одного потока данных, который будет отмерять время, просто передать количество, функцию для определения конца отрезка или необходимый отрезок времени, а функции buffer, bufferCount, bufferTest и bufferTime вернут нам список данных, который накопился.

Также иногда нам нужно отбрасывать данные и брать только последнее, что приходит. Для этого пригодятся методы debounce и debounceTime. В первый мы можем передать какой-нибудь другой Stream и при получении в него событий, получать данные и в изначальном. Во второй мы просто передадим время для промежутков с выдачей информации.

А что делать, если нужно объединить несколько потоков данных? Для этого у RxDart заготовлены несколько конструкторов. Например, MergeStream, который просто добавляет события из всех стримов в себя, или CombineLatestStream, который позволяет производить какие-либо вычисления, когда в один из стримов приходит событие, в этом случае, для других берутся последние значения.

Делитесь в чате, используете ли вы RxDart на своих проектах и как он вам помогает? А мы поделимся еще несколькими полезными концептами во второй части!
👍11🔥53❤‍🔥1
Hola, Amigos!

На связи Павел Гершевич, Mobile Team Lead агентства продуктовой разработки Amiga. Мы продолжаем изучать концепции и полезные функции в rxdart.

В прошлый раз мы забыли про троттлинг. Он похож на debounce, но возвращает не последнее, а первое значение, что полезно при обработке различных случаев, например, отправки форм. Для него можно использовать методы throttle и throttleTime.

Еще давайте затронем фильтрацию данных внутри стримов, так как это часто необходимо. Да, в Dart есть метод where, но его может не хватать или он будет слишком большим в коде. Поэтому в rxdart есть расширение whereType, которое позволяет фильтровать по типу без применения cast, и его дополнение - whereNotNull, которое убирает все нулевые значения из потока данных.

Еще одно полезное расширение - distinctUnique. Оно позволяет нам сохранять в стриме только уникальные значения. Очень похоже на применение toSet().toList() для списков.

И самое главное, что добавляет rxdart - это новые StreamController, которые здесь называются Subjects. Их 2 - BehaviorSubject и ReplaySubject. Давайте посмотрим на каждый из них.

BehaviorSubject - контроллер, который при добавлении слушателя сразу же передает ему последнее значение, которое попало в стрим. Также ему можно задать изначальное значение при помощи конструктора BehaviorSubject.seeded.

ReplaySubject - контроллер, который при добавлении слушателя сразу же передаст все значения, которые в него попадали. Но если нам нужно возвращать последние N значений, то мы можем применить в его конструкторе параметр maxSize.

Делитесь в чате, как часто вы используете стримы на своих проектах?
9👍5❤‍🔥3🔥2🥰1