mobi_dev | Unsorted

Telegram-канал mobi_dev - Мобильная разработка

15502

Актуальное по мобильной разработке — Android, iOS, кроссплатформа Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels Сайт: https://tprg.ru/site Другие наши проекты: https://tprg.ru/media

Subscribe to a channel

Мобильная разработка

Android CLI получил Device Streaming для тестов на реальных смартфонах

Google добавила в Android CLI поддержку Device Streaming: теперь консоль и ИИ-агенты могут работать с физическими устройствами в облаке. Подключение идет через защищенный ADB over SSL, поэтому удаленный смартфон виден тулчейну так же, как если бы был подключен по USB.

Из терминала можно деплоить сборки, выгружать системные логи и трейсы, а также снимать скриншоты в headless-режиме. Параллельно каталог официальных инструкций Android skills вырос до 20+ файлов SKILL.md: от профилирования в PerfettoSQL и миграции на CameraX до аудита правил Google Play.

В блоге привели кейс команды FotMob: с навыком по Wear Compose Material 3 инженеры за один день перевели восемь списков на TransformingLazyColumn и убрали рукописный rotary-код. При этом инструкции поймали ошибки модели — забытый contentPadding и хардкод размеров sp.

@mobi_dev

Читать полностью…

Мобильная разработка

Как проверять другую ветку в Android Studio через Git worktree

Git worktree создаёт для ветки отдельную рабочую папку, которая использует общую историю основного репозитория. Поэтому незакоммиченные изменения текущей задачи можно оставить на месте, а ветку коллеги открыть во втором окне Android Studio. Отдельными будут и рабочие файлы, и каталоги сборки, хотя это само по себе не гарантирует отсутствие повторных сборок Gradle.

Новый каталог и ветка создаются командой git worktree add ../myapp-review -b review/fix. Доступные рабочие деревья показывает git worktree list, а после ревью каталог удаляется через git worktree remove ../myapp-review. Одну ветку нельзя одновременно открыть в нескольких worktree.

Практическое руководство по Git worktrees также разбирает перенос изменений в основную ветку и организацию параллельной работы без постоянных переключений и stash.

Читать полностью…

Мобильная разработка

Liquid Glass в SwiftUI: как выбрать regular или clear на iOS 26

Модификатор glassEffect() по умолчанию использует вариант .regular. Он сильнее размывает фон и подбирает цвет стандартных надписей и символов под изображение позади панели. В примере с тёмными обоями символы остаются светлыми даже при светлой цветовой схеме интерфейса.

Вариант .clear прозрачнее и сохраняет больше деталей фотографии или видео. Но цвет символов у него зависит от светлой или тёмной схемы: на тёмном фоне при Light Mode они могут остаться тёмными и потерять контраст.

Для навигации и большинства кнопок стоит выбирать .regular. Если контент под панелью нужно сохранить видимым, подойдёт .clear, но контраст придётся проверить на разных кадрах и при необходимости добавить затемнение. Сравнение вариантов содержит код и примеры для обеих цветовых схем.

Читать полностью…

Мобильная разработка

Как подключать новые API SwiftUI без повышения минимальной версии iOS

Если приложению нужен модификатор toolbarVerticalBehavior из версии 27.1, необязательно сразу менять deployment target для всего проекта. Обёртка Backport проверяет доступность API: на новой системе вызывает модификатор, а на старой возвращает исходное представление без изменений.

Так проверки версии собираются в одном месте, а вызовы получают отдельное пространство имён .backport. Для API, поведение которых нужно воспроизвести на старых версиях iOS, в ветке совместимости можно добавить собственную реализацию.

Альтернатива пространству имён: префикс ported и аннотация @available. Когда минимальная версия приложения дорастёт до штатного API, компилятор предупредит об устаревшей обёртке. Это помогает сохранить поддержку прежнего deployment target и не забыть удалить временный код.

Читать полностью…

Мобильная разработка

Когда 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.

Читать полностью…

Мобильная разработка

Как адаптировать модальные экраны SwiftUI к сгибу iPhone Duo

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

Если в панели нужна только одна кнопка, например Close, вертикальную полосу можно отключить модификатором .toolbarVerticalBehavior(.disabled). Его применяют к содержимому внутри NavigationStack, чтобы освободить ширину формы.

Разбор всех шести положений iPhone Duo поможет проверить доступность элементов. Системные sheets, alerts и menus уже отводят интерактивные элементы от изогнутого центра, но собственную вёрстку стоит проверить во всех положениях.

Читать полностью…

Мобильная разработка

Как заставить VoiceOver озвучивать карточку SwiftUI целиком

Составную карточку с иконкой, названием и числом VoiceOver может прочитать как набор несвязанных элементов: «изображение, текст, текст». Модификатор .accessibilityElement(children: .combine) объединяет дочерние представления в один логический элемент.

После объединения задайте короткое основное описание через .accessibilityLabel(), текущее состояние через .accessibilityValue(), а дополнительный контекст через .accessibilityHint(). Например, карточка со звездой, числом 42 и подписью Favorites вместо трёх отдельных фрагментов будет звучать как «Favorites: 42».

Для проверки включите VoiceOver в настройках доступности iOS и пройдите по карточкам свайпами. Каждая должна озвучиваться как законченный объект с понятным названием и состоянием. Код карточки и сценарий проверки VoiceOver помогут сверить реализацию.

Читать полностью…

Мобильная разработка

Как проверить Auto Layout в iOS 26 на iPhone 17 и Air

У iPhone 17 и 17 Pro логическая область экрана составляет 402 × 874 пункта, у Air: 420 × 912, у Pro Max: 440 × 956. В портретной ориентации ширина у всех относится к классу Compact. В альбомной Air и Pro Max переходят в Regular, а 17 и 17 Pro остаются в Compact.

Безопасную область стоит отдельно проверить в альбомной ориентации. Верхний отступ у всех четырёх моделей равен 20 пунктам. У Air боковые отступы составляют 68 пунктов, нижний: 29; у остальных моделей боковые: 62, нижний: 20.

Для App Store Connect правило не изменилось: достаточно одного набора скриншотов для iPhone под дисплей 6,9 или 6,5 дюйма, остальные размеры масштабируются. Таблица размеров, классов ширины и безопасных отступов поможет выбрать конфигурации симулятора для проверки Auto Layout.

Читать полностью…

Мобильная разработка

Как сделать прокрутку LazyVStack в SwiftUI предсказуемее

LazyVStack не строит весь список сразу: он загружает элементы у видимой области, а размеры строк за экраном оценивает по уже размещённым. Когда реальные размеры отличаются, стек уточняет общую высоту и смещение ScrollView. Поэтому логика, привязанная к абсолютному смещению, может срабатывать в разных местах.

Для длинной ленты в iOS полезны три правила: задавать предсказуемую высоту строк с переменным текстом; не сдвигать анимацией невидимые элементы в область экрана; отслеживать появление строк через onScrollTargetVisibilityChange, а не по абсолютному смещению.

Apple подробно разбирает оценку размеров, загрузку представлений, предзагрузку и программную прокрутку. Доклад рассчитан на разработчиков, уже знакомых с компоновкой стеков в SwiftUI.

Читать полностью…

Мобильная разработка

Как тестировать 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 показан полный пример обёртки и аннотации для её планового удаления.

Читать полностью…
Subscribe to a channel