Kotlin Adept Notes
1.98K subscribers
67 photos
10 videos
114 links
Канал о разработке на Kotlin и обо всем, что с ним связано
По всем вопросам и рекламе: @ajiekcx
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
Попалась интересная статья (EN, 7 мин) о том как перевести такой красивый интерфейс с Jetpack Compose на Compose Multiplatform и запустить его на iOS.

Помимо переноса кода в commonMain сорсет, переработки gradle скриптов, необходимо сделать следующее:

Адаптировать ресурсы иконок, избавиться от ссылок на Android
Изменить способ работы со шрифтами для iOS
Убрать из общего кода все обращения к java классам, например к TimeUnit
Не использовать native canvas
Вынести реализацию BackHandler для разных сорсетов, поддержать обработку жестов в iOS

Исходный код примера можно посмотреть здесь
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Как опубликовать приложение с VPN в Google Play

Казалось бы, что может сложного опубликовать приложение с VPN в магазины приложений, но наш релиз в Google Play буквально задержался на год (штука про прошлогодний хлеб 😆)

Итак в чем суть, Google Play летом 2022 года ужесточили правила публикации приложений, использующих VpnService. Теперь VPN туннель могут создавать только те приложения, в которых VPN является основной функциональностью, но есть ещё несколько разрешенных кейсов.

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

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

Мы осознали свою ошибку:
🔵Заполнили информацию по использованию VpnService
🔵Записали shorts на YouTube, как использовать VPN
🔵Написали подробную инструкцию о том как включить VPN и для чего это нужно

Однако это никак не помогло и мы снова получили реджект с тем же пояснением 🤨:

We are unable to confirm your app's declared use of VpnService as a permitted use case


Мы подумали, что неправильно выбрали разрешенный кейс использования VPN и попробовали ещё пару раз пройти ревью, но результат не изменился.

Тогда пришлось прибегнуть к апелляции и узнать, что же от нас хотят, но какого было наше удивление, когда и на апелляции нам ответили то же самое 😭

Мы начали искать похожие кейсы в интернете, спрашивать в чатах разработчиков, но это никак не помогло и когда мы уже почти сдались и хотели выпилить VPN для сборки в Google Play, случилось чудо и нам ещё раз ответили по апелляции и сказали, что все с нашим кейсом окей, с одним НО.

‼️Нужно было указать в описании на странице приложения, что в нем есть VPN и пояснить для чего он нужен.

Это было супер очевидное решение проблемы, но почему-то мы до него не дошли раньше из-за невнятных сообщений от ревьюверов.

В итоге нам удалось успешно пройти ревью, но из-за такой вот мелочи пришлось потратить уйму времени.

⭐️Так что помните, если столкнетесь с подобной проблемой, что описание приложения тоже важно и не нужно пренебрегать его заполнением при обновлениях функциональности.

Спасибо, что дочитали до конца, всем удачных и быстрых ревью 🥂
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥185👏2
Как пошарить версии библиотек между проектами

Думаю вы знаете про достаточно новую фичу Gradle под названием Version Catalog. С помощью этого каталога можно шарить одни и те же версии библиотек между модулями в проекте, причем обновление этих версий не инвалидирует весь кеш сборки, как это было ранее с выносом библиотек в buildSrc папку, поэтому на сегодняшний день использование Version Catalog является рекомендуемым подходом.

Но как пошарить один и тот же каталог между разными проектами, которые находятся в разных репозиториях?

😐 Первое, что приходит на ум — это вынести единый .toml файл и подключать его через git submodule, но это не самое лучшее решение, так как уже недостаточно будет просто склонировать репозиторий проекта, и при этом придется внимательно следить за синхронизацией git модулей.

🙂 Гораздо лучше будет создать свой Gradle плагин, в котором будут описаны версии ваших библиотек, и затем нужно просто опубликовать и подключить его в другие проекты. Делается это гораздо проще, чем звучит! В статье (EN, 5 мин) подробно описано, как это сделать.

Но отсюда возникают другие проблемы:
1️⃣Нельзя по клику перейти в .toml файл, как это было раньше
2️⃣Новые версии библиотеки не будут подсвечиваться в студии

С первой проблемой особо ничего не поделать без написания IDEA плагина, а вот для проверки новых версий можно воспользоваться следующим плагином. Но обратите внимание, что обновления не будут автоматически проверяться у всех зависимостей, что указаны в каталоге версий, а только у тех, что подключены в gradle файле!

💬А как вы шарите общие версии библиотек между проектами?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🆒1
Наткнулся на статью "38 ошибок в Compose" и возникло строгое ощущение, что статью писало ChatGPT, ибо ошибок и неточностей там огромное количество, даже начиная с самых первых пунктов.

1. Нам предлагают написать такой код заместо обычной лямбды:


@Composable
fun MyComponent() {
var counter by remember { mutableStateOf(0) }
val clickAction = rememberUpdatedState { counter++ }

Button(onClick = { clickAction.value.invoke() }) {
Text("Clicked $counter times")
}
}


При том, что rememberUpdatedState в целом используется для другого, в примере с обычной лямбдой было бы все окей, так как Compose умеет мемоизировать лямбды со стабильным типами.

В большинстве случаев вам не нужно ничего оптимизировать – это задача команды Compose. Но если все же нужно:
🔵оберните лямбды с нестабильными типами в remember
🔵передавайте часто меняющиеся параметры как Sate или лямбду

2. Далее нам предлагают заменить вложенные layout на Box или ConstraintLayout 🤡

Тут даже комментировать не хочется, ибо в Compose есть правило одного прохода, вьюшки не меряются два раза, соответственно проблем с производительностью не будет.

Разумеется, это не все проблемы в статье, так что не верьте всему, что написано в интернете (мне тоже), а лучше читайте официальную документацию🗿
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥5🤔1🗿1
В этом году я стал одним из членов программного комитета на конференции Podlodka Android Crew.

Мы сейчас готовим 11 сезон и у нас уже есть три крутых потенциальных темы сезона:
🎨 Оптимизация UI
📈 Карьера разработчика
⚙️ Инструменты Android разработчика

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

⚙️Если у вас есть вопросы по конференции, то смело пишите в комментарии
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16
Коллега из сообщества (Максим Казанцев) опубликовал в публичный доступ 6 видео из своего курса по Kotlin Multiplatform.

🔸О курсе и знакомство с автором
🔸Инициализация проекта на KMP
🔸Задачи в Gradle
🔸Подключение Desktop + Compose
🔸Добавление Android модуля
🔸Подключение iOS таргета

Курс рассчитан на разработчиков от Junior+ и выше. Поэтому если вы не работали с KMP, или создавали проект с помощью визарда, но не совсем понимали как это сделать самостоятельно, то этот курс определенно для вас!

Приятного просмотра🤔
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18🙏6👨‍💻4🤝31
Давно на этом канале не было постов, но я пришел к вам с двумя хорошими новостями:

1️⃣ Я за это время сделал один интересный доклад про привычки Android разработки, которые мешают адаптировать приложение под KMP и скоро опубликуем его в открытый доступ, так что stay tuned

2️⃣ А также мы с командой подготовили новый 11 сезон Podlodka Android Crew с темой "Оптимизация UI".

Мы старались найти классных спикеров, помочь им с подготовкой и сезон получился довольно насыщенный:
🔹 Послушаем как продавать производительность бизнесу
🔹 Узнаем как работать с такими инструментами как Perfetto, JankStats и Jetpack Macrobenchmark
🔹 Увидим на примере как оптимизировать приложение на Jetpack Compose
🔹 А также поболеем за участников баттла и сами поучаствуем в квизе по производительности UI.

Конференция стартует уже 25 марта, так что присоединяйтесь, будет круто, все подробности на сайте.

🎁Ну и куда же без розыгрыша? Давайте разыграем одну проходку на Android Crew, единственное условие – быть подписанными на этот telegram канал @kotlin_adept.

Для участия в розыгрыше достаточно нажать на кнопку «Принять участие» под следующим постом и мы определим победителя рандомно уже в это воскресенье, удачи🤝
Please open Telegram to view this post
VIEW IN TELEGRAM
7🔥2
Розыгрыш проходки на 11 сезон конференции Podlodka Android Crew
Kotlin Adept Notes
Розыгрыш проходки на 11 сезон конференции Podlodka Android Crew
🎉 Результаты розыгрыша:

Победитель:
1. Дмитрий (@pervov_dmitry)

Проверить результаты
🔥1
Kotlin Adept Notes
Розыгрыш проходки на 11 сезон конференции Podlodka Android Crew
Выбор дополнительных победителей (в количестве 1):

Победитель:
1. Mikhail (@zykloned)

Проверить результаты
🔥2
Кастомные маски для TextField в Compose

Раньше в Android View реализовать маску для номера телефона, не говоря уже про что-то кастомное было далеко не самой простой задачей и люди, чтобы облегчить себе жизнь, использовали сторонние библиотеки, такие как Decoro.

Но теперь с приходом Compose надобность в сторонних решениях практически отпала, ведь реализовать кастомную маску для TextField можно буквально в 40 строк кода 😱, и это возможно благодаря продуманному и простому API интерфейса VisualTransformation.

Фишка в том, что VisualTransformation, как бы это неожиданно не звучало, влияет всего лишь на визуальное отображение, а не реальное значение поля, и, чтобы реализовать любую маску, достаточно сделать две вещи:

🔸Определить как исходный текст будет трансформироваться в текст с маской

var out = ""
text.text.forEachIndexed { index, char ->
when (index) {
2 -> out += "/$char"
4 -> out += "/$char"
else -> out += char
}
}


🔸Предоставить двухсторонний маппинг для правильного смещения курсора в поле ввода

val numberOffsetTranslator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
if (offset <= 2) return offset
if (offset <= 4) return offset + 1
return offset + 2
}

override fun transformedToOriginal(offset: Int): Int {
if (offset <= 2) return offset
if (offset <= 5) return offset - 1
return offset - 2
}
}


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

#Compose
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍41😁1
Forwarded from Android Broadcast
Media is too big
VIEW IN TELEGRAM
Немультиплатформенные привычки Android-разработки

Алексей Панов делится тем, как Android разработчику начать писать на Kotlin Multiplatform и отучиться от платформенных привычек

2:46 KMP Стек технологий
11:32 Переход с Java API
18:01 Переход с Android API
29:03 Использование Compose
36:07 Итоговые советы

Смотрите разбор на разных площадках:
👉YouTube
👉VK Video
👉Дзен

#AndroidBroadcast #кодинг
10🔥9👍51
ViewModel в KMP

Еще не так давно считалось, что ViewModel — это только Android only история и использовать ее в общем коде в мультиплатформе не получится, но в мире KMP все меняется очень быстро:
😀Google переписали ViewModel на Kotlin и адаптировали ее lifecycle под мультиплатформу
😀JetBrains сделали ее полностью мультиплатформенной, заодно адаптировав и компоузовскую навигацию

Из нюансов, нужно явно создавать инстанс ViewModel, даже с пустым конструктором! Но при этом сохранилась поддержка savedStateHandle.


@Composable
fun MyScreen(viewModel: MyViewModel = viewModel { MyViewModel(createSavedStateHandle()) }) {
...
}


Эти изменения безусловно положительно повлияют на популяризацию KMP, такими темпами скоро достаточно будет просто перенести весь код Android приложения в папку commonMain, адаптировать gradle скрипты и можно запускать приложение на любой платформе. Звучит круто, не правда ли! 👌

Но все же я не рекомендую продолжать использовать ViewModel напрямую, а думать о ней как о контейнере! Например, так реализован InstanceKeeper в Essenty.

Это дает несколько плюсов:
😀Вы можете сами управлять ЖЦ вашего компонента с логикой, делать его как синглтон, инжектить друг в друга, а не привязывать его только к ЖЦ ViewModel
😀Вы облегчаете внедрение зависимостей, так как по сути вы создаете обычный класс

Если все равно непонятно о чем речь, то советую прочитать эту статью, где подробно рассмотрена эта концепция.

А что вы думаете об использовании ViewModel в KMP
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16
Сегодня буду выступать на митапе от Usetech. Буду рассказывать обновленную версию своего доклада, ведь с тех пор картина сильно поменялась, теперь Room, ViewModel, Jetpack Navigation Compose уже можно использовать в KMP. Так что грань между Android и мультиплатформенной разработкой все больше стирается.

Поэтому если не смотрели доклад или хотите узнать, что поменялось и задать вопросы, то приходите сегодня в 15:00 мск на прямую трансляцию.

Также, помимо меня, на митапе выступят Анна Жаркова с докладом про SwiftUI и Евгений Сатуров с докладом про Flutter.

Регистрируйтесь по ссылке и до встречи🤝
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15❤‍🔥1
🟥Наконец-то опубликовали мой доклад с осеннего Mobius.

В докладе много всего интересного про подкапотную магию работы Compose, а именно:

🟢Поговорим про устройство снапшотов и узнаем причем здесь базы данных
🔵Разберемся как сделать свой стейт на основе снапшотов
🟣Рассмотрим как происходит чтение и запись, как снапшоты изолируются друг от друга
🔵А также ответим на вопрос, как при изменении стейта происходит рекомпозиция функций

Приятного просмотра😉
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥303🎉3🦄3
Также Mobius опубликовали наш совместный с Дмитрием Григорьевым квиз по Compose🎨

Квиз состоит из 4 блоков:
🟡Разминочные вопросы
🔵Вопросы по модификаторам
🟠Вопросы по рекомпозиции
🔵Хардкорные вопросы про подкапотную магию Compose

Так что, если не смотрели, то проверьте свои знания по Compose и напишите в комментариях на сколько вопросов  удалось ответить правильно и какой вопрос показался самым сложным🤔
Please open Telegram to view this post
VIEW IN TELEGRAM
7🔥3👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Коллега из Контура, Евгений Мельцайкин, написал статью о том, как сделать такую кнопку с помощью кастомного Layout в Compose и как оптимизировать ее, чтобы достичь минимального количества рекомпозиций. Приятного чтения 📕

Исходный код можно посмотреть здесь🐱

А вы сможете на взгляд определить какая кнопка сделана оптимально по количеству рекомпозиций?

#Compose
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥37👍2
Обзор Mobius 2024 Spring

Прошла очередная конференция Mobius и в этот раз я даже посмотрел больше двух докладов, так как фармить мерч удаленно не получается😒
И в целом сезон получился довольно интересным с хорошими и полезными докладами.

Вот мой личный топ:

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

Для нас сейчас это довольно актуальная тема, у нас уже был первый подход к скриншот тестированию, но мы также наткнулись на проблемы и нам ещё предстоит их преодолеть.

🔸Единая авторизация Ozon ID. Довольно лёгкий и менее технический доклад про способы авторизации, про часть из которых я узнал из доклада и выглядят они действительно интересно.

🔵Бессмертное приложение. Скорее не доклад, а больше справочник по разным лайфхакам как продлить время жизни приложения в фоне и пережить force stop, которые вы вряд ли найдете на StackOverflow.

🔹Как избавиться от рекурсии. Хардкорный, но интересный доклад про различные способы оптимизации рекурсии.

Так что, советую посмотреть эти доклады в записи, но если у вас нет билета на Mobius, то пишите в комментарии какую тему хотелось бы осветить и я напишу пост про самые важные инсайты из докладов 💻
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👏8👍3🤩2
Скриншот-тестирование

Практика скриншот-тестирования в Android началась еще более 10 лет назад и актуальна по сей день, за это время появилось огромное количество разных библиотек (Paparazzi, Shot, Testify и другие), но у всех библиотек есть существенный недостаток — поддержка. Всегда есть риски, что библиотеку перестанут поддерживать или будут обновлять зависимости несвоевременно.

И ребята из Тинькофф для тестирования дизайн-системы пошли другим путем, не используя сторонние библиотеки, так как все, что нужно для скриншот-тестирования уже есть в Android! (на самом деле нет)

Достаточно взять эталонный и текущий скриншот, сконвертировать все в Bitmap и попарно сравнить пиксели:


val referenceBitmap = BitmapFactory.decodeFile("assets/1.jpg")
val actualBitmap = onView(withId(R.id.mainContent)).captureToBitmap()
val isSameImage = compareBitmaps(referenceBitmap, actualBitmap)
assertTrue(isSameImage)


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

И вот список рекомендаций из их доклада про что нужно помнить:
▫️Подготовьте storybook и используете эти же состояния компонентов для тестирования
▫️Сделайте удобный тулинг для обновления эталонных скриншотов и просмотра диффа скриншотов
▫️Используйте CI как единый источник правды для создания эталонных скриншотов, так как на разных процессорах графика может отличаться
▫️Избавляйтесь от запуска тестов на эмуляторе, в этом может Robolectric с режимом @GraphicsMode(NATIVE)
▫️Подумайте о генерации тестов через KSP

Но, что если ваш проект полностью написан на Jetpack Compose? Неужели нет других вариантов скриншот-тестирования? Об этом расскажу в следующем посте, так что stay tuned!

#Testing #SnapshotTesting #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍21
Скриншот-тестирование в Compose

Google не так давно выкатили свой тулинг для скриншот-тестирования в Compose в экспериментальном режиме и работает он на основе Compose Preview 👀

У меня довольно скпептическое отношение к превью, за все время работы с Compose у меня постоянно были какие-то проблемы с этим механизмом, а с приходом Compose Multiplatform заставить превьюшки работать тот ещё челлендж, более менее дела с превью обстоят только в новой IDE Fleet, но там ещё ворох других проблем.

Так вот, вернёмся к тестированию, я попробовал этот способ и что могу сказать по текущему состоянию тулинга:

👍Официальное решение для скриншот-тестирования
👍Генерация отчёта с диффом изображений
👍Уже относительно работает и можно использовать на свой страх и риск
👍Тесты прогоняются без эмулятора и соответственно прогоняются быстро

👎Названия сгенерированных скриншотов нельзя поменять
👎Нельзя выборочно обновить эталонный скриншот
👎Нужно использовать специальные gradle таски для валидации скриншотов, потребуются доработки на CI
👎Нельзя настроить минимальный порог отличий между скриншотами
👎Только для Android

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

#Compose #SnapshotTesting
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍8