Forwarded from RutheniumOS
Список ресурсов по безопасности Android
GitHub
GitHub - ashishb/android-security-awesome: A collection of android security related resources
A collection of android security related resources - ashishb/android-security-awesome
👍4🤔1
Forwarded from AppFiles - Mobile Development
AboutLibraries автоматически собирает все зависимости и лицензии Gradle-проекта и предоставляет легко интегрируемые UI-компоненты для сред Android и Compose. Делает это во время компиляции и предлагает простые API для их визуализации в приложении. Никаких накладных расходов во время выполнения. Сильное кэширование. Поддерживаются любые gradle-зависимости. Поддерживает Kotlin Multiplatform.
AboutLibraries на GitHub: https://github.com/mikepenz/AboutLibraries
Платформа: Android
⭐️: 3.5K
AboutLibraries на GitHub: https://github.com/mikepenz/AboutLibraries
Платформа: Android
⭐️: 3.5K
👍3🔥2
Forwarded from Ra'Reilly - Заметки про Ktor и не только (Osip Fatkullin)
Продолжаю рубрику #насмотренность. Сегодня смотрим на inline-классы. На мой взгляд это одна из самый недооценённых фичей Котлина. Подозреваю, что это потому что потребность в inline-классах неочевидна. Попробую это исправить.
Напомню. Inline-класс это обёртка над другим типом. Он должен иметь строго один параметр в основном конструкторе — значение которое мы оборачиваем. При компиляции вместо нашего класса будет подставлено обёрнутое значение. То есть класс есть, а лишних аллокаций нет. Красота!
Минутка духоты: На самом деле обёрнутое значение не всегда будет инлайниться. Принцип работы похож на (un)boxing примитивов. Но это тема для отдельного поста.
1️⃣ Объявление собственных примитивов
Примитивные типы это то, что должно работать быстро. Мы ожидаем, что примитивы передаются по значению, то есть для них не создаётся объект в куче. Звучит как работа для inline-класса, ведь если в него завернуть примитив, то и перформанс получим как у примитива.
За примером далеко ходить не надо — UInt и другие беззнаковые типы в Kotlin это inline-классы. Но вот где действительно разгулялись с примитивами, так это в Jetpack Compose. Цвета раньше передавались либо как
2️⃣ Дешевые enum'ы
Помните совет гугла заменять enum'ы на
Так вот если всё-таки нужно заменить enum на примитив, inline-классы помогут обойтись без сомнительных конструкций с
Примеры этого подхода, опять же, можно посмотреть в Compose: TextAlign , TextOverflow и LineBreak. Да, к сожалению, при таком подходе в
3️⃣ Обёртки
Наиболее частое применение inline-классов — создание обёрток над другими типами, чтобы:
👉 Получить более строгую типизацию. Например, чтобы не ошибиться когда у нас много ID-шников одинакового типа у разных сущностей. Или более явно указать в сигнатуре функции, что "этот параметр должен быть не какой угодно строкой, а именно номером телефона". Это работает благодаря важному свойству inline-классов, что их нельзя сравнивать с другими типами. Попытка такого сравнения выкинет ошибку на этапе компиляции.
👉 Сузить скоуп для утилитарных функций. Вот есть у нас номер карты пользователя в формате строки. Мы хотим делать с этим номером много всякого: форматировать группами по 4 цифры, вывести маскированный номер карты вида
👉 Добавить новые свойства обёртнутой сущности. Добавить
Напоследок пример где и типизация важна, и новые свойства добавляются. Помните как в onMeasure нам прилетают Int'ы, с которыми нужно работать исключительно через утилитарный класс MeasureSpec? В Compose вместо этого прилетает один класс Constraints и мы сразу, без похода в документацию, понимаем набор действий, который можно совершать с этим классом. Ну не красота ли?
Напомню. Inline-класс это обёртка над другим типом. Он должен иметь строго один параметр в основном конструкторе — значение которое мы оборачиваем. При компиляции вместо нашего класса будет подставлено обёрнутое значение. То есть класс есть, а лишних аллокаций нет. Красота!
Минутка духоты: На самом деле обёрнутое значение не всегда будет инлайниться. Принцип работы похож на (un)boxing примитивов. Но это тема для отдельного поста.
1️⃣ Объявление собственных примитивов
Примитивные типы это то, что должно работать быстро. Мы ожидаем, что примитивы передаются по значению, то есть для них не создаётся объект в куче. Звучит как работа для inline-класса, ведь если в него завернуть примитив, то и перформанс получим как у примитива.
За примером далеко ходить не надо — UInt и другие беззнаковые типы в Kotlin это inline-классы. Но вот где действительно разгулялись с примитивами, так это в Jetpack Compose. Цвета раньше передавались либо как
Int в формате 0xAARRGGBB, либо как класс, теперь же Color это inline-class. Получаем все удобства класса и легковесность примитива. Кроме цветов есть ещё Dp, Size, Offset и т.д. (для типов, состоящих их нескольких свойств, например Size, под капотом используется упаковка данных в один примитив). Так что, если вас как и меня мучил вопрос почему нет ничего страшного в том, что мы на каждой рекомпозиции создаём объекты, это потому что на самом деле никаких объектов нет.2️⃣ Дешевые enum'ы
Помните совет гугла заменять enum'ы на
Int с аннотацией @IntDef? Потом Jake Wharton рассказал, что R8 умеет оптимизировать enum'ы и мы выдохнули.Так вот если всё-таки нужно заменить enum на примитив, inline-классы помогут обойтись без сомнительных конструкций с
@IntDef, которые опираются только на стат. анализ.Примеры этого подхода, опять же, можно посмотреть в Compose: TextAlign , TextOverflow и LineBreak. Да, к сожалению, при таком подходе в
when нет проверки, что покрыты все ветви, но на этот компромисс я готов пойти.3️⃣ Обёртки
Наиболее частое применение inline-классов — создание обёрток над другими типами, чтобы:
👉 Получить более строгую типизацию. Например, чтобы не ошибиться когда у нас много ID-шников одинакового типа у разных сущностей. Или более явно указать в сигнатуре функции, что "этот параметр должен быть не какой угодно строкой, а именно номером телефона". Это работает благодаря важному свойству inline-классов, что их нельзя сравнивать с другими типами. Попытка такого сравнения выкинет ошибку на этапе компиляции.
👉 Сузить скоуп для утилитарных функций. Вот есть у нас номер карты пользователя в формате строки. Мы хотим делать с этим номером много всякого: форматировать группами по 4 цифры, вывести маскированный номер карты вида
*1234 и т.д. Можно сделать кучу экстеншенов на String, которые будут видны когда нужно и когда не нужно, а можно завести inline-класс и явно определить что с ним можно делать.👉 Добавить новые свойства обёртнутой сущности. Добавить
@Immutable ко спискам? Запросто. Напоследок пример где и типизация важна, и новые свойства добавляются. Помните как в onMeasure нам прилетают Int'ы, с которыми нужно работать исключительно через утилитарный класс MeasureSpec? В Compose вместо этого прилетает один класс Constraints и мы сразу, без похода в документацию, понимаем набор действий, который можно совершать с этим классом. Ну не красота ли?
👍7🔥4🤔2
Forwarded from Mobile AppSec World (Yury Shabalin)
Make drozer great again
Не могу пройти мимо этой новости, спустя 7 долгих лет произошло обновление любимого многими инструмента drozer
Теперь он поддерживает python3! И очень надеюсь на добавление нового функционала.
Плюс, авторы обновили и репо с уязвимым приложением, которое показывает основные уязвимости Android приложений.
Ну и небольшое прохождение, которое показывает возможности drozer.
Пока что не поддерживается запуск на Windows и есть определенные проблемы со стабильностью в ряде случаев, но все равно это по настоящему возрождение легенды :)
#drozer #android
Не могу пройти мимо этой новости, спустя 7 долгих лет произошло обновление любимого многими инструмента drozer
Теперь он поддерживает python3! И очень надеюсь на добавление нового функционала.
Плюс, авторы обновили и репо с уязвимым приложением, которое показывает основные уязвимости Android приложений.
Ну и небольшое прохождение, которое показывает возможности drozer.
Пока что не поддерживается запуск на Windows и есть определенные проблемы со стабильностью в ряде случаев, но все равно это по настоящему возрождение легенды :)
#drozer #android
GitHub
GitHub - ReversecLabs/drozer: The Leading Security Assessment Framework for Android.
The Leading Security Assessment Framework for Android. - ReversecLabs/drozer
👍3🔥1💩1
Forwarded from Mobile Developer (Алексей Гладков)
Как избавиться от лишнего кода в build.gradle [EN]
https://proandroiddev.com/how-to-get-rid-of-boilerplate-code-in-build-gradle-files-7bfac83ca1c8
👉 Что можно вынести в settings.gradle
👉 Как написать convention plugin
👉 Практический совет на примере
https://proandroiddev.com/how-to-get-rid-of-boilerplate-code-in-build-gradle-files-7bfac83ca1c8
👉 Что можно вынести в settings.gradle
👉 Как написать convention plugin
👉 Практический совет на примере
Medium
How to get rid of boilerplate code in build.gradle files?
In this article I’d like to describe how you can get rid of boilerplate code in your build.gradle files in multimodule project with the…
👍1🔥1
Forwarded from Ra'Reilly - Заметки про Ktor и не только (Osip Fatkullin)
Хабр
Конструкторы-самозванцы в Kotlin
Сегодня я хочу поговорить про интересные моменты в Kotlin, связанные с вызовами конструкторов классов. Или не совсем конструкторов? Или же совсем не конструкторов? Давайте разбираться. Это...
Я веду бэклог постов и в рубрике #насмотренность следующий пост должен был быть про функции-конструкторы. Но иногда нужно просто немного подождать и кто-то сделает все за тебя :) На хабре вышла статья "Конструкторы-самозванцы в Kotlin", где автор описывает варианты мимикрии функций под синтаксис конструктора и в каких случаях это может понадобиться. Спасибо ему! Мне остаётся только досыпать примеров использования в Open Source.
1️⃣ Функция-конструктор
Это просто функция высшего порядка, написаная с большой буквы, которая внутри создаёт и возвращает инстанс класса.
Полезно, если хочется дать возможность "создавать инстанс интерфейса". Объявляете интерфейс, кладёте рядом с ним функцию с таким же названием и готово, даже импортировать её отдельно не придётся. Реализация интерфейса при этом может остаться приватной. Вызовы MutableStateFlow и MutableSharedFlow в корутинах, Json в kotlinx.serialization это всё вызовы таких функций. Это помогает уменьшить API-surface, а значит упростить использование API.
Ещё один вариант использования — вместе с inline-классами. Например, у Size в Compose конструктор помечен как
2️⃣ Перегрузка Companion.invoke
Причины применения указанные в статье (контроль над созданием объекта, создание пула объектов, кэширование и т.д.) классные, но нужны примеры. Пример контроля над созданием объекта можно увидеть в PlatformVersion в ktor. То есть в зависимости от определённой логики мы можем мы либо создаём инстанс, либо возвращаем какой-то существующий.
Но часто применение более банальное — вместо вторичного конструктора. Тут я могу только догадываться почему не используется вторичный конструктор, но примеры такого применения можно увидеть в RuleSet из detekt и MockEngine из ktor. Иногда применение вместо вторичного конструктора можно оправдать тем, что логики для подготовки параметров конструктора очень много. Например в SpriteAnimation из korge (игровой движок на Kotlin).
3️⃣ <Context>.invoke()
То же самое, что предыдущий вариант, но для случая когда нужно ограничить применение invoke контекстом.
В дикой природе этот вариант я не встречал, но сам автор даёт пример применения в yatagan и рассказывает в статье зачем это понадобилось. После выхода context parameters (следующая итерация context receiver'ов) этот вариант будет выглядеть приятнее.
🤔 Как относиться к такому?
Я часто вижу хейт в сторону подобных конструкций, мол мимикрия и переопределение операторов это зло, так как порождает неявность. Да, на самом деле вызывается не конструктор, а функция, но что в этом плохого если она выполняет ту же смысловую нагрузку? Уверен, многие с чистой совестью вызывают
Накидайте аргументов если я не прав!
#kotlin
1️⃣ Функция-конструктор
Это просто функция высшего порядка, написаная с большой буквы, которая внутри создаёт и возвращает инстанс класса.
Полезно, если хочется дать возможность "создавать инстанс интерфейса". Объявляете интерфейс, кладёте рядом с ним функцию с таким же названием и готово, даже импортировать её отдельно не придётся. Реализация интерфейса при этом может остаться приватной. Вызовы MutableStateFlow и MutableSharedFlow в корутинах, Json в kotlinx.serialization это всё вызовы таких функций. Это помогает уменьшить API-surface, а значит упростить использование API.
Ещё один вариант использования — вместе с inline-классами. Например, у Size в Compose конструктор помечен как
internal, а "создание инстанса" происходит через функцию c двумя параметрами.2️⃣ Перегрузка Companion.invoke
Причины применения указанные в статье (контроль над созданием объекта, создание пула объектов, кэширование и т.д.) классные, но нужны примеры. Пример контроля над созданием объекта можно увидеть в PlatformVersion в ktor. То есть в зависимости от определённой логики мы можем мы либо создаём инстанс, либо возвращаем какой-то существующий.
Но часто применение более банальное — вместо вторичного конструктора. Тут я могу только догадываться почему не используется вторичный конструктор, но примеры такого применения можно увидеть в RuleSet из detekt и MockEngine из ktor. Иногда применение вместо вторичного конструктора можно оправдать тем, что логики для подготовки параметров конструктора очень много. Например в SpriteAnimation из korge (игровой движок на Kotlin).
3️⃣ <Context>.invoke()
То же самое, что предыдущий вариант, но для случая когда нужно ограничить применение invoke контекстом.
В дикой природе этот вариант я не встречал, но сам автор даёт пример применения в yatagan и рассказывает в статье зачем это понадобилось. После выхода context parameters (следующая итерация context receiver'ов) этот вариант будет выглядеть приятнее.
🤔 Как относиться к такому?
Я часто вижу хейт в сторону подобных конструкций, мол мимикрия и переопределение операторов это зло, так как порождает неявность. Да, на самом деле вызывается не конструктор, а функция, но что в этом плохого если она выполняет ту же смысловую нагрузку? Уверен, многие с чистой совестью вызывают
MutableStateFlow и им не важно, что под капотом. Главное следовать принципу наименьшего удивления. Если что-то выглядит как конструктор, оно и работать должно как конструктор.Накидайте аргументов если я не прав!
#kotlin
👍2🔥1
Forwarded from Полуночные Зарисовки
Telegraph
Безболезненное перемещение ресурсов в мире нетранзитивных R-классов
Недавно делал задачу, связанную с перемещением иконок в проекте между модулями, и готовлюсь к задаче с большим количеством перемещений других ресурсов. И вот я что-то не замечал до этого момента (или не придавал особого значения) того, что Android Studio…
🤔2👍1
Forwarded from Kotlin Multiplatform (Kostya)
https://github.com/ShreyashKore/wonderous_compose
Я уже упоминал этот проект как-то раз. Очень красиво и работает на всех возможных платформах! (не надо только пробовать веб версию на мобильных устройствах)
А теперь там появились встроенные карты на всех платформах - стоит изучить 😉
Я уже упоминал этот проект как-то раз. Очень красиво и работает на всех возможных платформах! (не надо только пробовать веб версию на мобильных устройствах)
А теперь там появились встроенные карты на всех платформах - стоит изучить 😉
❤3🔥3👍1
Forwarded from Mobile Compose
#Предложка #Libs #Compose
Compose Color Preview
Наверняка вы замечали, что при работе с Compose Multiplatform в IntelliJ IDEA нет привычных превью цветов в панели слева. Одним из решений этой проблемы является Compose Color Preview — плагин, автором которого является один из подписчиков канала. Однозначно лайк 👍
Compose Color Preview
Наверняка вы замечали, что при работе с Compose Multiplatform в IntelliJ IDEA нет привычных превью цветов в панели слева. Одним из решений этой проблемы является Compose Color Preview — плагин, автором которого является один из подписчиков канала. Однозначно лайк 👍
👍8🔥3
Forwarded from Kotlin Multiplatform (Kostya)
Хабр
Как новый компилятор K2 ускоряет компиляцию Kotlin на 94%
Привет, меня зовут Мялкин Максим, я занимаюсь мобильной разработкой в KTS. Не за горами выпуск новой версии Kotlin 2.0, основной частью которого является изменение компилятора на K2. По замерам...
👍1
Forwarded from Записки разработчицы (Anna Zharkova)
Для тех, кому лень или некогда смотреть, хорошая статья на Хабре: https://habr.com/ru/companies/kts/articles/814363/
Хабр
Developer Keynote Google I/O 2024: официальная поддержка KMP, развитие Gemini и AI в Андроиде
Всем привет! Меня зовут Мялкин Максим, я лид мобильной команды в KTS . Сейчас проходит Google IO 2024, и мы с ребятами в команде решили выпустить обзор треков, которые нам показались интересными. Мы...
🔥5👍1
Forwarded from Kotlin Multiplatform Broadcast
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16❤1
Forwarded from iOS Makes Me Hate (Lev Bondarenko)
Как решать задачи на литкод
Какое-то монументальное видео, где чувак 4,5 часа выдает базу. Супер нишевый видос, когда автор просто на своем желании сделал офигенную лекцию, уровня которой не найдешь на ютубе. А где-то даже заменит целые курсы по алгосам от яндекса и тп.
Разобрав такие острые вопросы:
🟣 чем отличаются problem solving skills от заучивания алгоритмов
🟣 какие алгоритмы нужны и как начать понимать их пользу
🟣 почему большинство ошибается насчет бесполезности алгоритмов
🟣 работа с когнитивными искажениями и ментальными барьерами
🟣 ментальная гигиена и как не выгореть от неудач
Я тоже уже замечаю как регулярные алго задачи меняют мой мозг. Я начинаю любить шахматы, чаще думаю перед действиями в жизни, не боюсь неудач. Как-нибудь напишу пост об этом.
Пожелайте счастья таким людям, кто просто делает крутой контент для себя. Очень вайбовый видос, который смотришь на одном дыхании.
Какое-то монументальное видео, где чувак 4,5 часа выдает базу. Супер нишевый видос, когда автор просто на своем желании сделал офигенную лекцию, уровня которой не найдешь на ютубе. А где-то даже заменит целые курсы по алгосам от яндекса и тп.
Разобрав такие острые вопросы:
Я тоже уже замечаю как регулярные алго задачи меняют мой мозг. Я начинаю любить шахматы, чаще думаю перед действиями в жизни, не боюсь неудач. Как-нибудь напишу пост об этом.
Пожелайте счастья таким людям, кто просто делает крутой контент для себя. Очень вайбовый видос, который смотришь на одном дыхании.
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
Как решать задачи на Leetcode(+полный гайд, работа, мотивация, депрессия, менталка, problem solving)
Telegram post: https://news.1rj.ru/str/koduryem/26
Problem solving skills. Скиллы и гайд для решения задач.
Всем привет! В этом видео будет про вообще все, что связано с решением задач - не только leetcode, но и в целом теория решения задач и в других областях, зачем…
Problem solving skills. Скиллы и гайд для решения задач.
Всем привет! В этом видео будет про вообще все, что связано с решением задач - не только leetcode, но и в целом теория решения задач и в других областях, зачем…
🔥6👍2
Forwarded from Mobile Developer (Алексей Гладков)
Coroutines Essentials [EN]
https://typealias.com/start/kotlin-coroutines/
Еще одна статья, которая разжевывает прям в мелочах, как именно работают корутины во всех деталях
👉 Что такое многопоточность
👉 Как корутины реализуют concurrency
👉 Внутренняя машинерия
👉 Реальные примеры
Все весело, задорно, с картинками и игровыми механиками. В общем, если после этого рассказа все еще не понятно что такое корутины, то в следующем посте я скину вакансии из Вкусно и точки
https://typealias.com/start/kotlin-coroutines/
Еще одна статья, которая разжевывает прям в мелочах, как именно работают корутины во всех деталях
👉 Что такое многопоточность
👉 Как корутины реализуют concurrency
👉 Внутренняя машинерия
👉 Реальные примеры
Все весело, задорно, с картинками и игровыми механиками. В общем, если после этого рассказа все еще не понятно что такое корутины, то в следующем посте я скину вакансии из Вкусно и точки
Dave Leeds on Kotlin
Coroutine Essentials
Discover the power of coroutines in Kotlin and learn how to make your applications perform tasks concurrently and in parallel. Join Rusty and his construction crew as they streamline construction projects – and see how you can apply these same techniques…
👍5🔥1
Forwarded from Mobile AppSec World (Yury Shabalin)
Небольшая статья, которая поможет разобраться в разнообразии *links в Android
Всем привет!
Давно меня не было слышно, очень-очень плотно работа забрала себе :D
Но все-таки, хочется немного порадовать себя и вас. Сегодня у нас вышла новая статья по механизмам работы WebLinks, AppLinks и DeepLinks в Android. Я очень часто их путал и до конца не понимал, а в чем же отличие одного механизма от другого.
И наконец-то, совместно с @veselinaz до конца разобрались, что это и с чем едят.
Ну и конечно, сложно было не попробовать что-то сломать и попробовать проверить разные теории, как обойти проверку по верефицированному домену. Не скажу, что у нас получилось, сломать мы так ничего и не смогли, зато написали небольшую статью, чтобы всегда можно было освежить память и вспомнить, чем каждый из механизмов отличается и как поведет себя Android в той или иной ситуации.
Очень надеюсь, вам понравится!
Приятного чтения!
Всем привет!
Давно меня не было слышно, очень-очень плотно работа забрала себе :D
Но все-таки, хочется немного порадовать себя и вас. Сегодня у нас вышла новая статья по механизмам работы WebLinks, AppLinks и DeepLinks в Android. Я очень часто их путал и до конца не понимал, а в чем же отличие одного механизма от другого.
И наконец-то, совместно с @veselinaz до конца разобрались, что это и с чем едят.
Ну и конечно, сложно было не попробовать что-то сломать и попробовать проверить разные теории, как обойти проверку по верефицированному домену. Не скажу, что у нас получилось, сломать мы так ничего и не смогли, зато написали небольшую статью, чтобы всегда можно было освежить память и вспомнить, чем каждый из механизмов отличается и как поведет себя Android в той или иной ситуации.
Очень надеюсь, вам понравится!
Приятного чтения!
Хабр
Такие разные Android AppLinks, WebLinks, DeepLinks. Разбираемся и пытаемся сломать
Введение Всем привет! На связи Юрий Шабалин и Веселина Зацепина ( @VeselinaZatsepina ) эксперты по безопасности мобильных приложений в компании Стингрей. С каждым годом...
Forwarded from Dolgo.polo Dev | Денис Долгополов
Собрал тут кажется самую большую коллекцию:
@dolgo_polo_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3❤2
Forwarded from Android Live 🤖
When и Guard Conditions
#kotlin
С релизом Kotlin 2.1.0 появился апдейт для when — guard conditions. Эта новая фича улучшает читаемость кода, делая его более наглядным.
Давайте рассмотрим на примере, что она делает.
Предположим, есть базовый класс для получения ответа от сервера:
Если включить Guard Conditions, то проверка в when специальных юзкейсов будет выглядеть так:
Как мы видим, одну ошибку от бэка мы обработали без добавления if внутри условия:
Похоже, что стало удобнее, но нужно попробовать на практике.
Чтобы включить фичу, надо убедиться, что K2 Compiler включен, а потом добавить опцию:
Чуть больше информации можно найти тут.
#kotlin
С релизом Kotlin 2.1.0 появился апдейт для when — guard conditions. Эта новая фича улучшает читаемость кода, делая его более наглядным.
Давайте рассмотрим на примере, что она делает.
Предположим, есть базовый класс для получения ответа от сервера:
sealed interface HttpResult {
data class Success(val response: String) : HttpResult
data class Failed(val statusCode: Int) : HttpResult
}
Если включить Guard Conditions, то проверка в when специальных юзкейсов будет выглядеть так:
when (response) {
is HttpResult.Success -> println("Success")
is HttpResult.Failed if response.statusCode == 503 -> println("Maintenance")
is HttpResult.Failed -> println("Failed with code ${response.statusCode}")
}
Как мы видим, одну ошибку от бэка мы обработали без добавления if внутри условия:
when (response) {
is HttpResult.Success -> println("Success")
is HttpResult.Failed -> {
if (response.statusCode == 503) {
println("Maintenance")
} else {
println("Failed with code ${response.statusCode}")
}
}
}
Похоже, что стало удобнее, но нужно попробовать на практике.
Чтобы включить фичу, надо убедиться, что K2 Compiler включен, а потом добавить опцию:
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xwhen-guards")
}
}
Чуть больше информации можно найти тут.
🔥7❤1