Как Baidu переносила бизнес-логику iOS и Android на Kotlin Multiplatform
В приложении Wonder одинаковые правила отдельно реализовывали на Swift и Kotlin. Изменения приходилось синхронизировать между командами, а корректность проверять дважды. Связанный с логикой интерфейс также мешал повторно использовать код и писать модульные тесты.
Команда начала с общего слоя данных: объединила модели, REST-запросы, разбор JSON и кеш данных по ключу. Нативные интерфейсы iOS и Android сохранили. Позже часть интерфейсной логики перенесли на шаблон MVI для управления состоянием, а настройку модулей упростили собственными плагинами Gradle.
Подключение модуля добавляло 2 МБ из-за встроенной среды выполнения, а отладка общего Kotlin-кода для iOS сводилась к логам и замедлялась по мере роста проекта. Кейс Baidu показывает порядок внедрения и ограничения, которые стоит проверить на пилотном модуле.
В приложении Wonder одинаковые правила отдельно реализовывали на Swift и Kotlin. Изменения приходилось синхронизировать между командами, а корректность проверять дважды. Связанный с логикой интерфейс также мешал повторно использовать код и писать модульные тесты.
Команда начала с общего слоя данных: объединила модели, REST-запросы, разбор JSON и кеш данных по ключу. Нативные интерфейсы iOS и Android сохранили. Позже часть интерфейсной логики перенесли на шаблон MVI для управления состоянием, а настройку модулей упростили собственными плагинами Gradle.
Подключение модуля добавляло 2 МБ из-за встроенной среды выполнения, а отладка общего Kotlin-кода для iOS сводилась к логам и замедлялась по мере роста проекта. Кейс Baidu показывает порядок внедрения и ограничения, которые стоит проверить на пилотном модуле.
Как найти причину утечки памяти в Android с LeakCanary
Утечка возникает, когда приложение сохраняет ссылку на уже ненужный объект. LeakCanary строит leak trace: цепочку сильных ссылок от неудаляемого корня сборщика мусора до удерживаемого объекта. По состоянию и жизненному циклу объектов инструмент сокращает список подозрительных ссылок.
В примере из статьи синглтон Application хранит TextView в списке. TextView через поле mContext удерживает уничтоженную MainActivity. Такая цепочка указывает, где искать причину: View добавили в долгоживущую коллекцию приложения.
В руководстве LeakCanary разложены четыре этапа: получить цепочку, сузить подозрения, найти ссылку, которая вызывает утечку, и убрать её. LeakCanary выполняет первые два этапа, а решение в коде остаётся разработчику.
Утечка возникает, когда приложение сохраняет ссылку на уже ненужный объект. LeakCanary строит leak trace: цепочку сильных ссылок от неудаляемого корня сборщика мусора до удерживаемого объекта. По состоянию и жизненному циклу объектов инструмент сокращает список подозрительных ссылок.
В примере из статьи синглтон Application хранит TextView в списке. TextView через поле mContext удерживает уничтоженную MainActivity. Такая цепочка указывает, где искать причину: View добавили в долгоживущую коллекцию приложения.
В руководстве LeakCanary разложены четыре этапа: получить цепочку, сузить подозрения, найти ссылку, которая вызывает утечку, и убрать её. LeakCanary выполняет первые два этапа, а решение в коде остаётся разработчику.
square.github.io
Fixing a memory leak - LeakCanary
A memory leak detection library for Android
Было: качаешь альбом через торрент трое суток, боишься выключить компьютер. Стало: включаешь трек в одно нажатие и не думаешь, где он хранится.
Между этими двумя точками — двадцать пять лет, которые SpaceWeb прошёл вместе с рунетом. Анкета к юбилею компании как раз про этот путь.
Между этими двумя точками — двадцать пять лет, которые SpaceWeb прошёл вместе с рунетом. Анкета к юбилею компании как раз про этот путь.
Как отделить данные от интерфейса во Flutter с помощью репозитория
Репозиторий помещают в слой данных между источником и бизнес-логикой. Он вызывает REST API или базу данных, преобразует JSON в типизированные сущности и отдаёт их приложению. Виджеты не зависят от сетевого клиента и формата ответа, а изменение стороннего API исправляют только в репозитории.
В примере
Репозиторий помещают в слой данных между источником и бизнес-логикой. Он вызывает REST API или базу данных, преобразует JSON в типизированные сущности и отдаёт их приложению. Виджеты не зависят от сетевого клиента и формата ответа, а изменение стороннего API исправляют только в репозитории.
В примере
WeatherRepository задаёт получение погоды по городу, а реализация запрашивает OpenWeatherMap и разбирает ответ. В тестах сетевой код заменяют тестовым репозиторием. Абстрактный класс для этого необязателен: в Dart у каждого класса есть неявный интерфейс. Разбор Repository Pattern для Flutter сравнивает абстрактные и конкретные классы и показывает полный код приложения.🥱3❤2
Как ловить визуальные регрессии в Android Compose с Paparazzi
Скриншот-тест рендерит компонент или экран и сравнивает снимок с эталоном. Paparazzi запускает такую проверку на JVM без устройства и эмулятора. Можно быстро прогнать разные экраны, но библиотека использует LayoutLib и наследует ограничения превью Android Studio.
В разборе показан цикл: подключить плагин, вызвать
Добавляйте проверку в CI как дополнение к другим тестам. Для задуманного изменения эталон перезаписывают; визуальную регрессию исправляют. Если снимков много, автор советует Git LFS, чтобы не раздувать Git-репозиторий.
Скриншот-тест рендерит компонент или экран и сравнивает снимок с эталоном. Paparazzi запускает такую проверку на JVM без устройства и эмулятора. Можно быстро прогнать разные экраны, но библиотека использует LayoutLib и наследует ограничения превью Android Studio.
В разборе показан цикл: подключить плагин, вызвать
paparazzi.snapshot в JUnit-тесте, записать эталон через recordPaparazziDebug, затем сравнить кадр командой verifyPaparazziDebug. Отчёт покажет эталон, результат и различия.Добавляйте проверку в CI как дополнение к другим тестам. Для задуманного изменения эталон перезаписывают; визуальную регрессию исправляют. Если снимков много, автор советует Git LFS, чтобы не раздувать Git-репозиторий.
🎉2
Как использовать @MainActor для интерфейса в Swift
@MainActor привязывает класс, метод, свойство или замыкание к глобальному актору, задачи которого идут в главном потоке. В конкурентном коде так компилятор проверяет контекст обновлений UI вместо ручных вызовов DispatchQueue.main.async.
В Swift 6.2 новые проекты Xcode 26 по умолчанию изолируют код приложения главным актором. Тяжёлые вычисления можно вынести из главного актора через nonisolated или @concurrent, чтобы не задерживать интерфейс.
В режиме Swift 5 остаётся ловушка: синхронный @MainActor-метод из неизолированного контекста может выполниться в потоке вызывающего кода. Swift 6 ловит большинство таких случаев при компиляции. Разбор SwiftLee сравнивает MainActor.run с Task { @MainActor in } и объясняет ограничения assumeIsolated.
@MainActor привязывает класс, метод, свойство или замыкание к глобальному актору, задачи которого идут в главном потоке. В конкурентном коде так компилятор проверяет контекст обновлений UI вместо ручных вызовов DispatchQueue.main.async.
В Swift 6.2 новые проекты Xcode 26 по умолчанию изолируют код приложения главным актором. Тяжёлые вычисления можно вынести из главного актора через nonisolated или @concurrent, чтобы не задерживать интерфейс.
В режиме Swift 5 остаётся ловушка: синхронный @MainActor-метод из неизолированного контекста может выполниться в потоке вызывающего кода. Swift 6 ловит большинство таких случаев при компиляции. Разбор SwiftLee сравнивает MainActor.run с Task { @MainActor in } и объясняет ограничения assumeIsolated.
👍1
Как собрать переиспользуемую пагинацию во Flutter на Riverpod
Материал разбирает бесконечную ленту на Flutter без отдельного пакета пагинации. Автор строит общий контроллер поверх
Подключаемая примесь хранит текущий индекс, загружает первую страницу и добавляет следующую к уже полученным элементам. Конкретному экрану остаётся определить начальный индекс, запрос данных и способ вычислить следующий индекс. В интерфейсе
В руководстве Динко Маринаца есть схема слоёв, реализация поиска и фильтров и полный пример кода. Разбор предполагает знакомство с MVVM и репозиторием.
Материал разбирает бесконечную ленту на Flutter без отдельного пакета пагинации. Автор строит общий контроллер поверх
AsyncNotifier: один тип задаёт элементы списка, второй задаёт индекс страницы. Поэтому индексом может быть не только число, но и дата или строка.Подключаемая примесь хранит текущий индекс, загружает первую страницу и добавляет следующую к уже полученным элементам. Конкретному экрану остаётся определить начальный индекс, запрос данных и способ вычислить следующий индекс. В интерфейсе
NotificationListener отслеживает конец прокрутки и вызывает загрузку.В руководстве Динко Маринаца есть схема слоёв, реализация поиска и фильтров и полный пример кода. Разбор предполагает знакомство с MVVM и репозиторием.
👎3❤1
Как настроить и обрабатывать диплинки в SwiftUI
Диплинк открывает нужный экран iOS-приложения сразу после перехода по ссылке. В примере схема
Обработчик сверяет схему, разбирает адрес через
Диплинки пригодятся и для экранов отладки или переключения тестовой среды. Открыть поддерживаемый адрес может кто угодно, поэтому принимайте только известные действия и параметры. В материале SwiftLee показаны настройка URL Types в Xcode, варианты для AppDelegate и SceneDelegate и тестирование ссылок в RocketSim.
Диплинк открывает нужный экран iOS-приложения сразу после перехода по ссылке. В примере схема
recipeapp:// принимает действие open-recipe и параметр name, а SwiftUI получает адрес через onOpenURL.Обработчик сверяет схему, разбирает адрес через
URLComponents, проверяет действие и лишь затем читает имя рецепта. Если одну схему зарегистрируют несколько приложений, какое из них получит ссылку, не определено. Для однозначной привязки автор советует Universal Links.Диплинки пригодятся и для экранов отладки или переключения тестовой среды. Открыть поддерживаемый адрес может кто угодно, поэтому принимайте только известные действия и параметры. В материале SwiftLee показаны настройка URL Types в Xcode, варианты для AppDelegate и SceneDelegate и тестирование ссылок в RocketSim.
💯1
Как безопасно перевести Flutter-код на первичные конструкторы Dart 3.12
В Dart 3.12 появилась экспериментальная поддержка primary constructors, или первичных конструкторов: поля класса и параметры конструктора можно объявить одной записью. В Flutter это сокращает шаблонный код виджетов, но массовая замена требует проверки поведения, а не только синтаксиса.
Попытка поручить миграцию агентам давала разные результаты даже при повторных запусках. Поэтому автор сделал детерминированную утилиту: она читает дерево кода через пакет Dart analyzer и применяет фиксированные правила.
Утилита выполняет три вида преобразований и пропускает код в 31 ситуации, когда безопасность замены нельзя доказать. Она записывает файл только после успешного разбора, а тесты проверяют результат анализатором. В инженерном разборе миграции показано, что именно нужно проверять кроме синтаксиса.
В Dart 3.12 появилась экспериментальная поддержка primary constructors, или первичных конструкторов: поля класса и параметры конструктора можно объявить одной записью. В Flutter это сокращает шаблонный код виджетов, но массовая замена требует проверки поведения, а не только синтаксиса.
Попытка поручить миграцию агентам давала разные результаты даже при повторных запусках. Поэтому автор сделал детерминированную утилиту: она читает дерево кода через пакет Dart analyzer и применяет фиксированные правила.
Утилита выполняет три вида преобразований и пропускает код в 31 ситуации, когда безопасность замены нельзя доказать. Она записывает файл только после успешного разбора, а тесты проверяют результат анализатором. В инженерном разборе миграции показано, что именно нужно проверять кроме синтаксиса.
💯1
Как установить рантаймы симуляторов Xcode из терминала
После установки Xcode 27 beta загрузка рантайма iOS у автора зависла на получении сведений. Переустановка Xcode и перезагрузка Mac не помогли, поэтому он перешёл к
Сначала проверьте активную версию Xcode командой
Если команда ищет универсальный рантайм и отвечает
После установки Xcode 27 beta загрузка рантайма iOS у автора зависла на получении сведений. Переустановка Xcode и перезагрузка Mac не помогли, поэтому он перешёл к
xcodebuild.Сначала проверьте активную версию Xcode командой
xcode-select -p. Если выбрана не та, переключите её: sudo xcode-select -s /Applications/Xcode-beta.app. Затем запустите xcodebuild -downloadPlatform iOS.Если команда ищет универсальный рантайм и отвечает
No matching downloadable, явно запросите arm64: xcodebuild -downloadPlatform iOS -architectureVariant arm64. Команду для загрузки рантаймов всех платформ и полный вывод ошибки смотрите в статье Донни Уолса.👍2❤1
Как проверять iOS-приложение из Cursor, Claude Code и Codex
RocketSim 17 выводит поток с iOS Simulator на локальную веб-страницу, которую можно открыть в браузере среды разработки. По команде
После прогона симулятор остаётся открыт. Разработчик выбирает элементы интерфейса прицелом, оставляет комментарии и возвращает их агенту в том же рабочем контексте. Слева видна иерархия доступности, снизу указаны рабочее дерево Git и ветка.
Такой цикл сокращает переключения между средой разработки и симулятором, но сохраняет визуальную проверку за человеком. В материале SwiftLee показан весь сценарий и объяснено, как подключить навигацию и проверку к агенту.
RocketSim 17 выводит поток с iOS Simulator на локальную веб-страницу, которую можно открыть в браузере среды разработки. По команде
/rocketsim агент проходит по экранам приложения и проверяет изменения через командную строку.После прогона симулятор остаётся открыт. Разработчик выбирает элементы интерфейса прицелом, оставляет комментарии и возвращает их агенту в том же рабочем контексте. Слева видна иерархия доступности, снизу указаны рабочее дерево Git и ветка.
Такой цикл сокращает переключения между средой разработки и симулятором, но сохраняет визуальную проверку за человеком. В материале SwiftLee показан весь сценарий и объяснено, как подключить навигацию и проверку к агенту.
👍2❤1
Как Flutter готовит приложения к новым версиям iOS
Между WWDC и стабильным релизом iOS у команды Flutter около трёх месяцев. В 2026 году скрипт на Dart выгрузил стенограммы более 145 сессий, а Gemini оценил их важность и область влияния. К вечеру команда получила разбор всех докладов.
Отдельный кейс в статье посвящён UIScene. Apple предупреждала: после iOS 26 UIKit-приложение, собранное последним SDK без UIScene, не запустится. Полная поддержка UIScene вошла во Flutter 3.41 в феврале 2026 года, до появления бета-версии iOS 27 с обязательной проверкой. Большинству разработчиков достаточно выполнить
В разборе команды Flutter есть и другой полезный кейс: сбой жестов в webview воспроизвели на чистом Swift, после чего Apple исправила его в iOS 26.4.
Между WWDC и стабильным релизом iOS у команды Flutter около трёх месяцев. В 2026 году скрипт на Dart выгрузил стенограммы более 145 сессий, а Gemini оценил их важность и область влияния. К вечеру команда получила разбор всех докладов.
Отдельный кейс в статье посвящён UIScene. Apple предупреждала: после iOS 26 UIKit-приложение, собранное последним SDK без UIScene, не запустится. Полная поддержка UIScene вошла во Flutter 3.41 в феврале 2026 года, до появления бета-версии iOS 27 с обязательной проверкой. Большинству разработчиков достаточно выполнить
flutter upgrade; проекты со встраиванием Flutter в нативное приложение требуют ручной миграции, а плагины должны поддерживать UIScene.В разборе команды Flutter есть и другой полезный кейс: сбой жестов в webview воспроизвели на чистом Swift, после чего Apple исправила его в iOS 26.4.
🤝1
Как безопасно освобождать временные ресурсы с defer в Swift
В Swift блок
Для iOS-разработки автор разбирает два сценария. В первом приложение записывает данные во временный файл, а
В статье с примерами кода также показано, как применять приём для снятия блокировок и восстановления изменённого состояния.
В Swift блок
defer выполняется перед выходом из ближайшей области видимости, которую задаёт пара фигурных скобок. Его можно поставить сразу после создания ресурса: код очистки останется рядом с настройкой, но сработает в конце функции, цикла или вычисляемого свойства.Для iOS-разработки автор разбирает два сценария. В первом приложение записывает данные во временный файл, а
defer удаляет его даже при раннем выходе после неудачного создания XMLParser. Во втором API наблюдения HealthKit требует вызвать обработчик завершения после обработки данных; defer делает это при выходе из итерации.В статье с примерами кода также показано, как применять приём для снятия блокировок и восстановления изменённого состояния.
👍1👏1
Как управлять кнопками панели инструментов в SwiftUI
Одна и та же панель в SwiftUI ведёт себя по-разному: macOS показывает все действия справа сверху, а iOS часть оставляет вверху, остальные сворачивает в дополнительное меню. Новые API задают, что останется на виду.
Одна и та же панель в SwiftUI ведёт себя по-разному: macOS показывает все действия справа сверху, а iOS часть оставляет вверху, остальные сворачивает в дополнительное меню. Новые API задают, что останется на виду.
visibilityPriority задаёт высокий или низкий приоритет, и SwiftUI сворачивает элементы с низким. ToolbarOverflowMenu помещает группу в свёрнутое меню на всех платформах. topBarPinnedTrailing удерживает действие справа сверху и может свернуть его только при активном поиске, если места не хватает.toolbarMinimizeBehavior сворачивает панель вкладок, нижнюю, оконную или навигационную панель при прокрутке. Статья с примерами кода показывает все четыре API. Для iOS-команды схема такая: назначить приоритет ключевому действию, второстепенные убрать в меню, затем проверить интерфейс с активным поиском и при прокрутке.❤2👏1
Как переносить сложные Android-экраны на Jetpack Compose: опыт TikTok
Команда TikTok переносила отдельные пользовательские сценарии и после каждого этапа сверяла метрики: начала с QR-кода, затем взялась за вход и регистрацию.
При небольших изменениях время загрузки страниц сократилось на 20–30%, а для новых функций и полностью переписанных страниц — на 70–80%. Та же функция на Compose потребовала на 58% меньше кода, чем реализация на View.
Практический нюанс: множество маленьких ComposeView внутри одного ViewHolder добавляло расходы на композицию. Один ComposeView на весь ViewHolder сработал лучше. Для пилота берите один сценарий и измеряйте результат до расширения миграции. В разборе Android Developers Blog есть также пример с ViewPager.
Команда TikTok переносила отдельные пользовательские сценарии и после каждого этапа сверяла метрики: начала с QR-кода, затем взялась за вход и регистрацию.
При небольших изменениях время загрузки страниц сократилось на 20–30%, а для новых функций и полностью переписанных страниц — на 70–80%. Та же функция на Compose потребовала на 58% меньше кода, чем реализация на View.
Практический нюанс: множество маленьких ComposeView внутри одного ViewHolder добавляло расходы на композицию. Один ComposeView на весь ViewHolder сработал лучше. Для пилота берите один сценарий и измеряйте результат до расширения миграции. В разборе Android Developers Blog есть также пример с ViewPager.
🔥6
Как использовать свайп-действия вне List в SwiftUI
В SwiftUI свайп-действия вроде удаления больше не привязывают интерфейс к List. Для ScrollView с LazyVStack или собственного Layout достаточно оставить
Он не только включает жесты: следит, чтобы действия были раскрыты лишь у одной строки, и закрывает их при прокрутке или касании снаружи. В List эта логика уже встроена, поэтому отдельный модификатор там не нужен.
Приём пригодится, когда экрану нужна нестандартная компоновка или собственный стиль, но хочется сохранить нативное свайп-взаимодействие. Код для ScrollView и пользовательского Layout автор показывает в статье «Swipe actions outside of List in SwiftUI».
В SwiftUI свайп-действия вроде удаления больше не привязывают интерфейс к List. Для ScrollView с LazyVStack или собственного Layout достаточно оставить
swipeActions у строки и добавить контейнеру модификатор swipeActionsContainer().Он не только включает жесты: следит, чтобы действия были раскрыты лишь у одной строки, и закрывает их при прокрутке или касании снаружи. В List эта логика уже встроена, поэтому отдельный модификатор там не нужен.
Приём пригодится, когда экрану нужна нестандартная компоновка или собственный стиль, но хочется сохранить нативное свайп-взаимодействие. Код для ScrollView и пользовательского Layout автор показывает в статье «Swipe actions outside of List in SwiftUI».
👍1
Как ProfilingManager на Android 15+ помогает искать причины тормозов в продакшене
ProfilingManager собирает на устройствах трассировки процессора, образцы стека вызовов и дампы памяти. Datadog встроила API в мониторинг реальных пользователей: теперь команда видит не только долгий запуск или зависание главного потока, но и код с событиями системы, которые привели к проблеме.
Показательный случай: трассировка раскрыла, что фоновый сервис синтеза речи заранее запускался вместе с приложением, занимал самое производительное ядро процессора и заставлял главный поток ждать.
В разборе Android Developers' Blog описаны сбор миллионов профилей в неделю, встроенное ограничение частоты запросов и анализ трассировок через Perfetto. API доступен с Android 15, поэтому на более старых устройствах текущие средства телеметрии всё ещё нужны.
ProfilingManager собирает на устройствах трассировки процессора, образцы стека вызовов и дампы памяти. Datadog встроила API в мониторинг реальных пользователей: теперь команда видит не только долгий запуск или зависание главного потока, но и код с событиями системы, которые привели к проблеме.
Показательный случай: трассировка раскрыла, что фоновый сервис синтеза речи заранее запускался вместе с приложением, занимал самое производительное ядро процессора и заставлял главный поток ждать.
В разборе Android Developers' Blog описаны сбор миллионов профилей в неделю, встроенное ограничение частоты запросов и анализ трассировок через Perfetto. API доступен с Android 15, поэтому на более старых устройствах текущие средства телеметрии всё ещё нужны.
🎉1
Как вынести вычисления из ИИ-агента в Dart-код Flutter-приложения
В Flutter с GenUI агент может собирать экраны во время работы приложения. Но арифметику лучше не передавать ему: это тратит токены, требует ответа по сети и делает результат менее предсказуемым.
Клиентские функции A2UI позволяют зарегистрировать Dart-функцию, её параметры и тип результата. Агент вызывает её из сообщения, а приложение выполняет код на устройстве.
Так вычисления и форматирование валюты остаются в Dart-коде. В материале Flutter показаны реализация функции и её регистрация в каталоге GenUI.
В Flutter с GenUI агент может собирать экраны во время работы приложения. Но арифметику лучше не передавать ему: это тратит токены, требует ответа по сети и делает результат менее предсказуемым.
Клиентские функции A2UI позволяют зарегистрировать Dart-функцию, её параметры и тип результата. Агент вызывает её из сообщения, а приложение выполняет код на устройстве.
Так вычисления и форматирование валюты остаются в Dart-коде. В материале Flutter показаны реализация функции и её регистрация в каталоге GenUI.
🤝2🥱1
Как SwiftUI Agent Skill помогает улучшать код представлений
Открытый SwiftUI Agent Skill добавляет ИИ-агенту правила для SwiftUI. Компактный SKILL.md направляет его к отдельным справочникам по управлению состоянием, производительности, доступности и API, поэтому в контекст попадают только материалы под текущую задачу.
При ревью навык нашёл вложенные
В материале SwiftLee есть установка через свежую версию skills CLI, обновление старой установки и пример запроса для ревью. Навык можно использовать для проверки сгенерированных SwiftUI-представлений и новых экранов.
Открытый SwiftUI Agent Skill добавляет ИИ-агенту правила для SwiftUI. Компактный SKILL.md направляет его к отдельным справочникам по управлению состоянием, производительности, доступности и API, поэтому в контекст попадают только материалы под текущую задачу.
При ревью навык нашёл вложенные
ScrollView и повторную синхронизацию состояния в onAppear и onChange. Версия 5.0.0 также содержит проверенные по интерфейсам SDK 27 рекомендации для Xcode 27, включая адаптивную вёрстку без привязки к фиксированному размеру экрана.В материале SwiftLee есть установка через свежую версию skills CLI, обновление старой установки и пример запроса для ревью. Навык можно использовать для проверки сгенерированных SwiftUI-представлений и новых экранов.
🔥3🎉2
Как убрать задержку генеративного интерфейса во Flutter
В A2UI модель присылает JSON-сообщения с описанием компонентов, а пакет
Решение автора: при изменении записи серверная функция просит Gemini заранее создать A2UI-сообщение и сохраняет его в Firestore. Приложение при открытии читает готовый JSON и передаёт его в историю диалога и транспорт
У примера есть ограничение: триггеры Firestore в Dart пока экспериментальны и поддерживаются только в Firebase Emulator Suite. Серверный и клиентский код показан в разборе в блоге Flutter.
В A2UI модель присылает JSON-сообщения с описанием компонентов, а пакет
genui отрисовывает их во Flutter-приложении. Запрос к модели при каждом старте задерживает первый экран: ей нужно обработать инструкции, получить данные и собрать интерфейс.Решение автора: при изменении записи серверная функция просит Gemini заранее создать A2UI-сообщение и сохраняет его в Firestore. Приложение при открытии читает готовый JSON и передаёт его в историю диалога и транспорт
genui, обходя новый вызов модели.У примера есть ограничение: триггеры Firestore в Dart пока экспериментальны и поддерживаются только в Firebase Emulator Suite. Серверный и клиентский код показан в разборе в блоге Flutter.
👌1