Мобильная разработка
13.1K subscribers
1.03K photos
238 videos
3.16K links
Актуальное по мобильной разработке — Android, iOS, кроссплатформа

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

Регистрация в перечне РКН: https://tprg.ru/oVBP
Download Telegram
Долгая задача продолжится, даже если Android-приложение закрыли

Помощник собирает маршрут: ищет перелёт, гостиницу и билеты. Если весь процесс привязан к экрану телефона, уход приложения в фон усложняет сохранение прогресса.

В разборе архитектуры Jetpacker Google переносит многошаговый сценарий на сервер. Координатор ADK вызывает специализированных агентов, а Android-клиент показывает ход работы и запрашивает выбор пользователя.

AG-UI передаёт сообщения и события выполнения. A2UI описывает интерфейс структурированными данными, которые клиент отображает нативными компонентами Jetpack Compose.

Так сервер может менять сочетания поддерживаемых карточек без выпуска новой версии приложения. Но набор компонентов всё равно задаётся на клиенте: произвольный экран, которого бинарник не умеет рисовать, из JSON не появится. В статье есть ссылки на код сервера и Android-приложения.
👍1
Границы модулей, которые нельзя обойти случайным import

Фича оформления заказа захотела аватар пользователя — и получила зависимость от реализации профиля. Проект собирается, но менять эти части независимо уже сложнее.

В разборе модульной архитектуры Compose каждую возможность делят на -api и -impl. Только модуль приложения видит реализации. Остальные фичи общаются через контракты.

Правило проверяет convention plugin Gradle: зависимость чужой фичи от -impl останавливает сборку ещё на этапе конфигурации. Внутренние маршруты, репозитории и ViewModel дополнительно закрывают через Kotlin internal.

Для навигации наружу отдают launcher, возвращающий маршрут. Фича знает, куда можно перейти, а вызывающий код решает, как изменить back stack. В статье есть примеры проверок и цена такого разделения.
❤1👌1
Кнопка закрытия sheet переехала на боковую панель

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

В примере SwiftUI sheets это происходит автоматически при сборке с iOS 27.1 SDK. Следить за углом шарнира и вручную двигать окно для стандартного поведения не нужно.

Размещение можно уточнить через presentationPlacement. Но автор нашла нюанс в iOS 27.1 beta: у окна с положением trailing кнопка закрытия иногда перекрывалась системной областью. В её тесте помогло явное presentationDetents([.large]).

Это обход проблемы конкретной беты. Перед добавлением собственных отступов стоит проверить стандартное окно в симуляторе во всех положениях устройства.
💯1
Два String — и платёж ушёл не туда

Идентификаторы продавца и банка могут выглядеть одинаково. Если оба представлены строками, перепутанные аргументы спокойно проходят компиляцию.

В разборе опыта Verifone для каждого понятия вводят свой Kotlin value class: MerchantId, AcquirerId и другие. После этого подмена одного идентификатора другим становится ошибкой типов.

Та же логика распространяется на состояние операции. Обязательное поле не делают nullable «на всякий случай», а разные исходы описывают sealed-типами. Таймаут запроса сам по себе не доказывает, что платёж не состоялся.

Эти приёмы пригодятся и в мобильном клиенте: на границе API сырые данные проверяют и превращают в типы предметной области, с которыми дальше работает приложение.
🔥1
Lottie в пейволле: обычный пример с CDN не заработает

В RevenueCat можно добавить собственную анимацию в серверный пейволл. Но custom component загружается как самостоятельный набор веб-файлов со строгими ограничениями.

В руководстве для Android показаны варианты с Rive и Lottie. Скрипты, стили, runtime и данные анимации упаковывают вместе. Запросы через fetch, inline-скрипты и eval запрещены политикой CSP.

У Rive это влияет даже на выбор сборки: стандартный runtime подтягивает WebAssembly, поэтому в примере используют canvas-single. Данные анимации передают напрямую, без загрузки по URL.

В таком компоненте размещают декоративную часть. Выбор тарифа и кнопки покупки остаются нативными — обработкой покупки по-прежнему занимается SDK.
🤝1
Отдельные ToolbarItem ещё не означают отдельные кнопки

В iOS 26 соседние элементы SwiftUI toolbar могут объединяться в одну стеклянную капсулу. Разнести их по нескольким ToolbarItemGroup недостаточно.

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

Чтобы разделить действия явно, между ними ставят ToolbarSpacer. Фиксированный создаёт небольшой промежуток. Гибкий в нижней панели раздвигает группы к краям, но в верхней не получает пространство заголовка.

Отдельная ловушка — кнопка подтверждения. Одного placement confirmationAction недостаточно для собственной капсулы: в примере её выделяет роль confirm. Это стоит проверить, если «Готово» визуально слилось с соседним действием.
👏2
Kotlin давно вышел за пределы Android. Вот что показывает опрос

Больше половины Kotlin-разработчиков в исследовании JetBrains сообщили, что работают над backend-проектами. Это полезный контекст для мобильных команд, которые обсуждают общий язык с серверной частью.

В State of Kotlin 2026 собраны данные исследований JetBrains, отраслевые сведения и примеры использования языка. Отдельные разделы посвящены multiplatform и AI-инструментам.

Среди опрошенных Kotlin-разработчиков 93% используют хотя бы один AI coding tool. А 81% оценивают сгенерированный Kotlin-код как полностью корректный или требующий небольших исправлений.

Последнее число описывает ответы людей, а не результат независимого тестирования кода. Отчёт помогает увидеть практики сообщества; решение о KMP или генерации кода для своего приложения всё равно требует отдельной проверки.
❤2👎2🎉1
В Android Studio можно подключить своего coding agent

Агенту нужны структура проекта, диагностика сборки и доступ к эмулятору. Если всё это приходится передавать вручную, часть времени уходит на подготовку контекста.

Google добавила Bring Your Own Agent: интеграцию ACP-совместимых агентов с Android Studio. Среди вариантов — Claude Agent, Codex и Antigravity. Авторизация зависит от провайдера: через доступный тариф или API-ключ.

IDE передаёт сведения о проекте и подключает инструменты сборки, Compose Previews, Android SDK и управления эмулятором. Работа с агентом остаётся внутри среды разработки.

Функция выходит в preview в Canary-версии Android Studio Rabbit 2. Перед переносом рабочего процесса стоит проверить доступные инструменты и разрешения на отдельном проекте.
❤4🔥3💊2👎1
Size classes не скажут, насколько согнут экран

Для адаптивной вёрстки легко написать условие: compact — телефон, regular — большой экран. Но определить положение шарнира таким способом не получится.

В замерах iPhone Duo внутренний дисплей возвращает regular по обеим осям и в открытом, и в полусогнутом состоянии. На внешнем экране ширина compact, а в landscape compact становится и высота.

Есть ещё одна деталь: внутри ArrangementView каждая панель получает size classes по собственному размеру. Они могут отличаться от характеристик всего окна.

Поэтому значение из environment нужно читать там, к чему относится решение. Перестраиваете конкретную панель — смотрите её пространство. Выбираете компоновку для всего окна — считайте size classes выше ArrangementView.
❤1
Почему AI легче написать экран, чем мигрировать приложение

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

В Android Bench 2.0 добавили длинные задачи: обновление зависимостей, создание приложений и перенос с других платформ. Помимо полного прохождения учитывают долю выполненных требований, визуальное соответствие и регрессии.

На момент публикации лучший pass rate длинных задач составлял около 28%, тогда как у исходного набора — около 91%. Эти числа относятся к разным наборам задач.

Среди проблемных мест Google отмечает проверку во время выполнения, DI-графы и несовместимые изменения фреймворков. Для миграции приложения это повод заранее определить проверяемые этапы и критерии готовности.
❤‍🔥1🎉1
Deep links теперь можно проверить прямо в Play Console

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

Google представила встроенный deep link emulator в Play Console. Он позволяет просматривать и тестировать ссылки прямо в консоли.

В том же обновлении Ask Play получил сравнения приложений: например, по доступности офлайн-режима или модели подписки. Для ответов используются описание в магазине и отзывы пользователей.

Перед выпуском новой функции полезно проверить обе части: понятно ли она описана в карточке приложения и ведут ли связанные ссылки туда, куда ожидает пользователь. Работающий экран мало поможет, если путь к нему сломан.
👍6👎1👌1
ArrangementView не всегда делит экран пополам

У обложки и текста статьи разные потребности в пространстве. В iOS 27.1 долю каждой панели ArrangementView можно задать через splitArrangementLayoutRatio.

В примере с пропорциями значение idealHorizontal: 1 / 3 отдаёт представлению треть ширины. Для вертикальной компоновки есть idealVertical, а единое значение применяется к обеим осям.

Но на полусогнутом iPhone Duo разделение проходит по сгибу, и заданная пропорция игнорируется. Ширина доступного содержимого при этом может различаться из-за системной панели.

Модификатор также не увеличивает область под слишком большой контент: тот может выйти за её границы. Проверять нужно и пропорцию, и содержимое каждой панели. Для размеров в пунктах предусмотрен отдельный splitArrangementLayoutSize.
У пейволла две кнопки закрытия? Проверьте способ показа

Крестик, нарисованный внутри PaywallView, остаётся частью пейволла. Он не перемещается вместе с системным toolbar, когда интерфейс адаптируется к складному экрану.

В руководстве RevenueCat отдельно разбирают готовый presentPaywallIfNeeded и самостоятельный показ через sheet. Во втором случае рекомендуют убрать внутренний крестик и добавить закрытие в toolbar с placement cancellationAction.

Для дизайна со своим крестиком есть другой вариант: отключить вертикальные панели через toolbarVerticalBehavior(.disabled) и проверить его положение. Выбор должен оставаться последовательным.

При смене положения экрана должны сохраняться тарифы, цены и условия пробного периода. Кнопки и карточки покупки также стоит проверить в полусогнутом режиме: важные действия не должны попадать на сгиб.
ADB Wi-Fi 2.0 улучшает восстановление соединения при беспроводной отладке

Телефон уснул или изменилась конфигурация сети — устройство пропало из ADB. В ADB Wi-Fi 2.0 Google переработал сервер adb, демон adbd и интеграцию с Android Studio, чтобы такие разрывы меньше мешали работе.

На компьютере новый стек mDNS заменяет Bonjour и прежнюю реализацию обнаружения устройств. На телефоне отладка автоматически выключается в недоверенной сети и включается снова после возвращения в разрешённую пользователем.

В Android Studio устройство с включённой беспроводной отладкой появляется в Device Manager. Для сопряжения можно использовать QR-код или код подключения.

Для нового стека нужны Android 17, SDK Platform-Tools 37.0.0 и Android Studio Quail 3 или новее. Компьютер и устройство должны находиться в одной Wi-Fi-сети: обновление не превращает ADB в подключение через любой интернет.
🔥2
layoutMarginsGuide выравнивает содержимое UIKit по системным отступам устройства

Отступ в 16 пунктов совпал с краем заголовка на одном iPhone, а на другом текст оказался левее. Системные поля меняются в зависимости от устройства и ориентации, поэтому фиксированное число подходит не всегда.

В разборе layoutMarginsGuide автор привязывает содержимое к направляющим отступов корневого view контроллера. Система задаёт им поля, согласованные с навигационной панелью.

По умолчанию направляющие учитывают безопасную область экрана. В альбомной ориентации отступ со стороны Dynamic Island включает и эту область, и дополнительное поле. Повторно прибавлять safe area не нужно.

У вложенных view собственные поля: совпадение с родительскими не следует считать автоматическим. Для настройки пригодятся directionalLayoutMargins и preservesSuperviewLayoutMargins. В статье есть сравнения на разных экранах.
❤1
RevenueCat позволяет проверить план изменения продуктов магазина до его применения

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

В обновлении RevenueCat AI Toolkit для этого описан процесс через CLI: rc products store plan строит план из файла, show показывает его, а apply применяет изменения отдельным действием.

Так желаемое состояние каталога можно хранить в CSV и отправлять на ревью вместе с кодом. Проверка плана особенно полезна, когда запрос касается сразу двух магазинов или нескольких цен.

Сам CLI находится в публичной бете. Для автоматизации у него есть JSON-вывод, описание команд и режим --no-input, который завершает команду ошибкой вместо ожидания ответа. Создание плана ещё не означает, что цены в магазине уже изменились.
AndroidX Security State показывает исправления безопасности отдельно для компонентов устройства

Одна дата обновления Android не описывает всю картину: система, модули Google Play и ядро обновляются разными путями.

AndroidX Security State позволяет различать три состояния: что установлено на устройстве, какие исправления опубликованы и какое обновление уже доступно для установки именно здесь. Эти сведения помогают приложению объяснить пользователю, чего не хватает.

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

Доступность сведений об ожидающем обновлении зависит от клиента обновлений: он должен предоставлять их через поддерживаемый механизм. Поэтому отсутствие таких данных нельзя автоматически трактовать как отсутствие исправлений или подтверждение безопасности устройства.
Swift 6.4 разрешает писать some View? и any P? без лишних скобок

Раньше optional-тип приходилось записывать как (some View)? или (any Delegate)?. Без скобок парсер связывал вопросительный знак с протоколом, а затем отклонял результат.

В Swift 6.4 изменили это правило: some View? означает optional от скрытого конкретного типа, а any Delegate? — optional от экзистенциального типа. Старые записи со скобками остаются корректными.

Исключение — композиция протоколов. Для неё всё ещё нужны (any Codable & Sendable)? или any (Codable & Sendable)?. Короткая запись any Codable & Sendable? не принимается.

Изменение упрощает объявления делегатов и возвращаемых значений. Разницу между some и any оно сохраняет, а переходить на новый синтаксис во всём проекте не обязательно.
Rive 6.28 автоматически перерисовывает анимацию при изменении связанных данных

В приложении поменялось значение модели, а анимация осталась прежней. В новом Swift Concurrency runtime Rive обновления связанных данных теперь сами вызывают перерисовку.

В релизе rive-ios 6.28.0 это работает для основной и глобальных моделей, включая вложенные модели и элементы списков. Отдельно следить за dirtyStream() ради перерисовки больше не требуется; API объявлен устаревшим.

При миграции важно сохранить нужные экземпляры моделей у себя и явно связать их с машиной состояний. У новых удобных инициализаторов устаревший getter Rive.viewModelInstance возвращает nil — прежний способ получить модель уже не подходит.

На странице релизов есть пример перехода. После 6.28.0 также вышла 6.28.1 с исправлениями и улучшениями списков, поэтому при обновлении стоит смотреть изменения обеих версий.
Google Play позволяет сообщать о проблемах оплаты подписки прямо в приложении

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

В разборе обновлений подписок Google Play Google отдельно выделяет In-App Messaging API. Он доступен всем разработчикам и позволяет показывать пользователю сообщения о проблемах оплаты и предстоящих изменениях цены внутри приложения.

Вместо собственного экрана с общим текстом «что-то пошло не так» можно подключить предусмотренный магазином сценарий восстановления оплаты. Это стоит проверить рядом с обработкой состояний подписки на сервере.

Само сообщение не подтверждает успешный платёж. Доступ к платным возможностям всё равно должен соответствовать актуальному состоянию покупки. В статье также описаны механизмы удержания и возврата подписчиков — их доступность нужно проверять отдельно.
Typed throws в Swift позволяет проверять обработку конкретного типа ошибок при компиляции

Обычный throws сообщает, что функция может завершиться ошибкой, но не ограничивает её конкретным типом. В catch приходится выяснять, что именно прилетело.

В разборе typed throws функция объявляет throws(CatError). Когда тип сохраняется до обработчика, catch получает CatError, и компилятор проверяет полноту switch по вариантам перечисления.

Однако конкретный тип можно потерять. Например, если внутри do вызываются функции с разными типами ошибок, результат может расшириться до any Error. Типизация замыканий тоже влияет на то, что дойдёт до вызывающего кода.

У публичного API есть цена: расширение набора ошибок затрагивает клиентов с исчерпывающей обработкой. Поэтому точный тип полезен там, где этот контракт действительно нужен. Автоматически заменять им все обычные throws не стоит.