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

Новости Flutter-разработки, дайджесты мероприятий, личный опыт.
Download Telegram
Hola, Amigos! На связи Михаил Чернецов, Flutter Dev в Amiga. Сегодня разберем пакет bloc_concurrency, который позволяет манипулировать обработкой событий в BLoC и содержит в себе набор трансформеров 🙂

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

MyBloc() : super(MyState()) {
on<MyEvent>(
_myEvent,
transformer: concurrent(),
);
}


Трансформеры передаются через поле transformer в методе on. Для каждого отдельного события (event) можно задать свой трансформер. Если нужно применить один трансформер ко всем событиям, создайте абстрактный класс событий и назначьте его трансформеру.

abstract class MyAbstractEvent {}
class OtherEvent extends MyAbstractEvent {}

MyBloc() : super(MyState()) {
on<MyAbstractEvent>(
…,
transformer: concurrent(),
);
}


bloc_concurrency включает четыре типа трансформеров:

🔴 concurrent — обрабатывает все события одновременно; используется в bloc по умолчанию.

🔴 sequential — обрабатывает события последовательно, применяя asyncMap. Подходит для случаев, когда требуется поочередная обработка, например, при добавлении товара в корзину по одному.

🔴 restartable — прерывает обработку текущего события, если поступает новое. Полезен, когда каждое новое событие может полностью изменить результат, как при обновлении строки поиска: в этом случае нас не интересует результат обработки предыдущего ввода.

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

Ставьте 🔥, если было полезно и делитесь в чате, пользуетесь ли данным пакетом?
Please open Telegram to view this post
VIEW IN TELEGRAM
Hola Amigos! На связи Михаил Чернецов, Flutter Dev, и Павел Гершевич, Mobile Team Lead в Amiga. Сегодня расскажем, как собираем приложения под Android.

Существует два вида собираемых файла под Android: APK (Android Package Kit) и Android App Bundle (AAB). Рассмотрим их особенности.

APK — это исполняемый файл, а App Bundle — формат публикаций.

Сборка APK

Запускаем команду:

flutter build apk


Однако такой APK подписан debug-ключом и не подходит для публикации. Чтобы создать релизный ключ, используем инструмент keytool из JDK.

Для Windows:

keytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks `
-storetype JKS -keyalg RSA -keysize 2048 -validity 10000 `
-alias upload


Для macOS и Linux:

keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \
-keysize 2048 -validity 10000 -alias upload


Не забудьте указать правильный путь и имя файла ключа. Затем создаем файл /android/key.properties для подписи:

storePassword=<пароль от KeyStore>
keyPassword=<пароль от самого ключа>
keyAlias=upload
storeFile=<местоположение файла с ключом>


Теперь APK готов к публикации, но он универсальный и достаточно объемный. Чтобы уменьшить размер, лучше собрать отдельные APK для каждой архитектуры процессора:

flutter build apk --split-per-abi


На выходе получим несколько APK, которые можно зарелизить. Однако они будут крупнее по сравнению с теми, что пользователи смогут скачать из магазинов приложений с использованием AAB.

Сборка AAB

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

Для сборки AAB:

1) Подготовьте файл для подписи приложения.
2) Запустите команду:

flutter build appbundle


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

Когда использовать APK?

Сборка APK также важна, например, для тестирования — чтобы не выкладывать каждую сборку в магазины приложений. Или если приложение распространяется вне Google Play, App Gallery или RuStore.

Если вам нужен экспертный взгляд или помощь в сборке и публикации приложения, пишите нам. Будем рады помочь!
«Попали в сердечко»🥹

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

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

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

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

Смотрите фотки и ставьте 🔥, если ждете записи докладов!
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
Никогда еще не был космос так близко

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
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
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
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
Дайджест сентября

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

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

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

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

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

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

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

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

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

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

Hola, amigos!

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

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

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

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

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

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

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

До встречи! 🙂
Hola, Amigos!

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

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

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

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

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

Делитесь в чате, используете ли вы RxDart на своих проектах и как он вам помогает? А мы поделимся еще несколькими полезными концептами во второй части!