Переход на AGP 9 в KMP-проектахМы долго откладывали миграцию на AGP 9, ждали, пока всякие авторы по типу Huawei адаптирует свои плагины, и наконец решились ⚪️Казалось бы, спустя столько времени это должна была быть легкая прогулка, но не тут-то было.С какими проблемами столкнулись🟢Теперь нельзя использовать плагин android.application в KMP-модулях.🟢Все модули нужно было мигрировать на новый Android Gradle Plugin.🟢Больше нельзя генерировать BuildConfig в KMP-модулях.🟢Значительно изменились многие API, которые мы использовали в своих Gradle-плагинах.Помимо этого, обновление Kotlin и Compose нам тоже вставило палки в колеса, но сегодня не об этом. Так что поделюсь рекомендациями для тех, кто еще не перевел свои проекты.Скиллы для агентов🟢Официальный skill от Google для миграции KMP-проектов абсолютно не подходит: он лишь понаделал кучу deprecated свойств в gradle.properties.🟢А вот аналогичный skill от JetBrains хорош! К сожалению, мы узнали о нем поздно, поэтому пришлось делать свой, но с pet-проектом он справился отлично.Что еще почитать🟢Переход на Android Gradle Plugin для KMP🟢Миграция на built-in Kotlin🟢Гайд по миграции на AGP 9💬 А как прошла ваша миграция на APG 9?
Kotlin Adept Notes
@kotlin_adept
Канал о разработке на Kotlin и обо всем, что с ним связано По всем вопросам и рекламе: @ajiekcx
Похожие каналы
Все →Последние посты
Особенности работы с Passkeys в Android и iOSМы наконец-то реализовали мультиплатформенный модуль для работы с Passkeys и хочу поделиться нюансами, с которыми столкнулись.Passkeys — более безопасная и простая альтернатива паролям, где аутентификация в сервисе происходит по биометрии.В случае с Android поддержка Passkeys появилась с Android 9, в то время как на iOS только с iOS 16. При этом технология значительно совершенствовалась в последних версиях ОС, например, предоставляя выбор кастомного менеджера паролей.🤖 В Android работа с Passkeys происходит через CredentialManager и реализована довольно удобно: почти всё происходит под капотом, достаточно лишь передать JSON с бэкенда. Но есть две проблемы: обработка ошибок и необходимость в Activity context, что создаёт определённые архитектурные сложности. В случае обработки ошибок приходится вручную извлекать из текста через регулярки коды ошибок, чтобы отображать понятные пользователю сообщения.🇨🇳 А вот пользователи Huawei, к сожалению, не смогут воспользоваться этой фичей, так как CredentialManager просто отказывается работать с другими менеджерами паролей. Хотя для Huawei существует своя реализация FIDO2, API там реализован далеко не лучшим образом, и всё это делается через отдельную Activity, которая будет открываться даже если ключей нет 😐🍏В iOS же работа с Passkeys происходит через ASAuthorizationController, где приходится вручную мапить каждое поле, конвертировать NSData в Base64URL и обратно. В общем, работать со всем этим добром не очень удобно. Также имеются отличия от Android: например, нельзя передать excludeCredentials для исключения дубликатов ключей, и не поддерживается direct attestation, который позволяет определить, что устройство подписано корневым сертификатом производителя.💬 А вы интегрировали Passkeys в свой проект или планируете это сделать?#Passkeys #KMP #Android #iOS
Генерация макетов через Figma MCP 🖌Пока все говорят про "убийцу Figma", хочу рассказать о том, как мне удалось примерить шапочку дизайнера и собрать макеты приложения в Figma с использованием корпоративной дизайн-системы с помощью Figma MCP.Не так давно Figma сделала скил под названием figma-use, который даёт доступ к рисованию на канвасе, переменным, стилям и компонентам. И это стало отличным шансом собрать макеты приложения без навыков работы в Figma.Я не стал сразу пытаться собирать макеты в Figma, а начал с генерации макетов в виде сайта, скормив бизнес-сценарии приложения и несколько изображений-референсов по стилю AI-агенту. В целом Claude с одного промта справился очень даже неплохо, дальше пришлось просто допилить некоторые моменты.И уже после этого я решил зафиксировать макеты в Figma на основе сгенерированного сайта. Но первое, во что я упёрся — это лимиты Figma: они закончились буквально за пару вызовов MCP, так что на бесплатном тарифе можете даже не пытаться что-то сделать 🙃Далее я попробовал выборочно перенести экран как есть, без использования дизайн-системы, и это сработало хорошо, всё перенеслось так, как я и ожидал. Но проблемы начались, когда нужно было использовать компоненты существующей дизайн-системы.В нашем случае ключевой проблемой оказались кастомные шрифты, которых нет в Figma, из-за чего MCP не может редактировать текст в компонентах 😠В итоге, чтобы добиться хоть какого-то вменяемого результата, мне пришлось создать ещё два скила: один для корректной работы с палитрой, чтобы правильно выбирать цвета, и отдельно для работы с дизайн-системой, где описаны id всех компонентов и их свойства, а также решения для всех проблем, возникших по пути.Через боль и страдания я перенёс все макеты. И что могу сказать по текущему статусу работы Figma MCP: пока что это очень сырая штука. Механизм self-валидации через скриншоты работает ужасно — такое ощущение, что работаешь со слепым дизайнером. Да и в целом всё это работает очень долго, даже банальные з
Как защитить API от нежданных клиентовНа днях я делал приложение для bug bounty активности на конференции, в котором нужно будет найти секретную ссылку. Мне не хотелось, чтобы всё решилось простым запросом в AI или пересборкой приложения с отключением SSL-пиннинга, поэтому я задумался о том, как защититься от пересборки приложения, чтобы только версия с моей подписью могла делать запросы к серверу.Я решил попробовать Play Integrity. Всё бы ничего, но приложение должно быть обязательно опубликовано в Google Play, хотя бы во внутреннем тестировании, иначе аттестация устройства не будет проходить. Поэтому этот вариант мне не подошёл, и я решил реализовать собственный сервер аттестации, который проверяет цепочку сертификатов, извлекает из сертификата отпечаток подписи приложения и сравнивает его с заданным.Звучит круто, но почему тогда это не используется массово? Дело в том, что, во-первых, это работает не на всех версиях Android. Кроме того, устройство должно поддерживать Hardware Attestation, что может отсечь часть устройств и на них приложение просто не будет работать.Если вас заинтересовала тема, вы ещё успеваете залететь на Podlodka Android Crew и послушать доклад про Play Integrity, где разберут как работают эти механизмы. А ещё вы сможете попробовать сами обойти эту защиту в нашей bug bounty активности 💻Так что присоединяйтесь, будет не только полезно, но и интересно 😉

Розыгрыш билета на Podlodka Android Crew #15Мы снова подготовили для вас новый сезон конференции Podlodka Android Crew, который пройдет с 30 марта по 3 апреля.В этот раз неделя будет посвящена безопасности в Android-разработке, и, на мой взгляд, нам удалось собрать интересную программу.Мой личный топ докладов, которые хотелось бы послушать:🔘Про защиту видеоконтента🔘Про passkeys, так как прямо сейчас мы имплементируем это у себя🔘Про то, как работает защита Play Integrity🔘Про reverse engineering на практике от моего коллегиИ в связи с этим хочу провести розыгрыш билета.Условия розыгрыша💬 Вам нужно написать комментарий под этим постом на тему безопасности мобильных приложений. Можно рассказать про самый интересный баг в безопасности, с которым вы сталкивались, или, наоборот, поделиться опытом, как вы реализовали какое-то безопасное решение.Итоги розыгрыша🗓 Победителя выберу случайным образом уже в эту субботу в 10:00 МСК. Удачи!P.S. Ну а для тех, кто не хочет участвовать в розыгрыше, могу предложить скидку по промокоду adept15
Vibe reverse engineeringРаньше, чтобы разобраться в том, как работает тот или иной участок кода без доступа к исходникам было не самой простой задачей и требовало определенных навыков. Сейчас же AI-агенты могут прочитать ваш APK как открытую книгу, и R8 уже не так сильно усложняет злоумышленнику жизнь. По сути, порог входа в reverse engineering значительно снизился.Как вкатиться в reverse engineering?Я рекомендую попробовать APKLab — это плагин для VS Code, который позволяет дизассемблировать APK в байткод (smali-файлы), декомпилировать в Java через утилиту jadx, пересобирать APK с изменением исходного кода и делать ещё много всего крутого.Далее просто открываем APK-файл в этой утилите, при желании декомпилируем исходники в Java и натравливаем на всё это AI-агента с мощной моделью, задавая интересующие вопросы по кодовой базе.В целом это уже очень неплохо работает: агент легко находит различные связи в коде, и Java-код ему даже не обязателен, он спокойно ориентируется и в байткоде. Единственное ограничение — это размер контекста, но в скором времени, думаю, и это перестанет быть проблемой.Как теперь защищать критически важный исходный код?В целом — никак. Стопроцентной защиты никогда и не существовало 👍По сути, единственный способ, который гарантированно усложнит злоумышленнику жизнь — это использование нативного кода. Однако и для этих целей уже есть готовый MCP-сервер для IDA Pro.Так что сохранить исходный код в тайне в мобильных приложениях становится всё сложнее. А вам приходилось делать коммерческие SDK, в которых нужно по максимуму защитить исходный код?#ReverseEngineering #Security #AI
Устроил себе месячный детокс от программирования и это прекрасно. Всем рекомендую попробовать 🏝И забавно, что за этот месяц в мобильной разработке почти ничего интересного не произошло, все разговоры только про AI да и только. Отсюда складывается стойкое ощущение, что сфера потихоньку умирает. Или нет?Давайте разберёмся вместе, поэтому призываю вас принять участие в исследовании мобильных разработчиков от DevCrowd.Зачем участвовать?– сверить себя с рынком: стек, грейд, зарплаты– понять, что происходит в мобильной разработке в целом: кроссплатформа победила или натив всё ещё жив– узнать, насколько мобильные разработчики адаптировались к AI-миру– разобраться, куда расти и где сейчас проще или сложнее с работой📝 Опрос займёт примерно 10 минут📊 Итоги появятся в апреле на devcrowd.ru👉 Пройти опрос

Продолжим тему безопасности. Сейчас всё чаще мобильные разработчики начинают писать свои бэкенды, разумеется, с AI-агентами, куда же без них. И в плане безопасности доверять ИИ точно не стоит!Предположим, мы хотим, чтобы для каждого URL, начинающегося с /api/, проверялось, что пользователь предоставил некий ключ доступа, иначе возвращалась ошибка. И для Ktor Server ИИ может написать вам такой интерцептор, который показан на изображении, и это даже как-то будет работать, но, разумеется, есть нюанс. Есть идеи, как это можно обойти?На самом деле всё очень просто: нужно всего лишь заменить букву соответствующим кодом в ASCII. Например, было http://0.0.0.0:4040/api/apps, а стало http://0.0.0.0:4040/%61pi/apps.Таким образом, проверка перестанет работать, а все запросы будут успешно выполняться.Более правильным вариантом было бы использование встроенных механизмов аутентификации, чтобы неявно проверять API-key для каждой ручки.#Security #Ktor #Backend

Pixnapping attackНа днях узнал об одной интересной уязвимости, которая, по сути, без каких-либо разрешений и без root-доступа позволяет украсть изображение с любого приложения на устройстве будь то браузер или нативное приложение, например TOTP-код из Google Authenticator 😱Как это работает?🔘Атакующее приложение через intent открывает приложение-жертву и тут же возвращает свою Activity в foreground, что делает атаку почти незаметной для пользователя.🔘Затем поверх атакуемого приложения накладывается стек полупрозрачных Activity, где всё заливается белым цветом за исключением одного прозрачного пикселя, через который просвечивает UI атакуемого приложения.🔘Используя blur и особенности SurfaceFlinger, можно растянуть этот пиксель и получить либо однородный шаблон, если пиксель белый, либо шумный, если пиксель другого цвета.🔘Далее нужно определить цвет пикселя. Это делается за счёт особенностей графического сжатия в GPU: однородные изображения рендерятся быстрее, а шумные медленнее. Измерить это время можно с помощью VSync callback.🔘Таким образом, повторяя этот процесс для разных пикселей, можно полностью восстановить изображение атакуемого приложения 👍Насколько это опасно?На текущий момент нет гарантированной защиты от этой атаки, хотя Google и предприняла попытку ограничить количество Activity, которые могут использовать blur. Однако, как можно понять, такой сложный pipeline требует времени: полное восстановление изображения может занимать порядка 24 часов 😁 Поэтому для сценариев кражи TOTP-кодов используются более оптимизированные варианты атаки.На мой взгляд, уязвимость очень интересная, но из-за её сложности маловероятно, что она будет массово эксплуатироваться в реальных условиях.А вам в целом откликается тема безопасности? Было бы вам интересно узнать больше про подобного рода уязвимости?#Security #Android

Итоги 2025 годаКак и у многих, у меня выдался не самый простой конец года, и в целом этот год для индустрии вышел нелёгким: какие-то проекты закрылись, кого-то сократили, и в целом чувствуется упадок интереса к сфере мобильной разработки и не только 😕Тем не менее хочется верить в лучшее, что турбулентность пройдёт, компании адаптируются к новым условиям и снова начнут вкладывать деньги в инвестиционную деятельность 🤑Несмотря на всё это, канал значительно вырос за этот год. Спасибо всем старым и новым подписчикам за поддержку, лайки, репосты и комментарии. Всё это мотивирует и дальше продолжать вести канал и как-то развивать наше сообщество ❤️Всех с наступающим и отличных вам новогодних каникул 🏡
Представьте ситуацию: вы скачали какое-то приложение из Google Play и отложили телефон, а тем временем кто-то получает полный удаленный доступ к вашему устройству, разблокирует его и может зайти в любое приложение даже без вашего разрешения на шаринг экрана 😨Звучит жутко. Но такой вирус точно не пропустят в сторы, да ведь? На самом деле еще как пропустят, потому что именно так работают приложения для удаленного доступа. Мой коллега Андрей Жуков поделился особенностями технической реализации такого приложения.Ключевым элементом для удаленного управления является Accessibility Service и справедливости ради, пользователю все-таки придется выдать одно разрешение на его использование, поэтому просто скачать приложение недостаточно.Теперь оператор сможет удаленно управлять устройством. Однако без доступа к шарингу экрана ничего видно не будет. Но как выдать разрешение без ведома пользователя? Очень просто: находим нужную кнопку подтверждения трансляции экрана и автоматически нажимаем на нее через тот же Accessibility Service 💀Дальше встает вопрос: а как приложение может вообще работать до разблокировки экрана пользователем? Для этого в Android есть специальный режим Direct Boot mode. Его особенность в том, что у приложения есть доступ только к специальному зашифрованному хранилищу устройства, и для работы в этом режиме как минимум придется произвести миграцию SharedPreferences.Остается решить вопрос со стабильностью. Например, можно перезапускать сервисы после перезагрузки устройства, реализовать механизм хелсчеков, детектить, что система пересоздала sticky-сервис, или прибегнуть к советам из этого поста.В общем, лично для меня тема показалась очень интересной, но в формате одного поста раскрыть ее полноценно не получится. Если вы хотели бы узнать подробности, то ставьте реакции, и я мотивирую ребят написать подробную статью или сделать доклад по теме. 🔥#Android #AccessibilityService #RemoteControll
Jetpack Navigation 3Только сейчас дошли руки более пристально взглянуть на новую Jetpack Navigation 3.Помню, многие жаловались, что Decompose весь такой сложный, а навигация от Google простая. Но что мы видим в новой версии:NavBackStack, NavEntry, NavDisplay, NavEntryDecorator, SceneStrategy и так далее 🫠При этом, несмотря на то что вышла стабильная версия, много кода всё равно придётся писать дополнительно:Хочешь навигацию по табам? Пиши код для управления бэкстеком.Нужен BottomSheet? Пиши декоратор.Необходимо привязать ЖЦ ViewModel к экрану? Подключай отдельную библиотеку.Нужна вложенная навигация? Разбирайся с кастомными сценами.В общем, вы поняли. Довольно много бойлерплейта придётся копировать из примеров на GitHub, чтобы всё завести. Если хотите, чтобы я сделал подробное сравнение с Decompose, вы знаете, что надо сделать 👍Ну и напишите, планируете ли вы миграцию с любой другой библиотеки на Navigation 3? Интересно будет узнать ваше мнение.#Compose #Navigation
Android Gradle Library PluginЕсли вы вдруг пропустили, то для KMP-проектов появился отдельный Android-плагин для library-модулей, который значительно уменьшает количество Gradle-тасок и ускоряет как конфигурацию проекта, так и сборку.Особенности плагина:🔘В нём убрали поддержку flavor и build type.🔘Отключена Java-компиляция по умолчанию.🔘Отключены по умолчанию unit и инструментальные тесты (не забудьте про них, а то будет как в этом посте).Мы уже подключили его в пару наших проектов, и результаты действительно впечатляющие 🔥🟢Количество тасок при прогоне unit-тестов уменьшилось более чем в 4 раза, и во столько же раз удалось ускорить их выполнение.🟢С Android Lint похожая история: там количество запускаемых тасок сократилось в 2 раза, и в 1,5 раза удалось получить прирост скорости.В общем, миграция определённо того стоит, но посмотрите внимательно на текущие ограничения в документации, возможно, вам пока этот плагин не подойдёт.#Android #KMP #Gradle

Посмотрите на код на изображении. Эта composable-функция используется на экране с камерой, чтобы сделать полупрозрачную рамку по периметру. Как думаете, в чем тут проблема?Вместо прозрачного выреза на некоторых старых устройствах будет чёрный прямоугольник.Я уже когда-то сталкивался с этой проблемой, когда Compose еще не было и в помине. При работе с Android Canvas проблема заключалась в использовании PorterDuff.Mode.CLEAR.В прошлый раз эту проблему в AndroidView удалось пофиксить, переведя отрисовку на hardware-accelerated layer:setLayerType(LAYER_TYPE_HARDWARE, null)Но как сделать то же самое в Compose? Если просто получить текущий View через LocalView, то, вероятно, мы не получим нужного поведения, так как изменим layerType для верхнеуровневой вьюшки.Мне ничего лучше не пришло в голову, чем сделать composable-функцию враппер, в которой контент будет прокидываться в AbstractComposeView, где уже и будет происходить изменение layerType.Таким образом, чтобы пофиксить проблему, достаточно будет обернуть код на изображении в этот враппер. Если нужен код враппера, напишите в комментариях.P.S. Как думаете, когда люди уже перестанут использовать семилетние смартфоны Xiaomi?#Android #Canvas #Compose

Как улучшить дальность сканирования кодов маркировкиБиблиотеки вроде Google ML Kit, ZXing или его аналога на C++ со стандартными настройками камеры имеют довольно посредственную дальность сканирования, приходится подносить камеру очень близко, чтобы хоть что-то отсканировать. Особенно это касается акцизных марок нового образца. При этом, если взглянуть на коммерческие решения, они работают на голову выше.Как можно улучшить ситуацию?🟢Как ни странно, можно попробовать уменьшить разрешение камеры, двух мегапикселей более чем достаточно для распознавания.🟢Увеличить параметр zoomRatio в камере по-умолчанию, например, установить 1.5f вместо 1f.🟢Реализовать автоматический зум к потенциальным кодам. Для этого в ML Kit появились настройки enableAllPotentialBarcodes и ZoomSuggestionOptions.🟢Ограничить размер зоны сканирования.Наверняка можно придумать что-то ещё. Хотелось бы спросить совета у тех, кто уже сталкивался с подобной задачей, есть идеи, что еще можно сделать?P.S. Обучение собственной модели не предлагать 🙂#Camera #BarcodeReader