Мобильная разработка
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
Границы модулей, которые нельзя обойти случайным 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 не стоит.
Google открыл публикацию Android-игр для автомобильных экранов с запуском только на стоянке

Игры для Android Auto и Android Automotive OS вышли из беты: теперь разработчики могут отправлять их в открытое тестирование и в рабочую публикацию Google Play.

В руководстве по адаптации разобраны настройки манифеста и требования к поведению. Для Android Auto поддержка игр начинается с Android 15; для Automotive OS отдельно объявляется автомобильный форм-фактор.

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

Ещё понадобятся адаптация под широкие и вертикальные экраны и проверка качества. Android Auto тестируют через Desktop Head Unit, Automotive OS — через соответствующий эмулятор. Одних изменений манифеста для публикации недостаточно.
😁1