15502
Актуальное по мобильной разработке — Android, iOS, кроссплатформа Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels Сайт: https://tprg.ru/site Другие наши проекты: https://tprg.ru/media
Когда SubcomposeLayout в Jetpack Compose оправдывает свою цену
Обычный Layout измеряет и размещает готовое дерево. SubcomposeLayout создаёт компоненты во время измерения, когда уже известны ограничения родителя, поэтому обходится дороже.
Он нужен, когда размер определяет состав интерфейса: например, строка тегов создаёт элементы до границы экрана и добавляет счётчик скрытых.
В разборе механики и DynamicChipRow показано, почему для расчёта одних размеров обычно достаточно Layout.
Как связать список и экран деталей анимацией в Jetpack Compose
Схема интеграции с Navigation Compose: SharedTransitionLayout размещают над NavHost, а элементам списка и экрана деталей задают одинаковый ключ по ID. Compose сопоставляет их и анимирует положение и размер.
Для одного изображения подходит sharedElement, для карточки с меняющимся содержимым — sharedBounds. Не используйте индекс списка как ключ: после перестановки элементы могут связаться неверно.
Длительность лучше держать в пределах 300–400 мс и учитывать системное отключение анимаций.
Как загружать локальный HTML в SwiftUI WebView через свою URL-схему
В iOS 26 у SwiftUI появились WebView и WebPage, а собственная URL-схема позволяет загружать локальные ресурсы. Например, приложение может открыть quotes://001.html, найти файл в основном пакете и показать страницу без сервера.
Обработчик URLSchemeHandler получает запрос, проверяет схему, находит файл, определяет MIME-тип и читает данные. Затем он последовательно передаёт в асинхронный поток URLResponse и содержимое файла, а при ошибке завершает поток с исключением.
Обработчик регистрируется в WebPage.Configuration, созданная WebPage передаётся в WebView, а загрузка запускается через page.load. Метод возвращает события, по которым можно отслеживать ход загрузки. Перед внедрением проверьте минимальную версию приложения: этот API доступен начиная с iOS 26.
Как передавать контент между iOS-приложениями через Siri
Чтобы Siri могла отдать сущность другому приложению, AppEntity представляют системным типом. В примере ContactEntity содержит IntentPerson, реализует Transferable и передаёт свойство через IntentValueRepresentation. Так система получает значение для обмена.
При импорте IntentValueQuery ищет сохранённый контакт по имени, телефону, адресу почты или ID. Пустой результат запускает importing-замыкание: оно создаёт новую сущность и сохраняет контакт. Правила сопоставления остаются в приложении.
Разбор передачи контента через App Intents содержит Swift-код обоих направлений. Минимальная версия iOS и требования SDK не указаны, поэтому совместимость нужно отдельно сверить с документацией Apple.
Как Baseline Profiles ускоряют запуск и прокрутку Android-приложений
ART сначала интерпретирует байткод Kotlin и Java, а затем компилирует часто вызываемые методы. Baseline Profile заранее задаёт нужные классы и методы: с Android 9 ART компилирует их при установке приложения.
Meta собирает последовательности загрузки классов для запуска, прокрутки ленты и открытия фото. По данным компании, профили улучшили отдельные ключевые метрики до 40%.
Опыт Meta с Baseline Profiles показывает, как ускорять не только холодный запуск.
Как показывать ответ Foundation Models в iOS по мере генерации
В Swift метод respond возвращает результат после завершения генерации. Для постепенного обновления интерфейса можно вызвать streamResponse: он создаёт ResponseStream, который перебирается через for try await и выдаёт частичные версии объекта.
Макрос @Generable добавляет тип PartiallyGenerated с необязательными свойствами. Модель заполняет поля в порядке объявления, поэтому заголовок, текст и подсказки стоит выводить в той же последовательности.
Разбор потоковой генерации также показывает collect(): после перебора потока метод возвращает итоговый структурированный объект.
Как обновлять схемы SwiftData и не ломать данные после релиза
После обновления iOS-приложение открывает существующее хранилище. Поэтому даже первую модель автор советует выпускать через VersionedSchema: она станет исходной точкой для следующих версий.
SwiftData сама переносит данные при лёгких изменениях, например при добавлении необязательного свойства. Новое обязательное поле без значения, смена типа или объединение сущностей требуют ручного преобразования через SchemaMigrationPlan и MigrationStage.
Разбор миграций SwiftData объясняет, как учитывать пользователей, которые пропускают версии приложения, и когда нужны промежуточные схемы. Проверяйте переход с реального хранилища на диске: значение по умолчанию в Swift-инициализаторе не гарантирует заполнение старых записей.
Как изолировать ViewModel по записи навигации в Android Navigation 3
После миграции с Navigation 2 вызов viewModel() может сохранять состояние экрана: в Compose-приложении с одной Activity модель по умолчанию привязана к Activity.
Для отдельной ViewModel у каждой записи добавьте lifecycle-viewmodel-navigation3:2.10.0 и передайте в NavDisplay декораторы rememberSaveableStateHolderNavEntryDecorator() и rememberViewModelStoreNavEntryDecorator(). Новая запись получит свой экземпляр, а удаление из стека очистит его.
Готовая конфигурация NavDisplay поможет выбрать между свежим состоянием экрана и общей моделью.
Как довести код ИИ-агента в iOS до TestFlight
Donny Wals разбирает пайплайн, в котором агент пишет код, а разработчик сохраняет контроль над архитектурой и релизом. Правила для Swift, SwiftUI и тестов лежат в agents.md; агент Xcode 26.3 тоже читает этот файл.
Перед реализацией агент составляет план с перечнем файлов и выбранным подходом. После проверки плана он создаёт pull request, а Cursor BugBot ищет логические ошибки, крайние случаи и случайные изменения.
Bitrise запускает тесты для каждого pull request. После слияния в основную ветку второй сценарий ещё раз проверяет код, подписывает архив и загружает сборку в App Store Connect, откуда она попадает в TestFlight. Получается воспроизводимый путь до тестовой сборки без ручного запуска Xcode, но с проверкой плана, кода и тестов человеком.
Как подготовить Android-интерфейс к широким складным экранам Samsung
Galaxy Z Fold8 получил сверхширокий основной экран с альбомной ориентацией. Android-разработчикам советуют отказаться от жёстких размеров и ориентации: выбирать компоновку по классу ширины окна, затем учитывать высоту.
Для Compose предлагают Grid, FlexBox и MediaQuery. Сгибы и шарниры лучше использовать как разделители, а состояние при складывании сохранять через ViewModel. Примеры собраны в статье Android Developers Blog.
Как загружать ресурсы iOS по требованию и не хранить токены в бинарнике
On-Demand Resources выносят изображения, модели и конфигурации из начальной загрузки: iOS скачивает их из App Store, кэширует и удаляет при нехватке места.
Механизм можно применить к API-токенам: загрузить конфигурацию по тегу и сохранить данные в Keychain. Но это не граница безопасности: после загрузки файлы доступны при доступе к устройству.
В статье Swift with Majid есть обёртка на Swift и пример загрузки конфигурации. Для нового кода Apple рекомендует вместо устаревших On-Demand Resources использовать Background Assets.
Room 3.0 переводит Android-разработчиков на Kotlin и KSP
В анонсе Room 3.0 команда отказалась от генерации Java-кода, Java Annotation Processing и KAPT. Новая версия генерирует только Kotlin-код и обрабатывает его через KSP, Kotlin Symbol Processing.
Room также больше не поддерживает API SupportSQLite: библиотека полностью переходит на драйверы androidx.sqlite, совместимые с Kotlin Multiplatform. Асинхронные API теперь строятся вокруг корутин Kotlin, в том числе ради поддержки веб-платформ.
Перед переходом на Room 3.0 проверьте сборку Android-приложения: модули с Java AP или KAPT придётся перевести на KSP, а код, завязанный на SupportSQLite, адаптировать к драйверам androidx.sqlite.
Как SwiftUI Agent Skill помогает улучшать код представлений
Открытый SwiftUI Agent Skill добавляет ИИ-агенту правила для SwiftUI. Компактный SKILL.md направляет его к отдельным справочникам по управлению состоянием, производительности, доступности и API, поэтому в контекст попадают только материалы под текущую задачу.
При ревью навык нашёл вложенные ScrollView и повторную синхронизацию состояния в onAppear и onChange. Версия 5.0.0 также содержит проверенные по интерфейсам SDK 27 рекомендации для Xcode 27, включая адаптивную вёрстку без привязки к фиксированному размеру экрана.
В материале SwiftLee есть установка через свежую версию skills CLI, обновление старой установки и пример запроса для ревью. Навык можно использовать для проверки сгенерированных SwiftUI-представлений и новых экранов.
Как ProfilingManager на Android 15+ помогает искать причины тормозов в продакшене
ProfilingManager собирает на устройствах трассировки процессора, образцы стека вызовов и дампы памяти. Datadog встроила API в мониторинг реальных пользователей: теперь команда видит не только долгий запуск или зависание главного потока, но и код с событиями системы, которые привели к проблеме.
Показательный случай: трассировка раскрыла, что фоновый сервис синтеза речи заранее запускался вместе с приложением, занимал самое производительное ядро процессора и заставлял главный поток ждать.
В разборе Android Developers' Blog описаны сбор миллионов профилей в неделю, встроенное ограничение частоты запросов и анализ трассировок через Perfetto. API доступен с Android 15, поэтому на более старых устройствах текущие средства телеметрии всё ещё нужны.
Как переносить сложные Android-экраны на Jetpack Compose: опыт TikTok
Команда TikTok переносила отдельные пользовательские сценарии и после каждого этапа сверяла метрики: начала с QR-кода, затем взялась за вход и регистрацию.
При небольших изменениях время загрузки страниц сократилось на 20–30%, а для новых функций и полностью переписанных страниц — на 70–80%. Та же функция на Compose потребовала на 58% меньше кода, чем реализация на View.
Практический нюанс: множество маленьких ComposeView внутри одного ViewHolder добавляло расходы на композицию. Один ComposeView на весь ViewHolder сработал лучше. Для пилота берите один сценарий и измеряйте результат до расширения миграции. В разборе Android Developers Blog есть также пример с ViewPager.
Как тестировать App Intents и Spotlight без автоматизации интерфейса
На WWDC26 Apple показала AppIntentsTesting для интеграционных тестов App Intents в iOS. Проверки запускают интенты на устройстве через тот же стек, что Siri, Shortcuts и Spotlight, но не зависят от интерфейса приложения или системы.
Тесты живут в обычном пакете XCUITest и обращаются к приложению по идентификатору пакета. Можно выполнить интент, проверить результат, прогнать запрос сущностей, связать несколько интентов и проверить индексацию Spotlight. Код приложения импортировать не нужно; приложение и средство запуска тестов должны использовать одну команду разработчика в настройках подписи.
В докладе с примерами кода также разбирают подготовку тестовых данных и запуск проверок в CI. Так регрессии интеграций с Siri и Shortcuts можно ловить без ручной проверки интерфейса.
Как ускорить первый кадр камеры в iOS 26 с AVFoundation
Apple предлагает разделить запуск камеры: сначала создать превью и кнопку затвора, а остальные элементы интерфейса и выходы захвата инициализировать позже. В докладе о быстром запуске камеры Deferred Start сократил ожидание превью примерно вдвое.
AVCaptureSession, startRunning и stopRunning блокируют поток, поэтому их не стоит вызывать в главном потоке. Конфигурацию применяют один раз, а при Deferred Start откладывают все выходы, кроме превью.
API доступен с iOS 26. При сборке с SDK iOS 26 автоматический режим включён по умолчанию. Первый кадр появится раньше, но фотосъёмка не ускорится, пока не готов её выход.
Как встроить генерацию изображений через Image Playground в iOS-приложение
Фреймворк Image Playground позволяет создавать изображения в Swift из текста, фотографии, рисунка PencilKit или большого текстового фрагмента. За генерацию отвечает ImageCreator: метод images получает описание, стиль и число результатов, а затем возвращает их по одному через AsyncSequence.
Доступны стили animation, illustration и sketch, но конкретный набор зависит от устройства. Перед вызовом стоит проверить availableStyles; создание ImageCreator может завершиться ошибкой, если устройство не поддерживает генерацию. За один запрос система выдаёт не больше четырёх изображений.
Примеры на Swift показывают, как передать текст вместе с исходной картинкой и получить CGImage. Минимальную версию ОС и список совместимых устройств статья не называет, поэтому их нужно проверить отдельно перед внедрением.
Как собрать фильтры и индикаторы в Android на Compose Material 3
В Compose Material 3 есть готовые компоненты для интерфейсов, которые часто собирают вручную. TriStateCheckbox связывает общий флажок с дочерними: показывает, выбраны все пункты, ни одного или только часть. SegmentedButton позволяет выбрать один или несколько вариантов из двух-пяти.
Для фильтра по цене подойдёт RangeSlider, а BadgedBox поможет оформить индикатор непрочитанных уведомлений. При переносе примера с ползунком проверьте начальную границу диапазона: её нужно исправить. Параметр steps задаёт количество промежуточных значений, а не общее число позиций.
Примеры компонентов с кодом подходят для Material 3 версий 1.3.2, 1.4.0-beta02 и 1.5.0-alpha04: используемый API между ними не менялся.
Как перевести платное iOS-приложение на freemium и сохранить доступ покупателям
Схема миграции через StoreKit опирается на AppTransaction: исходная версия и дата покупки помогают распознать тех, кто установил приложение до перехода. Им можно выдать пожизненный доступ.
В TestFlight и среде ревью исходная версия всегда «1.0», а в production приходит номер сборки: сравнивайте номера сборок. Для отладки добавьте ручное переключение статуса, иначе ревьюер не увидит покупку.
После переустановки исходная версия меняется на текущую. Для одного устройства статус храните в Keychain, для нескольких понадобится CloudKit или сервер.
Как добавить свайп-действия в Android без устаревшего API
В Compose Material 3 компонент SwipeToDismissBox позволяет назначить разные действия для свайпов влево и вправо. В примере элемент списка после одного жеста помечается прочитанным, после другого удаляется.
Состояние создаётся через rememberSwipeToDismissBoxState без устаревшего confirmValueChange. Направление жеста обрабатывается в колбэке компонента, а reset() возвращает элемент на место перед отметкой прочитанного. Фон меняет цвет и значок в зависимости от направления и хода свайпа. Для элементов списка используются стабильные ключи, чтобы состояние не переезжало между строками.
Пошаговый пример с кодом рассчитан на Material 3 1.4.0 и 1.5.0-alpha11. Если в проекте другая версия библиотеки, перед внедрением сверьте сигнатуры API.
Как передать изображение в Foundation Models и получить Swift-структуру
Мультимодальный ввод позволяет отдать модели фотографию прямо из iOS-приложения. В примере снимок блюда превращается в PlateClassification: структура с названием блюда и признаками сахара, белка, клетчатки и насыщенных жиров.
Схема такая: @Generable задаёт тип результата, PromptBuilder объединяет инструкцию с Attachment, а LanguageModelSession возвращает заполненную структуру через result.content. Вложение можно создать из URL, буфера пикселей, CGImage или CIImage.
Практический разбор с кодом показывает весь путь от изображения до данных для интерфейса. Требования к версии iOS и совместимым устройствам автор не приводит, поэтому перед внедрением их стоит сверить с документацией SDK.
Как собирать диагностику iOS-приложения через MetricKit
Xcode Organizer показывает сбои, зависания, время запуска, расход памяти и завершения приложения, но не всегда объясняет причину завершения. MetricKit отдаёт системные метрики и диагностику, которые можно отправить в свою аналитику.
В примере на Swift AppDelegate подписывается на MXMetricManager. Один обработчик получает MXMetricPayload со счётчиками фоновых завершений из-за лимитов CPU и памяти, другой получает MXDiagnosticPayload с данными о сбоях.
Система может агрегировать отчёты и доставлять их раз в сутки или чаще, поэтому на точное расписание рассчитывать нельзя. timeStampBegin и timeStampEnd показывают период данных, а JSON-представление можно выгрузить в собственный API и обработать на бэкенде.
Как заменить List собственным контейнером в SwiftUI
Для больших однородных наборов данных подходит List. Если экран iOS-приложения состоит из карточек разных типов, автор предлагает связку ScrollView и ленивого стека: она даёт точнее управлять оформлением и не требует модификаторов, работающих только внутри List.
Контейнер ScrollingSurface выбирает вертикальный или горизонтальный стек. DividedCard получает дочерние представления через Container View API и добавляет между ними разделители, а SectionedSurface извлекает секции и пропускает пустые. Отдельный стиль кнопки возвращает стрелку для навигации.
В статье «Building List replacement in SwiftUI» есть код всех компонентов и пример их сборки в экране приложения. Подход пригодится, когда стандартный список ограничивает дизайн, а данные не требуют переиспользования огромного числа одинаковых ячеек.
Как собрали ИИ-кофейню на Flutter и Firebase
GenLatte поддерживает iOS и Android, хотя посетители работали только с веб-версией. В одном монорепозитории команда объединила Flutter-приложение, серверную часть на Firebase и общий код: так бизнес-логика не расходилась между пятью интерфейсами для заказа, бариста, модерации и очереди.
Для персонализации Gemini превращал короткое описание «счастливого места» в четыре запроса к генератору изображений. Затем генеративный интерфейс выбирал подходящий элемент из небольшого набора фирменных виджетов: текстовое поле для открытого вопроса или переключатель для нескольких вариантов.
Из разбора команды Flutter можно забрать архитектуру общего приложения и централизованные проверки ролей через GoRouter и Firebase. Выпуск в App Store и Google Play, версии SDK и совместимость со старыми устройствами материал не рассматривает.
Как заставить Swift напомнить об удалении временного API
При поддержке iOS 18 и iOS 26 разработчику может понадобиться обёртка для различий между версиями. В примере из статьи ToolbarLabelStyle показывает текстовые кнопки на iOS 18 и значки на iOS 26. После повышения минимальной версии приложения до iOS 26 такой код станет лишним.
Аннотация @available превращает будущую уборку в проверку компилятора. Параметр deprecated: 26 помечает обращения предупреждением, когда минимальный таргет поднимется до iOS 26, а obsoleted: 27 сделает их ошибками на iOS 27. Можно сразу указать obsoleted: 26, но автор советует сначала объявить API устаревшим, затем запретить его.
В статье Swift with Majid показан полный пример обёртки и аннотации для её планового удаления.
Как убрать задержку генеративного интерфейса во Flutter
В A2UI модель присылает JSON-сообщения с описанием компонентов, а пакет genui отрисовывает их во Flutter-приложении. Запрос к модели при каждом старте задерживает первый экран: ей нужно обработать инструкции, получить данные и собрать интерфейс.
Решение автора: при изменении записи серверная функция просит Gemini заранее создать A2UI-сообщение и сохраняет его в Firestore. Приложение при открытии читает готовый JSON и передаёт его в историю диалога и транспорт genui, обходя новый вызов модели.
У примера есть ограничение: триггеры Firestore в Dart пока экспериментальны и поддерживаются только в Firebase Emulator Suite. Серверный и клиентский код показан в разборе в блоге Flutter.
Как вынести вычисления из ИИ-агента в Dart-код Flutter-приложения
В Flutter с GenUI агент может собирать экраны во время работы приложения. Но арифметику лучше не передавать ему: это тратит токены, требует ответа по сети и делает результат менее предсказуемым.
Клиентские функции A2UI позволяют зарегистрировать Dart-функцию, её параметры и тип результата. Агент вызывает её из сообщения, а приложение выполняет код на устройстве.
Так вычисления и форматирование валюты остаются в Dart-коде. В материале Flutter показаны реализация функции и её регистрация в каталоге GenUI.
Как использовать свайп-действия вне List в SwiftUI
В SwiftUI свайп-действия вроде удаления больше не привязывают интерфейс к List. Для ScrollView с LazyVStack или собственного Layout достаточно оставить swipeActions у строки и добавить контейнеру модификатор swipeActionsContainer().
Он не только включает жесты: следит, чтобы действия были раскрыты лишь у одной строки, и закрывает их при прокрутке или касании снаружи. В List эта логика уже встроена, поэтому отдельный модификатор там не нужен.
Приём пригодится, когда экрану нужна нестандартная компоновка или собственный стиль, но хочется сохранить нативное свайп-взаимодействие. Код для ScrollView и пользовательского Layout автор показывает в статье «Swipe actions outside of List in SwiftUI».
Как убрать нестабильность скриншот-тестов Paparazzi с Lottie
Paparazzi снимает Android-интерфейс через Layoutlib без эмулятора. Layoutlib обычно вызывают из одного потока, а приложение запускает фоновые задачи.
В нестабильном тесте Lottie загружала анимацию в фоне, а затем отправляла задачу через Handler. Одновременно Paparazzi перебирала карту очереди обработчиков. Добавление обработчика во время перебора вызывало ConcurrentModificationException и периодически роняло часть CI-прогона.
Обход для тестов: в методе @Before заменить LottieTask.EXECUTOR исполнителем, который запускает задачу в текущем потоке. Исправление в Layoutlib требует синхронизировать доступ к карте и её спискам. Код воспроизведения и вариант синхронизации есть в подробном разборе.