fa
Feedback
Flutter. Много

Flutter. Много

رفتن به کانال در Telegram

Заказать мобильную разработку: https://amiga.ru//?utm_source=tg Заказать рекламу в канале @amiga_agency_bot Новости Flutter-разработки, дайджесты мероприятий, личный опыт.

نمایش بیشتر
3 009
مشترکین
-424 ساعت
-77 روز
-730 روز
آرشیو پست ها
🎬🎬🎬🎬🎬🎬🎬🎬🎬🎬🎬🎬🎬 📱 Мобильная разработка в ритме города: Day&Night* 2026 Приглашаем мобильных разработчиков на главную конференцию Городских сервисов Яндекса. Саша Аникин расскажет про будущее городов и роботакси, а Кирилл Нейман разберёт техническую архитектуру машины с голосовым управлением. Всё остальное время займут тематические клубы. Мобильное направление курируют Саша Борисков — руководитель разработки клиентской платформы в Еде и Илья Царев — руководитель разработки в Яндекс Go. Обсудим: 🔶 Архитектуру супераппов, песочницы и внедрение ИИ-агентов в мобильную разработку. 🔶 Как делегировать нейросетям рутинную часть разработки. А для души будут клубы музыки и винила и активного образа жизни, где можно выдохнуть и пообщаться с единомышленниками. 🍸 Завершим вечер нашей традиционной вечеринкой до 2 ночи. 🚀 Регистрация открыта — успейте подать заявку! Все заявки проходят модерацию, обязательно дождитесь обратной связи. *День и Ночь

Hola, Amigos! Сегодня мы посмотрим, каким образом мы можем грузить и показывать данные пользователям при помощи пагинации. Па
Hola, Amigos! Сегодня мы посмотрим, каким образом мы можем грузить и показывать данные пользователям при помощи пагинации. Пагинация - способ, который используется для разделения больших данных на небольшие группы (страницы) вместо загрузки всего сразу. Например, для API в 10000 объектов, вместо огромного массива данных, мы будем запрашивать потихоньку: страница 1 (объекты 1-10), страница 2 (объекты 11-20) и т. д. Это помогает нам: • Уменьшить нагрузку на сеть. Меньше данных в запросе - выше скорость его выполнения на сервере и быстрее передача ответа; • Оптимизировать производительность. Меньше объем данных - меньше занимаемой оперативной памяти, быстрее обработка; • Улучшить UX. Пользователи будут видеть новые данные практически, а не когда мы получим и распарсим все объекты. Для того, чтобы правильно сделать пагинацию в мобильном приложении, нужно знать, как она делается на сервере. Тут существует 3 способа: Page-based (стандартный способ) Тут мы запрашиваем данные, передавая page, страницу, и limit - количество элементов. Запрос будет выглядеть примерно так:
GET /posts?page=1&limit=10
Offset-based (гибкий способ) Тут запрос осуществляется с указанием сколько элементов нужно пропустить - offset.
GET /posts?offset=20&limit=10
Cursor-based (профессиональный способ) Самый расширяемый метод. Мы запрашиваем через курсор (обычно ID или timestamp последнего полученного объекта) и получаем данные, которые были добавлены в БД после тех данных, которые мы уже знаем.
GET /posts?cursor=50&limit=10
Последний способ применяется редко, так как он может не подойти под некоторые случаи. Но у первых двух тоже есть недостаток - может возникнуть дублирование или пропажа данных. С тем, как запрашивать данные, мы определились, теперь нужно понять, какая страница последняя? Тут есть 2 варианта - либо API вернет нам номер последней страницы при запросе, либо на последней странице придет число меньше указанного нами лимита. Теперь поработаем с нашим State Manager. Нам нужны состояния - загрузки, успеха и ошибки. И обязательно хранить в них - список полученных данных, страницу (если применяем page-based или offset-based) и при возможности номер последней страницы. Кто-то делает отдельное состояние для загрузки новой страницы, но можно обойтись и без него. И нам нужно 2 функции - для инициализации экрана, чтобы подгрузить первые данные, и для подгрузки во время пагинации. Для BLoC советуем отбрасывать событие подгрузки, если мы находимся в состоянии загрузки. В следующей части расскажем, как привязать это все к UI. А вы делитесь в комментариях, какой способ пагинации чаще всего используете на своих проектах?

Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. Сегодня мы поговорим про то, как лучше всего кешировать карт
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. Сегодня мы поговорим про то, как лучше всего кешировать картинки и в каком качестве их выводить на экран. Часто случается ситуация, что сервер отдает слишком большую картинку. А уж если их несколько на одном экране - могут возникнуть проблемы с производительностью, да и размер кеша может значительно вырасти. Как и все, для кеширования и отображения картинок с интернета, мы используем хорошо знакомую всем библиотеку cached_network_image. Но не все знают, что при помощи нее можно настроить максимальный размер изображения, который будет закеширован и показан на экране. Для этого есть 4 свойства:

maxHeightDiskCache: 300,
maxWidthDiskCache: 300,
memCacheHeight: 300,
memCacheWidth: 300,
Давайте разберемся с ними: maxHeightDiskCache и maxWidthDiskCache отвечают за кеш, который хранится в постоянной памяти. Уменьшая его размер, мы уменьшаем количество данных на устройстве пользователя. memCacheHeight и memCacheWidth отвечают за изображение, которое хранится в ОЗУ и выводится пользователю. Делается это при помощи встроенного в Flutter виджета - ResizeImage. Похожие свойства есть и в Image.network - cacheHeight и cacheWidth. Тут мы указываем именно размер виджета, а не изображения. Теперь давайте рассмотрим, как их использовать. Для того, чтобы правильно подобрать размер, нам нужны: ширина и высота виджета и Device Pixel Ratio - характеристика устройства, которая показывает плотность пикселей. Если размер нам неизвестен либо высчитывается автоматически, то можно прибегнуть к получению constraints через LayoutBuilder. В итоге у нас получается такой код:

LayoutBuilder((context, constraints) {
  final devicePixelRatio = MediaQuery.devicePixelRatioOf(context);
  final cacheHeight = constraints.maxHeight * devicePixelRatio;
  final cacheWidth = constraints.maxWidth * devicePixelRatio;
  return CachedNetworkImage(
    …
    maxHeightDiskCache: cacheHeight,
    maxWidthDiskCache: cacheWidth,
    memCacheHeight: constraints.maxHeight,
    memCacheWidth: constraints.maxWidth,
    …
  );
});
Делитесь в комментариях, пробовали ли вы такой способ оптимизации производительности приложения?

Hola, Amigos! Сегодня обсудим pattern matching. Он сокращает boilerplate, улучшает код и повышает безопасность работы со stat
Hola, Amigos! Сегодня обсудим pattern matching. Он сокращает boilerplate, улучшает код и повышает безопасность работы со state. 1. Деструктуризация с помощью паттернов Пример с Records:

var user = ('Naman', 29);
var (name, age) = user;

print(name);
print(age);
2. Деструктуризация объектов Есть класс:

class User {
  final String name;
  final int age;

  User(this.name, this.age);
}
Можно извлечь свойства так:
var User(:name, :age) = user;
Это эквивалентно:

var name = user.name;
var age = user.age;
3. Pattern Matching в switch Традиционный подход:

if (state is Success) {
  final data = state.data;
}
Подход с pattern matching

switch (state) {
  case Success(data: var data):
    render(data);
  case Loading():
    showLoader();
  case Error(message: var msg):
    showError(msg);
}
4. Сопоставление коллекций Паттерны умеют анализировать списки и map:

switch(list) {
  case []:
    print("Empty");
  case [first, second]:
    print(first);
}

switch(json) {
  case {'status': 'ok', 'data': var d}:
    process(d);
  case {'status': 'error', 'message': var m}:
    showError(m);
}
5. Guard-условия

switch(user) {
  case User(age: var age) when age > 18:
    print("Adult");
  case _:
    print("Minor");
}
А вы используете pattern matching?

Hola, Amigos! Наш Flutter Team Lead Павел Гершевич примет участие в круглом столе на FlutterConf 🙂 Запускаешь новый проект —
Hola, Amigos! Наш Flutter Team Lead Павел Гершевич примет участие в круглом столе на FlutterConf 🙂 Запускаешь новый проект — и снова тот же вопрос: какой state manager выбрать? Проверенный временем? Популярный в комьюнити? Или тот, который сейчас чаще всего советуют? На FlutterConf вынесли тему на открытое обсуждение с аргументами и практическим опытом. Обсудим реальные кейсы, плюсы и минусы подходов, гибкость Flutter и попробуют понять, возможен ли тот самый «золотой стандарт». В обсуждении участвуют:Павел Гершевич, Team Lead Flutter Amiga — Анна Жаркова, руководитель группы разработки Usetech — Олег Скирюк, Frontend Team Lead билайн — Станислав Чернышев, доцент СПбГУАП, автор книги «Основы Dart» — Николай Омётов, руководитель Flutter-отдела Mad Brains — Андрей Смирнов, Dart Dependant Overthinking Specialist Яндекс — Федор Благодырь, разработчик Яндекс ⚙️ Билеты уже в продаже. Круглый стол «Я твой State Manager труба шатал» ⚙️ Москва, 3-я ул. Ямского Поля, 26А ⚙️ 27 февраля, 18:05–19:20 ⚙️ Зал 1 А с промокодом FLUTTER_MNOGO вас ждет скидка 20%

Запланируйте 2026 год вместе с Merge В 2025 году под эгидой Merge прошло сразу четыре события для профессионального IT-сообще
Запланируйте 2026 год вместе с Merge В 2025 году под эгидой Merge прошло сразу четыре события для профессионального IT-сообщества, Мероприятия объединили более 6000 участников и свыше 500 спикеров. Сейчас Merge строит планы на 2026 год. И приглашает всех присоединиться. Merge Innopolis | 17–18 апреля В 2026 году инновационный центр Поволжья, город Иннополис, готовится принять Merge в пятый раз. Все ключевые направления IT на одной площадке. 200+ спикеров, 2000+ участников, 10 потоков докладов по 7 ключевым трекам: «Разработка», «Управление», «Маркетинг», «Аналитика», «HR», «1С», «Карьера в IT». Summer Merge | 3–5 июля Самая летняя IT-тусовка на берегу Волги, неформальный нетворкинг и лучший палаточный уикенд для IT-специалистов. Merge Baltic | 25–27 сентября Профессиональная конференция Merge соберет представителей всех направлений сферы IT на берегу Балтийского моря. Здесь привычную деловую программу и нетворкинг расширит тревел-трек и экскурсии по удивительным местам Калининградской области. По промокоду AMIGA действует скидка 10% на билеты. Успейте присоединиться до повышения цены. Присоединяйтесь!

Hola, Amigos! Async/await и Isolate оба помогают держать UI плавным, но решают разные задачи. Сегодня обсудим, что и в каких
Hola, Amigos! Async/await и Isolate оба помогают держать UI плавным, но решают разные задачи. Сегодня обсудим, что и в каких ситуациях лучше использовать. Неправильно: async/await для CPU-тяжелой задачи

Future<String> processBigData() async {
  final raw = await fetchHugeJson();           // ← I/O — ок
  final data = jsonDecode(raw);                // ← блокирует UI ~1с
  final result = heavyMath(data);              // ← ещё ~1с
  return result;
}
Правильно и просто: compute()

import 'package:flutter/foundation.dart';

Future<String> processBigData() async {
  final raw = await fetchHugeJson();           // сеть — ок

  return compute(_heavyWork, raw);             // ← выполняется в Isolate
}

String _heavyWork(String json) {
  final data = jsonDecode(json);
  return heavyMath(data);
}
Когда нужен полный контроль, подойдет Raw Isolate

Future<void> startWorker() async {
  final receivePort = ReceivePort();
  isolate = await Isolate.spawn(_worker, receivePort.sendPort);
  sendPort = await receivePort.first as SendPort;
}

Future<String> doHeavyTask(String input) async {
  final response = ReceivePort();
  sendPort.send([input, response.sendPort]);
  return await response.first as String;
}

static void _worker(SendPort mainPort) async {
  final port = ReceivePort();
  mainPort.send(port.sendPort);

  await for (final msg in port) {
    final input = msg[0] as String;
    final replyTo = msg[1] as SendPort;
    replyTo.send("processed: $input"); // heavy work here
  }
}
Разберем по ситуации: - Блокирует main thread > ~300 мс → compute() - Просто ждет (network/db) → async/await - Нужен worker с диалогом → raw Isolate А ты пользуешься Isolate/compute или решаешь через async/await? Делись опытом ⚙️

Hola, Amigos! Небольшое обновление 🙂 Мы запустили отдельный канал нашей компании. Теперь все новости агентства, анонсы мероприятий и выступлений, кейсы, а также инсайты про рынок разработки будут выходить там. Этот канал, как и раньше, остается про Flutter ❤️

Repost from Amiga
Hola, Amigos! Совсем скоро нам исполнится 5 лет, и мы наконец-то создали этот канал. Сначала хотим к юбилею отрефлексировать
Hola, Amigos! Совсем скоро нам исполнится 5 лет, и мы наконец-то создали этот канал. Сначала хотим к юбилею отрефлексировать все взлеты и падения, а позже будем делиться интересными инсайтами, анонсами мероприятий и выступлений, мыслями о продуктах и рынке. Уже пять лет мы разрабатываем приложения и сайты — от идеи до выхода продукта на рынок и первых пользователей. Работаем со всем циклом: от аналитики и дизайна до разработки, поддержки и усиления команд. Были и удачные запуски, и сложные решения, и, конечно, ошибки, из которых потом вырастали сильные продукты. Весь февраль будем рассказывать о себе и о том, как мы работаем ⚙️ Велкам!

Hola, amigos! Сегодня разберем подборку Flutter-инструментов, которые прокачивают взаимодействие с пользователем. 1. Dismissi
Hola, amigos! Сегодня разберем подборку Flutter-инструментов, которые прокачивают взаимодействие с пользователем. 1. Dismissible позволяет легко реализовать логику swipe-to-delete.

Dismissible(
  key: Key(item.id),
  background: Container(color: Colors.red),
  onDismissed: (direction) => deleteItem(item.id),
  child: ListTile(
    title: Text("Swipe me to delete"),
  ),
)
2. Tooltip показывает краткую подсказку при долгом нажатии (mobile) или наведении (web/desktop).

Tooltip(
  message: 'Download PDF',
  child: IconButton(
    icon: Icon(Icons.download),
    onPressed: () {},
  ),
)
3. Draggable подходит, чтобы реализовать drag-and-drop, как в Trello или корзине интернет-магазина.

Draggable<Color>(
  data: Colors.blue,
  feedback: Container(
    height: 100,
    width: 100,
    color: Colors.blue.withOpacity(0.5),
  ),
  childWhenDragging: Container(
    height: 100,
    width: 100,
    color: Colors.grey,
  ),
  child: Container(
    height: 100,
    width: 100,
    color: Colors.blue,
  ),
);
4. ReorderableListView идеально подходит для настроек, плейлистов и любых кастомных списков.

ReorderableListView(
  onReorder: (oldIndex, newIndex) {
    setState(() {
      if (newIndex > oldIndex) newIndex -= 1;
      final item = list.removeAt(oldIndex);
      list.insert(newIndex, item);
    });
  },
  children: list
      .map(
        (item) => ListTile(
          key: ValueKey(item),
          title: Text(item.toString()),
        ),
      )
      .toList(),
);
А какими виджетами для UX чаще всего пользуетесь вы? Делитесь в комментариях.

Hola, amigos! Сегодня рассмотрим четыре инструмента, которые помогают писать чище код, избавляться от хардкода и не жертвоват
Hola, amigos! Сегодня рассмотрим четыре инструмента, которые помогают писать чище код, избавляться от хардкода и не жертвовать производительностью. 1. LayoutBuilder работает с реальными ограничениями родительского виджета, чтобы интерфейс получился гибким и предсказуемым на любых устройствах

LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 700) {
      return Row(
        children: [
          Sidebar(),
          Expanded(child: Content()),
        ],
      );
    }
    return Content();
  },
);
2. AnimatedSwitcher позволяет аккуратно анимировать переходы через fade, slide или scale и сразу делает интерфейс «дороже»

AnimatedSwitcher(
  duration: Duration(milliseconds: 300),
  child: Text('$count', key: ValueKey(count)),
);
3. TweenAnimationBuilder закрывает до 80% простых анимаций

TweenAnimationBuilder<double>(
  tween: Tween(begin: 0, end: progress),
  duration: Duration(milliseconds: 500),
  builder: (context, value, child) {
    return LinearProgressIndicator(value: value);
  },
);
4. RepaintBoundary изолирует часть UI и не дает ей перерисовываться без необходимости

RepaintBoundary(
  child: ExpensiveWidget(),
)
А что для в работе используете вы?

Hola, Amigos! Продолжаем разбор полезных Flutter-виджетов для адаптивной верстки. Во второй части еще несколько инструментов,
Hola, Amigos! Продолжаем разбор полезных Flutter-виджетов для адаптивной верстки. Во второй части еще несколько инструментов, которые помогут сделать UI стабильным на разных экранах. 1. FractionallySizedBox. Позволяет задать размер дочернего виджета как долю от размера родителя (по ширине и/или высоте). Use case: когда нужно, чтобы кнопка или контейнер занимали, например, 80% ширины родителя без hardcoded значений.

FractionallySizedBox(
  widthFactor: 0.8,
  child: ElevatedButton(
    onPressed: () {},
    child: Text("Continue"),
  ),
)
Помогает сохранять пропорции на разных экранах и устройствах → UI выглядит консистентно и адаптивно. 2. FittedBox. Масштабирует дочерний виджет так, чтобы он вписался в доступное пространство, сохраняя пропорции (aspect ratio). Use case: когда нужно вписать крупный текст или иконку в небольшую карточку или контейнер без overflow.

FittedBox(
  child: Text(
    "Responsive Title",
    style: TextStyle(fontSize: 40),
  ),
)
Предотвращает ошибки переполнения (overflow) и гарантирует корректное масштабирование UI. Что возьмете в рвботу?

Hola, Amigos! Сегодня разбираем полезные и часто недооцененные виджеты во Flutter, которые реально спасают в реальных проекта
Hola, Amigos! Сегодня разбираем полезные и часто недооцененные виджеты во Flutter, которые реально спасают в реальных проектах 🙂 1. AbsorbPointer. Он блокирует взаимодействия (тапания, жесты) для своего потомка полностью, когда absorbing is true. Use case: запретить двойные тапы на кнопке во время состояния загрузки.

AbsorbbPointer(
  absorbing: isLoading,
  child: isLoadingButton(
    child: ElevatedButton(
      onPressed: () { /* submit */ },
      child: Text("Submit"),
    ),
  ),
)
Позволяет UI оставаться видимым и интерактивным для анимаций, но останавливает ввод пользователя. 2. IgnorePointer. Отключает жесты, но не блокирует layout hit testing. Use case: чтобы UI выглядел «активным», но не реагировал на пользователя.

IgnorePointer(
  ignoring: isReadOnly,
  child: Slider(
    value: sliderValue,
    onChanged: (_) {},
  ),
)
Подойдет, чтобы временно отключить взаимодействие без изменения визуального layout и footprint виджета. AbsorbPointer не пропускает какие-либо действия под собой, а IgnorePointer блокирует только взаимодействие именно с ним. 3. Offstage. Убирает виджет из рендеринга/layout'а, но оставляет его в дереве виджетов. Use case: пре-билдить сложные или дорогие части UI (табы, экраны), но пока не показывать их.

Offstage(
  offstage: !showSettings,
  child: SettingsPanel(),
)
Почему помогает: скрытый виджет остается живым (state, controllers, animations) без влияния на видимый layout и без перестроек каждый раз.

Hola, Amigos! Сегодня делимся простыми, но рабочими лайфхаками, которые помогут сделать ваше Flutter-приложение быстрее, легч
+5
Hola, Amigos! Сегодня делимся простыми, но рабочими лайфхаками, которые помогут сделать ваше Flutter-приложение быстрее, легче и стабильнее. Делитесь в комментариях, пользовались чем-то?

Hola, Amigos! Даже идеально защищенный backend не поможет, если приложение уязвимо на уровне устройства. В финальной части по
Hola, Amigos! Даже идеально защищенный backend не поможет, если приложение уязвимо на уровне устройства. В финальной части посмотрим на безопасность со стороны устройства и пользовательского интерфейса. 1. Запрещайте скриншоты на чувствительных экранах Некоторые чувствительные данные не должны попадать в скриншоты:

@override
void initState() {
  super.initState();
  if (Platform.isAndroid) {
    FlutterWindowManager.addFlags(
      FlutterWindowManager.FLAG_SECURE,
    );
  }
}
2. Используйте биометрию Биометрия нужна не только для логина.

final auth = LocalAuthentication();

await auth.authenticate(
  localizedReason: "Verify to access your bank account",
  options: const AuthenticationOptions(
    biometricOnly: true,
  ),
);
Подходит для различных сценариев: - входа - платежей - доступа к профилю 3. Автоматический логаут и контроль сессии

class SessionManager {
  Timer? _timer;

  void start(void Function() onExpire) {
    _timer?.cancel();
    _timer = Timer(
      const Duration(minutes: 5),
      onExpire,
    );
  }

  void refresh() {
    _timer?.cancel();
  }
}
Выход при: - уходе в фон - бездействии - истечении токена 4. Root / Jailbreak — блокировать

final isRooted = await RootChecker.isRooted();
if (isRooted) {
  exit(0);
}
Не забывайте про использование в нескольких местах и рандомных триггерах, чтобы труднее было подвергнуть приложение реверс-инжинирингу. 5. Код и логи в продакшене

flutter build apk --obfuscate --split-debug-info=./symbols
flutter build ios --obfuscate

if (kDebugMode) {
  print("Token: $token");
}
Надеюсь, советы были полезны и помогут избежать типовых ошибок при разработке приложений на Flutter. Если тема откликнулась — пишите в комментарии!

Hola, Amigos! Продолжаем разговор о безопасности приложений на Flutter. Даже при корректной аутентификации приложение остаетс
Hola, Amigos! Продолжаем разговор о безопасности приложений на Flutter. Даже при корректной аутентификации приложение остается уязвимым, если сетевой слой и серверная валидация реализованы неправильно. В этой части поговорим о защите сетевых запросов, доверии к данным и проверке OTP. 1. SSL pinning — обязательное требование Без pinning HTTPS не спасает от атаки MITM (Man In The Middle), когда злоумышленники перехватывают трафик между приложением и сервером, а потом читают или подменяют запросы через прокси или wi-fi:

final context = SecurityContext(withTrustedRoots: false);
context.setTrustedCertificatesBytes(certBytes);

final httpClient = HttpClient(context: context);

final dio = Dio()
  ..httpClientAdapter = IOHttpClientAdapter(
    createHttpClient: () => httpClient,
  );
Это блокирует: - proxy - fake Wi-Fi - подмену сертификатов 2. OTP всегда проверяется на сервере Проверка OTP на клиенте — критическая уязвимость:
if (enteredOtp == "123456") success();
Только сервер:

await api.verifyOtp(
  mobile: mobile,
  otp: enteredOtp,
);
3. Клиентская валидация — не финальная. Данные всегда проверяются на сервере:

bool isValidAmount(String value) {
  final amount = double.tryParse(value);
  return amount != null && amount > 0 && amount < 100000;
}
Эти меры закрывают большую часть рисков, но сами по себе они не решают все. Даже при защищенном трафике и корректной логике на бэке приложение остается уязвимым на уровне устройства и интерфейса. В следующей части разберем защиту UI, работу с сессиями и ограничения на уровне устройства.

Hola, Amigos! Сегодня начнем серию постов о банковских приложениях на Flutter. В таких проеках цена ошибок в безопасности нам
Hola, Amigos! Сегодня начнем серию постов о банковских приложениях на Flutter. В таких проеках цена ошибок в безопасности намного выше, чем в обычных mobile-проектах. В нескольких частях разберем практические подходы к защите Flutter-приложений в банковском контексте. В первой части начнем с фундамента: хранения данных и аутентификации. Именно здесь чаще всего закладываются уязвимости, которые потом сложно исправить. 1. Не храните данные в открытом виде Сохранение токенов в SharedPreferences — прямой путь к компрометации:

final prefs = await SharedPreferences.getInstance();
prefs.setString("token", token);
Используйте зашифрованное хранилище:

final secureStorage = FlutterSecureStorage();

await secureStorage.write(
  key: "access_token",
  value: token,
);

final token = await secureStorage.read(key: "access_token");
2. Только token-based аутентификация Cookies и сессии не подходят для банковских приложений. Токен должен добавляться ко всем запросам централизованно:

class AuthInterceptor extends Interceptor {
  final FlutterSecureStorage storage;

  AuthInterceptor(this.storage);

  @override
  void onRequest(RequestOptions options, handler) async {
    final token = await storage.read(key: "access_token");
    if (token != null) {
      options.headers["Authorization"] = "Bearer $token";
    }
    handler.next(options);
  }
}
3. Никогда не хардкодьте личные данные API-ключи и токены не должны попадать в репозиторий:

const apiKey = "sk_test_123456";
Правильно:

const apiKey = String.fromEnvironment("API_KEY");
Передача через CI:
--dart-define=API_KEY=your_key_here
А что происходит, когда аутентификация уже выстроена, но трафик можно перехватить, а OTP проверяется на клиенте? В следующей части разберем сетевую безопасность, SSL pinning и работу с OTP⚙️

Hola, Amigos! Хотим поделиться с вами классной новостью. 5 декабря прошла церемония награждения премии Tagline Awards 2025 —
Hola, Amigos! Хотим поделиться с вами классной новостью. 5 декабря прошла церемония награждения премии Tagline Awards 2025 — главной награды за достижения в digital-сфере. В премии участвует 500+ известных брендов и агентств, а награды вручаются за уровень работ, качество их исполнения и эффективность решения коммерческих задач🔥 Делимся победами! В этом году мы заняли: 🏆 2 место в номинации «Лучший сайт об услугах» с кейсом разработки сайта для федеральной сети клиник 🏆 3 место в номинации «Лучшее ритейл-приложение» с кейсом мобильного приложения CMstore 🏆 А также мы попали в шорт-лист номинации «Лучшая кампания для искусства/культуры/развлечений» с нашим первый мероприятием — народным рейтингом «Люди ИТ-индустрии» Спасибо команде за работу и заказчикам за доверие ❤️ Особенно радует, что наш рейтинг, который мы вместе с Alto и Телеграмошной реализовали за пару месяцев, попал в шорт-лист! Замотивированы развиваться и дальше предлагать рынку свежие идеи ⚙️ Пишите свое мнение в комментариях, мы будем рады вашему фидбеку)

Hola, Amigos! Заканчиваем год, но продолжаем выступать на мероприятиях! 11 декабря наш Mobile Team Lead Павел Гершевич выступ
Hola, Amigos! Заканчиваем год, но продолжаем выступать на мероприятиях! 11 декабря наш Mobile Team Lead Павел Гершевич выступит с докладом «Как не стоит делать корзину для мобильного e-com приложения». В своем выступлении он поделится: ⚙️ почему лучше вести разработку с одной командой, а не с несколькими разными; ⚙️ почему проектировать API должен тот, кто будет его использовать, а не разработчик бэкенда; ⚙️ опыт исправления ошибкок на проекте, где API диктовалось не командой МП, а командой Backend. А для самых внимательных слушателей Павел подготовил подарок! За лучший вопрос он подарит экземпляр своей книги «Основы Flutter», о презентации которой мы недавно писали. Митап пройдет в Красноярске, регистрируйтесь на сайте!

Hola, Amigos! Очень нужна ваша поддержка на Tagline Awards! Сейчас идет народное голосование, в котором у нас участвует 4 про
Hola, Amigos! Очень нужна ваша поддержка на Tagline Awards! Сейчас идет народное голосование, в котором у нас участвует 4 проекта: ⚙️ Сайт-путеводитель для самой северной точки Евразии — если Териберка надоела, можно заглянуть на Таймыр к оленям :) Сделали все, чтобы выбрать экскурсию и подобрать маршрут было удобно ⚙️ Travelpayouts: перезапустили инструмент для поиска авиабилетов — освежили дизайн и внутреннюю логику, осуществили поддержку 61 языка, включая арабский, чтобы справа налево тоже читалось ⚙️ Мобильное приложение CMstore — запустили приложение, где можно купить (или просто посмотреть) дайсоны, последние айфоны и другую технику ⚙️ Народный рейтинг «Люди ИТ-индустрии» — наш дебют в мероприятиях. Совместно с Alto и Телеграмошной запустили рейтинг, где можно голосовать не за кейсы или компании, а за людей, которые раскачивают индустрию Будем рады и благодарны вашим голосам❤️