Kotlin Adept Notes
2.36K subscribers
82 photos
9 videos
133 links
Канал о разработке на Kotlin и обо всем, что с ним связано
По всем вопросам и рекламе: @ajiekcx
Download Telegram
Стоит ли переходить с Room на SQLDelight?

На данный момент обе библиотеки поддерживают KMP. Если раньше особого выбора не было, то теперь многие могут задаться вопросом: стоит ли вообще переходить с Room?

Я считаю, что нет, не стоит. Конечно, у каждой библиотеки есть свои преимущества и недостатки, но, на мой взгляд, у SQLDelight их заметно больше:

🔘 Нельзя задать разные имена для таблицы в БД и сгенерированного класса. Если вы придерживаетесь общепринятого синтаксиса именования таблиц, то имена сгенерированных классов будут выглядеть просто ужасно.
🔘 Видимость сгенерированных файлов также нельзя регулировать — все они будут public.
🔘 Нет поддержки suspend-функций, приходится явно менять диспетчер для каждого запроса. (оказывается есть, в настройках плагина есть свойство generateAsync)
🔘 Нельзя сразу сгенерировать класс с отношением many-to-many или другими связями, например, чтобы получить фильм со списком актёров, придётся делать дополнительный маппинг на стороне Kotlin.
🔘 Нет автоматических миграций, как в Room (но в целом это зло).
🔘 Очень скудная документация.

Из плюсов я бы выделил следующее:

🟢 Небольшие таблицы можно сразу смаппить в доменные типы с помощью Type Projections.
🟢 Нет магии аннотаций, все запросы пишутся явно.
🟢 Нет зависимости на KSP и плагины компилятора.
🟢 Поддерживается больше таргетов, чем в Room.
🟢 Может работать не только с SQLite.

В общем, я пришёл к выводу, что Room для меня выигрывает у SQLDelight, и мигрировать с него я бы не стал. Но и возвращаться обратно, если вы уже перешли, особого смысла тоже не вижу.

А что думаете вы, какая из библиотек вам ближе

#Room #SQLDelight #KMP
Please open Telegram to view this post
VIEW IN TELEGRAM
25👍12❤‍🔥3
10 кругов ада, или как вручную перенести все фотки из-за аккаунта разработчика

Так вышло, что фотографирую я не очень часто, и только сейчас у меня закончилось место на Google Диске. Теперь в каждом своём приложении Google показывает страшные баннеры и вынуждает купить подписку 🤑

Что ж, убедили, идём покупать. Но с русским платёжным профилем ничего не купить. Зачем тогда предлагали? Ну да ладно.

Пытаемся поменять платёжный профиль, но этого сделать нельзя из-за активного аккаунта разработчика 🤨

Аккаунт я давно забросил и все приложения там удалил, но Google заодно «удалил» и мой аккаунт, так как я не подтвердил личность.

Пишу в техподдержку, чтобы аккаунт удалили окончательно и я смог поменять платёжный профиль. На что получаю ответ: сделать это нельзя, если на аккаунте нет активных приложений 😵

Тут я понял, что ситуация патовая и надо что-то делать. Одним из вариантов было создать новый аккаунт для фоток и заодно перенести все фото на Яндекс Диск.

Окей, качаем через Google Takeout архив со всеми фотками. Метаданные EXIF лежат там в отдельном JSON-файле, соответственно, ни данных о дате, ни геолокации в фотке нет, и нужно это как-то восстанавливать.

Я нашёл скрипт на Python, который это делает, и пришлось ещё немного подвайбкодить, чтобы всё заработало...

Вот такой вот квест получился. А если бы аккаунта разработчика не было, все бы решилось проще, так что думайте 😏

#Offtop
Please open Telegram to view this post
VIEW IN TELEGRAM
1🤯22😁84👍1😨1
Зоопарк кроссплатформенных фреймворков

Думаю, вы все слышали про такие фреймворки, как Flutter и Expo (React Native) для разработки кроссплатформенных мобильных приложений и не только. Но, разумеется, таких фреймворков существует значительно больше, и по сей день появляются новые решения.

Давайте рассмотрим некоторые из них:

Valdi — фреймворк от Snapchat, где UI пишется на TypeScript DSL, который напрямую компилируется в нативные вьюшки. Разработчики обещают производительность, сопоставимую с нативными приложениями, так как фреймворк не использует ни WebView, ни JavaScript Bridge. Поддерживает Android, iOS и macOS.

ArkUI-X — проект, расширяющий декларативный UI-фреймворк для разработки приложений под HarmonyOS NEXT и позволяющий добавить поддержку компиляции под Android и iOS. Это ещё один фреймворк, использующий TypeScript, а точнее его надмножество ArkTS.

Skip — единственный платный для корпоративного использования фреймворк, который изначально представлял собой транспилятор из Swift в Kotlin и позволял переводить нативные iOS-приложения на SwiftUI в Android-приложения с Jetpack Compose. Но в новом режиме Fuse Skip начал использовать недавно вышедший Swift SDK для Android, что позволит уйти от прямой транспиляции кода по крайней мере для бизнес-логики.

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

#Crossplatform #Frameworks
👍12😐7
Как улучшить дальность сканирования кодов маркировки

Библиотеки вроде Google ML Kit, ZXing или его аналога на C++ со стандартными настройками камеры имеют довольно посредственную дальность сканирования, приходится подносить камеру очень близко, чтобы хоть что-то отсканировать. Особенно это касается акцизных марок нового образца. При этом, если взглянуть на коммерческие решения, они работают на голову выше.

Как можно улучшить ситуацию?

🟢Как ни странно, можно попробовать уменьшить разрешение камеры, двух мегапикселей более чем достаточно для распознавания.
🟢Увеличить параметр zoomRatio в камере по-умолчанию, например, установить 1.5f вместо 1f.
🟢Реализовать автоматический зум к потенциальным кодам. Для этого в ML Kit появились настройки enableAllPotentialBarcodes и ZoomSuggestionOptions.
🟢Ограничить размер зоны сканирования.

Наверняка можно придумать что-то ещё. Хотелось бы спросить совета у тех, кто уже сталкивался с подобной задачей, есть идеи, что еще можно сделать?

P.S. Обучение собственной модели не предлагать 🙂

#Camera #BarcodeReader
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👍5❤‍🔥3😈1
Посмотрите на код на изображении. Эта 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
🤯22🔥4😭3👍2
Android Gradle Library Plugin

Если вы вдруг пропустили, то для KMP-проектов появился отдельный Android-плагин для library-модулей, который значительно уменьшает количество Gradle-тасок и ускоряет как конфигурацию проекта, так и сборку.

Особенности плагина:

🔘В нём убрали поддержку flavor и build type.
🔘Отключена Java-компиляция по умолчанию.
🔘Отключены по умолчанию unit и инструментальные тесты (не забудьте про них, а то будет как в этом посте).

Мы уже подключили его в пару наших проектов, и результаты действительно впечатляющие 🔥

🟢Количество тасок при прогоне unit-тестов уменьшилось более чем в 4 раза, и во столько же раз удалось ускорить их выполнение.
🟢С Android Lint похожая история: там количество запускаемых тасок сократилось в 2 раза, и в 1,5 раза удалось получить прирост скорости.

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

#Android #KMP #Gradle
Please open Telegram to view this post
VIEW IN TELEGRAM
👍26😱2
Jetpack Navigation 3

Только сейчас дошли руки более пристально взглянуть на новую Jetpack Navigation 3.

Помню, многие жаловались, что Decompose весь такой сложный, а навигация от Google простая. Но что мы видим в новой версии:
NavBackStack, NavEntry, NavDisplay, NavEntryDecorator, SceneStrategy и так далее 🫠

При этом, несмотря на то что вышла стабильная версия, много кода всё равно придётся писать дополнительно:

Хочешь навигацию по табам? Пиши код для управления бэкстеком.
Нужен BottomSheet? Пиши декоратор.
Необходимо привязать ЖЦ ViewModel к экрану? Подключай отдельную библиотеку.
Нужна вложенная навигация? Разбирайся с кастомными сценами.

В общем, вы поняли. Довольно много бойлерплейта придётся копировать из примеров на GitHub, чтобы всё завести. Если хотите, чтобы я сделал подробное сравнение с Decompose, вы знаете, что надо сделать 👍

Ну и напишите, планируете ли вы миграцию с любой другой библиотеки на Navigation 3? Интересно будет узнать ваше мнение.

#Compose #Navigation
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍103🔥157🤯4
Представьте ситуацию: вы скачали какое-то приложение из Google Play и отложили телефон, а тем временем кто-то получает полный удаленный доступ к вашему устройству, разблокирует его и может зайти в любое приложение даже без вашего разрешения на шаринг экрана 😨

Звучит жутко. Но такой вирус точно не пропустят в сторы, да ведь?

На самом деле еще как пропустят, потому что именно так работают приложения для удаленного доступа. Мой коллега Андрей Жуков поделился особенностями технической реализации такого приложения.

Ключевым элементом для удаленного управления является Accessibility Service и справедливости ради, пользователю все-таки придется выдать одно разрешение на его использование, поэтому просто скачать приложение недостаточно.

Теперь оператор сможет удаленно управлять устройством. Однако без доступа к шарингу экрана ничего видно не будет. Но как выдать разрешение без ведома пользователя? Очень просто: находим нужную кнопку подтверждения трансляции экрана и автоматически нажимаем на нее через тот же Accessibility Service 💀

Дальше встает вопрос: а как приложение может вообще работать до разблокировки экрана пользователем? Для этого в Android есть специальный режим Direct Boot mode. Его особенность в том, что у приложения есть доступ только к специальному зашифрованному хранилищу устройства, и для работы в этом режиме как минимум придется произвести миграцию SharedPreferences.

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

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

#Android #AccessibilityService #RemoteControll
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1079👍7
Итоги 2025 года

Как и у многих, у меня выдался не самый простой конец года, и в целом этот год для индустрии вышел нелёгким: какие-то проекты закрылись, кого-то сократили, и в целом чувствуется упадок интереса к сфере мобильной разработки и не только 😕

Тем не менее хочется верить в лучшее, что турбулентность пройдёт, компании адаптируются к новым условиям и снова начнут вкладывать деньги в инвестиционную деятельность 🤑

Несмотря на всё это, канал значительно вырос за этот год. Спасибо всем старым и новым подписчикам за поддержку, лайки, репосты и комментарии. Всё это мотивирует и дальше продолжать вести канал и как-то развивать наше сообщество ❤️

Всех с наступающим и отличных вам новогодних каникул 🏡
Please open Telegram to view this post
VIEW IN TELEGRAM
50
Pixnapping attack

На днях узнал об одной интересной уязвимости, которая, по сути, без каких-либо разрешений и без root-доступа позволяет украсть изображение с любого приложения на устройстве будь то браузер или нативное приложение, например TOTP-код из Google Authenticator 😱

Как это работает?

🔘Атакующее приложение через intent открывает приложение-жертву и тут же возвращает свою Activity в foreground, что делает атаку почти незаметной для пользователя.
🔘Затем поверх атакуемого приложения накладывается стек полупрозрачных Activity, где всё заливается белым цветом за исключением одного прозрачного пикселя, через который просвечивает UI атакуемого приложения.
🔘Используя blur и особенности SurfaceFlinger, можно растянуть этот пиксель и получить либо однородный шаблон, если пиксель белый, либо шумный, если пиксель другого цвета.
🔘Далее нужно определить цвет пикселя. Это делается за счёт особенностей графического сжатия в GPU: однородные изображения рендерятся быстрее, а шумные медленнее. Измерить это время можно с помощью VSync callback.
🔘Таким образом, повторяя этот процесс для разных пикселей, можно полностью восстановить изображение атакуемого приложения 👍

Насколько это опасно?

На текущий момент нет гарантированной защиты от этой атаки, хотя Google и предприняла попытку ограничить количество Activity, которые могут использовать blur. Однако, как можно понять, такой сложный pipeline требует времени: полное восстановление изображения может занимать порядка 24 часов 😁
Поэтому для сценариев кражи TOTP-кодов используются более оптимизированные варианты атаки.

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

А вам в целом откликается тема безопасности? Было бы вам интересно узнать больше про подобного рода уязвимости?

#Security #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍59🤯23🔥6🤔32
Продолжим тему безопасности. Сейчас всё чаще мобильные разработчики начинают писать свои бэкенды, разумеется, с 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
👍283🔥1👏1