We Love Android – Telegram
We Love Android
632 subscribers
259 photos
26 videos
4 files
630 links
Новости из мира Android-разработки
Download Telegram
Forwarded from Mobile Native ️️
Mastering Execution Time Measurement in Kotlin

Статья с примерами того, как можно измерять время выполнение ваших функций в Kotlin, с помощью👇

• measureNanoTime()
• measureTimeMillis()
• measureTimeMicros()
• measureTime()

Читать (En)
👍2
Forwarded from Android Guards
Попалась мне тут совершенно замечательная ссылка, которой не имею сил не поделиться - https://github.com/krizzsk/HackersCave4StaticAndroidSec.

Там куча ссылок на туториалы, утилиты и исследования по уязвимостями в Android. Звучит скучно да? Верно. Это был бы еще один всратый "awesome list" если бы не одно "но" - там много ссылок на нативные китайские блоги и статьи. И там действительно полезная инфа, которую просто так не загулишь, если не ищешь специально на китайском. Я давно хотел найти что-то подобное и вот оно пришло. Из полезного лично для себя, я нашел там разбор форматов различных файлов (AndroidManifest.xml, resources.arsc и т.п.) и материалы по статическому анализу. Всем 你好 ;)
🔥4
Forwarded from Mobile Native ️️
Building an Android System Design Architecture for Efficient Image Uploads with Clean Architecture

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

Без примера кода, но с разбивкой на слои и детальным описанием связей и работы каждого слоя.

Читать (En)
👍1
Forwarded from Kotlin Multiplatform Broadcast (Кирилл Розов)
Ключевые слова in и out. А так же что такое ковариантность и контрвариантность (12 мин)

Погружение в вариативность Generic типов в Kotlin. Тема непростая, но может раскрыть вам новые грани гибкости вашего кода и его строго типизации
👍2💩2
Forwarded from Android Broadcast (Кирилл Розов)
Обновили официальную документацию по обработке изменения конфигурации (поворот экрана, смена языка и пр.). Добавили советы по использованию Jetpack API, как работать с этим из Compose и лучшие практик
👍2
Forwarded from Android Broadcast (Кирилл Розов)
Вышла вторая Dev Preview Android 14, которую можно ознаменовать как "еще больше ограничений для разработчиков" и радость для магазинов приложений!
👉 Выдача доступа приложения к отдельным фото и видео, вместо всех (аналогично на iOS)
👉 Credential Manager - единая точка работы с sign-in. Через Jetpack это API уже портировано на Android 4.4+
👉 Дополнительные ограничения по запуску Activity из фона
👉 Больше ограничений на фоновую работу
👉 Новое API в PackageInstaller позволит каждый раз не запрашивать установку приложений, а сделать это один раз для приложений. Альтернативным магазинам станет жить проще
👉 Региональные настройки для всей системы и для каждого приложения
👉 Разработчики смогут определить когда делаются скриншоты

Все изменения я разберу в отдельных постах

@android_broadcast #android14
👍3
SuperImage - это Android-приложение для улучшения качества изображений на основе нейронной сети, созданное с использованием фреймворка глубокого обучения MNN и Real-ESRGAN. Входное изображение обрабатывается тайлами на графическом процессоре устройства с использованием предварительно обученной модели Real-ESRGAN. Затем плитки объединяются в окончательное изображение с высоким разрешением. Это приложение требует поддержки Vulkan или OpenCL и Android 7 или выше.

SuperImage на GitHub: https://github.com/Lucchetto/SuperImage
Платформа: Android
⭐️: 486
👍3
Forwarded 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>".
#aht
🤔6👍3👎1
Обычно мы на всех проектах добавляем тип сборки QA. Это такая сборка, которая максимально близка к релизной, но может включать в себя дебаг-панель и позволяет подключиться к приложению через дебаггер.
И вот недавно оказалось, что схема не работает. QA сборки не обфусцируются, а значит не сильно отличаются от дебажных. Причём не понятно в какой момент отвалилась обфускация и из-за чего это произошло.
Расследование привело к багтреккеру гугла: "AGP 7.2.0 onwards does not obfuscate our built app" и issue закрыто как Won't fix (Intended behavior) 🙂

Дело в том, что флаг isDebuggable = true теперь отключает обфускацию и по задумке инженеров гугла так должно было работать всегда. Ведь вы не сможете бегать по коду дебаггером, если он отличается от исходников, какой же это тогда получается debuggable? То что раньше была возможна обфускация с isDebuggable = true это изначально ошибочное поведение и AGP никогда не должен был так работать. Видимо ошибка показалась настолько очевидной, что фикс даже не упомянули в release notes, а как известно every change breaks someones workflow, что и случилось.

Решение подсказали там же в issue. Новый API, добавленный в AGP 7.0 4.2 позволяет вклиниться в процесс подготовки артефактов сборки. Можно подменять, добавлять и изменять промежуточные файлы, например: манифест, APK и даже использовать совсем чёрную магию — модифицировать уже скомпилированные классы. Хотелось когда-нибудь модифицировать один класс в библиотеке, чтобы не ждать исправления бага?
Но сейчас не об этом. Нам интересен манифест. С помощью этого API мы можем дописать любой текст в смердженный манифест, в частности и флаг debuggable.

👨‍🦽 Результат можно увидеть в фиксе для gradle-infrastructure или в отдельном сниппете.

P.S. Помимо флага в манифесте приходится ещё руками менять значение BuildConfig.DEBUG ведь он тоже зависит от isDebuggable.

#agp #snippet
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2🤔2
Forwarded 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.
👍4🔥2👎1
Forwarded 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. В противном случае кодогенератор начинает чудить и падать.
👍3🔥2🤯2
Насмотренность — важный навык в работе дизайнера. Это то что помогает быть в тренде, учиться на чужом опыте, черпать вдохновение, отличать хороший дизайн от плохого, критически оценивать свою работу и так далее. Нет вы не ошиблись каналом, просто я считаю, что насмотренность важна и разработчикам. Чем больше чужого кода смотришь — тем лучше пишешь свой. Просто потому что больше новых приёмов и концепций узнаёшь, улучшаешь свой скилл владения языком. С хэштегом #насмотренность буду писать про всё интересное на что наткнулся при просмотре 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>
🔥7👍2🤔2
Forwarded from Mobile Native ️️
10 Useful Kotlin Extension Functions for Android Developer

Еще один большой набор полезных Kotlin Extension функций для удобного использования.

👉 Print to Logcat
👉 View Visibility
👉 Toast Message
👉 Snackbar Message
👉 Hide Keyboard
👉 dp and px conversion
👉 Digit, Alphabetic, and Alphanumeric Check
👉 isNull, ifNull
👉 Date Formatter

Читать (En)
🔥3👍21
Forwarded from Записки разработчицы (Anna Zharkova)
Врываемся с хорошими новостями в эту пятницу. Открыт для обсуждения proposal о внесении статиков в Kotlin
https://github.com/Kotlin/KEEP/issues/348
👍1🤔1
Forwarded from Kotlin Multiplatform (Kostya)
https://medium.com/@bchoi000/sunflower-flavor-kmm-get-started-with-kotlin-multiplatform-mobile-9dc014c45b95

Все, наверное, видели официальное приложение гугла Android Sunflower with Compose, которое демонстрирует лучшие практики в разработке приложений под Андроид, по мнению гугл! 🙌
Так вот, Ethan Choi взял и по шагам перевел приложение на Kotlin Multiplatform и реализовал нативный UI на iOS. 🤩
Очень круто! 🥳
👍2🔥2
Forwarded from Mobile Native ️️
Easy caching Android + Kotlin + Flow

Статья с примером организации кеширования (Cached Source) с разными опциями(NEVER, IF_FAILED, IF_HAVE, ONLY, CACHED THEN LOAD) в связке Kotlin + Coroutines + Flow.

Пример кода на GitHub → Universal Cache

Читать (En)
🔥6👍2
Forwarded from red_mad_dev
・Senior iOS-разработчик red_mad_robot Аня Кочешкова рассказала, чем отличаются три менеджера зависимостей, в каких случаях и для каких задач подойдёт тот или иной. Аня подробно объяснила, что такое семантическое версионирование, как устроены модули кода и в чём разница между динамическими и статическими библиотеками. Материал будет полезен джунам, которые только начали погружаться в разработку.

・Head of Android red_mad_robot Central Asia Влад Бауэр поделился опытом, как решил нехватку iOS-разработчиков на одном из внутренних проектов. Он придумал решение: пошарил часть кода и перенёс его в Kotlin Multiplatform Mobile. Спойлер: у Влада получилось, и теперь он рассказывает о нюансах, с которыми ему пришлось столкнуться.

#ios #android #kotlin
👍2🔥2
Forwarded from Android Broadcast (Кирилл Розов)
Инструкция по реализации собственного виджета для выбора времени (Time Picker) на Jetpack Compose

#compose
👍3🔥2😱1