We Love Android
Open in Telegram
655
Subscribers
No data24 hours
+17 days
+2430 days
Posts Archive
Repost from Ra'Reilly - Заметки про Android и не только
Насмотренность — важный навык в работе дизайнера. Это то что помогает быть в тренде, учиться на чужом опыте, черпать вдохновение, отличать хороший дизайн от плохого, критически оценивать свою работу и так далее. Нет вы не ошиблись каналом, просто я считаю, что насмотренность важна и разработчикам. Чем больше чужого кода смотришь — тем лучше пишешь свой. Просто потому что больше новых приёмов и концепций узнаёшь, улучшаешь свой скилл владения языком. С хэштегом #насмотренность буду писать про всё интересное на что наткнулся при просмотре open-source проектов. Это первый пост :)
👀 Companion object
Чаще всего
companion object используется просто как замена статическим методам и полям из Java. А ведь companion object это в первую очередь object и как у любого другого объекта у него может быть имя и он может реализовывать интерфейсы и наследоваться от других классов. Сегодня будет два примера таких companion object'ов.
☝️ Json в kotlinx.serialization
Это класс, но мы можем использовать его как-будто он object:
val result = Json.decodeFromString("42")
Всё потому что companion object у Json реализует класс Json:
companion object Default : Json(JsonConfiguration(), EmptySerializersModule())Зачем так сложно, если можно было бы просто объявить
object Json? Потому что тогда не было бы возможности создать свой инстанс, а когда Json это класс, такая возможность остаётся.
✌️CoroutineContext.Key в kotlinx.coroutines
CoroutineContext вообще интересная штука. По сути это что-то между Map и Set. Каждый элемент контекста хранится в CoroutineContext по ключу и получить элементы контекста можно через оператор get.
Каждый ключ должен быть singleton'ом и ключ должен быть у каждого элемента контекста (Job, CoroutineDispatcher и т.д.). Идеальная задача для companion object!
У каждого элемента контекста companion object это реализация CoroutineContext.Key и смотрите какая красота получается в совокупности с оператором get у CoroutineContext:
val job = coroutineContext[Job] val dispatcher = coroutineContext[CoroutineDispatcher]Выглядит как-будто получаем элемент контекста по типу. На самом деле используется
companion object c типом Key, объявленный в этих классах. Например, в Job он выглядит так:
companion object Key : CoroutineContext.Key<Job>
Repost from Dev Easy Notes
Два друга @JvmWildcard и @JvmSuppressWildcards.
В комментах накинули вопрос про @JvmSuppressWildcards. Тоже довольно неочевидная штука, но порой приходится разбираться. Суть в чем, Java и Kotlin полностью совместимы, что означает что из Java можно вызывать Kotlin, и наоборот. На стыке этих двух языков начинаются приколы, например в Kotlin все типы делятся на Nullable и NotNullable, а в Java такого разделения нет.
Работа дженериков тоже немного отличается. Буквально в предыдущем посте я описывал, что ковариантность и контравариантность в Kotlin может работать на уровне классов, а не ссылок. И вот пример:
class Box<out T>(val value: T)
fun box(value: Integer): Box< Integer> = Box(value)
fun unbox(box: Box<Number>): Number = box.value
Как видите в Box дженерик помечен как out, что означает ковариантность на уровне всех объектов. Только это работает на уровне Kotlin. Если попытаемся вызвать метод box из Java, то он вернет Box без дженерика. Это как бы немного нарушает логику ковариантности которую обещает Kotlin. При этом в методе unbox автоматически появится wildcard. В итоге в Java получим вот это:
Box box(Integer value)
Number unbox(Box<? extend Number>)
В целом все не так страшно, однако иногда охото подкрутить это поведение. Например, мы не хотим, чтобы в методе unbox автоматически проставлялся wildcard. Или же напротив проставлялся в результатах функции, в методе box. И вот для этого, нужны наши волшебные аннотации. Кафк всегда, лучше на примере.
Делаем в Kotlin:
fun box(value: Integer): Box<@JvmWildcard Integer> = Box(value)
Получаем в Java:
Box<? extend Integer> box(Integer value)
Делаем в Kotlin:
fun unbox(box: Box<@JvmSuppressWildcards Number>): Number = box.value
Получаем в Java:
Number unbox(Box<Number> box)
Сравните эти две полученные функции с дефектным поведением и суть станет ясна.
Где это нужно на практике? У меня такое было только при работе с Dagger. Фишка в чем, в том что Dagger работает на базе Kapt. Если вдруг не знали, то kapt работает в два приседания. Сперва он перегоняет весь код в Java Stub и только потом генерит нужный код. Поэтому он такой долгий и по этой причине иногда нужно делать подсказки компилятору, когда пишем модули на Kotlin. В противном случае кодогенератор начинает чудить и падать.Repost from Kotlin Multiplatform Broadcast
KMM Utilities - набор различных утилит для Kotlin
👉 ApiResult - монада для оборачивания результата операции. Схоже с kotlin.Result, но больше возможностей.
👉 Common - Дополнения к Kotlin stdlib
👉 Datetime - Все чего не хватает и kotlinx.datetime, Java Calendar и DateTime API.
👉 Coroutines: Расширения для Coroutines & Flows API. Расширения для Android.
Repost from Ra'Reilly - Заметки про Android и не только
Обычно мы на всех проектах добавляем тип сборки QA. Это такая сборка, которая максимально близка к релизной, но может включать в себя дебаг-панель и позволяет подключиться к приложению через дебаггер.
И вот недавно оказалось, что схема не работает. QA сборки не обфусцируются, а значит не сильно отличаются от дебажных. Причём не понятно в какой момент отвалилась обфускация и из-за чего это произошло.
Расследование привело к багтреккеру гугла: "AGP 7.2.0 onwards does not obfuscate our built app" и issue закрыто как Won't fix (Intended behavior) 🙂
Дело в том, что флаг 7.0 4.2 позволяет вклиниться в процесс подготовки артефактов сборки. Можно подменять, добавлять и изменять промежуточные файлы, например: манифест, APK и даже использовать совсем чёрную магию — модифицировать уже скомпилированные классы. Хотелось когда-нибудь модифицировать один класс в библиотеке, чтобы не ждать исправления бага?
Но сейчас не об этом. Нам интересен манифест. С помощью этого API мы можем дописать любой текст в смердженный манифест, в частности и флаг
isDebuggable = true теперь отключает обфускацию и по задумке инженеров гугла так должно было работать всегда. Ведь вы не сможете бегать по коду дебаггером, если он отличается от исходников, какой же это тогда получается debuggable? То что раньше была возможна обфускация с isDebuggable = true это изначально ошибочное поведение и AGP никогда не должен был так работать. Видимо ошибка показалась настолько очевидной, что фикс даже не упомянули в release notes, а как известно every change breaks someones workflow, что и случилось.
Решение подсказали там же в issue. Новый API, добавленный в AGP debuggable.
👨🦽 Результат можно увидеть в фиксе для gradle-infrastructure или в отдельном сниппете.
P.S. Помимо флага в манифесте приходится ещё руками менять значение BuildConfig.DEBUG ведь он тоже зависит от isDebuggable.
#agp #snippetRepost from Android Guards
Даже если на устройстве есть root доступ, команды
adb push/pull все равно будут работать в пользовательском режиме. Это значит, что не выйдет скачать или отправить файлы в директории доступные только суперпользователю. Но выход есть. Вместо adb push будет cat file.txt | adb shell su -c "dd of=/data/file.txt", а для замены adb pull - adb shell su -c "dd if=/data/file.txt" >> file.txt. В целом, так можно выполнить любую команду с правами root - adb shell su -c "<command>".
#ahtRepost from AppFiles - Mobile Development
SuperImage - это Android-приложение для улучшения качества изображений на основе нейронной сети, созданное с использованием фреймворка глубокого обучения MNN и Real-ESRGAN. Входное изображение обрабатывается тайлами на графическом процессоре устройства с использованием предварительно обученной модели Real-ESRGAN. Затем плитки объединяются в окончательное изображение с высоким разрешением. Это приложение требует поддержки Vulkan или OpenCL и Android 7 или выше.
SuperImage на GitHub: https://github.com/Lucchetto/SuperImage
Платформа: Android
⭐️: 486
Repost from Android Broadcast
Вышла вторая Dev Preview Android 14, которую можно ознаменовать как "еще больше ограничений для разработчиков" и радость для магазинов приложений!
👉 Выдача доступа приложения к отдельным фото и видео, вместо всех (аналогично на iOS)
👉 Credential Manager - единая точка работы с sign-in. Через Jetpack это API уже портировано на Android 4.4+
👉 Дополнительные ограничения по запуску Activity из фона
👉 Больше ограничений на фоновую работу
👉 Новое API в PackageInstaller позволит каждый раз не запрашивать установку приложений, а сделать это один раз для приложений. Альтернативным магазинам станет жить проще
👉 Региональные настройки для всей системы и для каждого приложения
👉 Разработчики смогут определить когда делаются скриншоты
Все изменения я разберу в отдельных постах
@android_broadcast #android14
Repost from Mobile Compose
#Article #Medium #Compose
[Eng] How to Handle Automatic Content Resizing when keyboard is visible in Jetpack Compose
Неплохая статья с разбором того, как можно адаптировать контент приложения под открытие/закрытие клавиатуры на Compose.
Repost from Android Broadcast
Обновили официальную документацию по обработке изменения конфигурации (поворот экрана, смена языка и пр.). Добавили советы по использованию Jetpack API, как работать с этим из Compose и лучшие практик
Repost from Kotlin Multiplatform Broadcast
Ключевые слова in и out. А так же что такое ковариантность и контрвариантность (12 мин)
Погружение в вариативность Generic типов в Kotlin. Тема непростая, но может раскрыть вам новые грани гибкости вашего кода и его строго типизации
Repost from Mobile Native ️️
Building an Android System Design Architecture for Efficient Image Uploads with Clean Architecture
Пример проектирования архитектуры для приложения, которое могло бы позволить загружать большое количество картинок на сервер без блокировки UI и с доп. кейсами.
Без примера кода, но с разбивкой на слои и детальным описанием связей и работы каждого слоя.
Читать (En)
Repost from Android Guards
Попалась мне тут совершенно замечательная ссылка, которой не имею сил не поделиться - https://github.com/krizzsk/HackersCave4StaticAndroidSec.
Там куча ссылок на туториалы, утилиты и исследования по уязвимостями в Android. Звучит скучно да? Верно. Это был бы еще один всратый "awesome list" если бы не одно "но" - там много ссылок на нативные китайские блоги и статьи. И там действительно полезная инфа, которую просто так не загулишь, если не ищешь специально на китайском. Я давно хотел найти что-то подобное и вот оно пришло. Из полезного лично для себя, я нашел там разбор форматов различных файлов (
AndroidManifest.xml, resources.arsc и т.п.) и материалы по статическому анализу. Всем 你好 ;)Repost from Mobile Native ️️
Mastering Execution Time Measurement in Kotlin
Статья с примерами того, как можно измерять время выполнение ваших функций в Kotlin, с помощью👇
• measureNanoTime()
• measureTimeMillis()
• measureTimeMicros()
• measureTime()
Читать (En)
Repost from Android Broadcast
В Chrome появится поддержка Partial Custom Tabs, которая частично перекрывает контент вашего приложения и позволяет взаимодействовать с вашим приложениям и Web контентом. Эта возможность уже доступна в Jetpack Browser 1.5.0
@android_broadcast #chrome #jetpack
Repost from Рубанов про мобилу
Про нейминг в коде
Арсений Мельников выпустил отличную статью про нейминг. Арсений занимается нашим публиным API у Dodo IS, круто что у него в этом такой системный подход.
https://habr.com/ru/company/dododev/blog/714512/
Repost from Mobile Compose
#Featured #AndroidDevelopers #MADSkills #YouTube
[Eng] Constraints and modifier order
Очередной видеоролик про базовые практики в Compose из серии MAD Skills, в котором на этот раз разбирается как работает цепочка модификаторов (Modifiers) в Compose, а также почему так важен порядок их применения.
Repost from Android Good Reads
Как Reddit переезжали на Anvil
Дано: приложение на 500 модулей, активно использующее Dagger 2 и кастомный kapt процессор для борьбы с циклическими зависимостями. Команде не нравилось, что их DI сетап слишком сложный, онбордить новых людей в него трудно, а использование kapt существенно замедляет сборку.
Чтобы решить эти проблемы, проект перевели на работу с Anvil. В статье – история миграции, результаты и советы тем, кто решит повторить их путь.
Repost from AppFiles - Mobile Development
Read You - открытый RSS-ридер для Android на Jetpack Compose и с Material You.
Read You на GitHub: https://github.com/Ashinch/ReadYou
Платформа: Android
⭐️: 1.8K
Repost from Mobile Compose
#Article #Blog #OpenSource
Maps Compose Library Tutorial for Android: Getting Started
В феврале 2022 года Google выпустила библиотеку Maps Compose (набор composable функций с открытым исходным кодом для упрощения интеграции с Google Maps, а также различных типов данных, связанных с Maps SDK). О том, как работать с этой библиотекой на примере приложения GeoMarker — в сегодняшней статье.
Repost from Mobile AppSec World
Дамп и расшифровка трафика без использования Proxy
Все мы так или иначе сталкивались с необходимостью посмотреть трафик приложения и поисследовать его. Но всегда мешают всякие нехорошие безопасники, которые заставляют делать разработчиков SSL Pinning в приложении. И наиболее частый вопрос - как открутить пиннинг в приложении.
Как правило, это использование frida или аналогов, чтобы подмениить и отключить проверку сертификата в приложении. Но сделать это удается далеко не всегда и не со всеми приложениями.
Есть альтернативный вариант данному методу - это логировать SSL-ключи, которые используются для шифрования внутри канала связи, снимать дамп трафика и потом его расшифровывать этими ключами.
Спасибо огромное @vadim_a_yegorov за универсальный скрипт для Android и iOS (12/13/14/15), который помогает снимать и сохранять ключи!
Вот тут можно найти полный Frida-код этого прекрасного скрипта.
Спасибо, это очень круто!
#sslpinning #ssl #keys #dump
