Мобильное Чтиво
1.6K subscribers
272 photos
43 videos
153 links
Очень серьезный канал про мобильную разработку. Веду канал я — @maxkachinkin
Download Telegram
📜 Ваш любимый логгер! 📜

Мы в своих Android-проектах давно логируем через SLF4J/Logback Android. Да, да, это тот самый проверенный временем логгер.

🎯 У него есть плюсы: Надежный (не считая истории с CVE-2023-6481, но там речь про классический, а не android), стабильный, с хорошей поддержкой форматов логирования. Работает без сюрпризов, настройки для форматирования и фильтрации логов. В общем по функционалу всё нравится.
Но есть главный минус: Увы, только для Android. Не подходит для KMP, да и по гибкости проигрывает более свежим решениям.

Я понимаю, что SLF4J/Logback — это не самый гибкий и современный подход, особенно если ваши проекты уже идут в стороны Kotlin Multiplatform.

А как у вас с логированием дела обстоят? 😎

- Logback Android, как у нас?
- Может быть Timber?
- Или уже думаете о будущем и логируете с помощью 🦸‍♂️Napier или 🐸Kermit?
- Или, может, у вас есть свой подход?

Поделитесь, очень интересно узнать! 👀

P.S. Не забывай! В закрепе БЕСПЛАТНЫЙ билет на 🟢Mobius🟢! 🎁 Успейте до четверга!

#android #kmp #logging
5🤓1
🔥 Топ ожидаемых докладов 🔥

Недавно я запустил конкурс на бесплатный билет на Mobius (у вас еще остался 1 день, завтра днем крутану рандомайзер 🎰), и я попросил написать, какие доклады вы ждете больше всего. Кто-то написал 1 доклад, кто-то несколько. Я учел и посчитал все упоминания.

🎤 И вот самые ожидаемые доклады по версии подписчиков Мобильное чтиво:

Первое место разделили:

🥇 Не два байта переслать: эмуляция бесконтактных карт на мобильных устройствах
Павел Васильев, Positive Technologies

🥇Что не так с мобильными сервисами в Android и iOS
Кирилл Розов, Android Broadcast

🥇Kotlin in GitHub Actions. Расширяем горизонты KMP
Максим Качинкин, Dodo Engineering
Эти доклады набрали по 5 голосов.

Могу предположить, что мой доклад упоминали, потому что я веду этот канал 😏. Поэтому вот доклады, которые на 2м месте — они набрали по 4 голоса. Тоже очень ожидаемые!

Второе место:

🥈 Compose и SwiftUI: найди 10 отличий
Алексей Панов, Контур

🥈 Опасности в Android: уязвимости и защитные меры
Юлия Стекачева, Райффайзен Банк

🥈 Предпринимательство для инженера: как запустить свою компанию
Евгений Мацюк, MarathonLabs

🥈 Суперапп с чистого листа
Сергей Балалаев, Ozon

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

Я жду вот эти 2:

🚀 Заезжаем в KMP. Но какой ценой?
Денис Александров, Яндекс 360

🚀 Последнее слово в Android-навигации
Данил Колесников, Дзен

#Mobius2024 #Android
5👍2🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
🔥15👍1😁1
🤣 Пятничный мем 🤣

Сегодня выступил на Mobius на online дне. Про само выступление напишу потом. Сегодня просто легкий пятничный пост.

Как я готовился к выступлению с визуальной части. Есть 3 момента:

- Мне нравится рассказывать стоя. Так я чувствую себя более динамично и бодро. 💪
- Хочется, чтобы фон был красивый. 🎨
- У меня нет стола с регулировкой высоты, поэтому приходится что-то придумывать. 🤔

Для этого я нашел стену, обустроил её как надо (бахнул на телек красивую картинку), а чтобы встать рядом с ней стоя, пришлось соорудить конструкцию из того, что попалось под руку (включая коробку из-под обуви). И, конечно, надо поставить кружку воды, мобилу и прочее. 📱☕️

И получился мем:
Frontend - Backend 😄

#mobius #meme #пятница
😁29🔥6👍4🤣41
📅 Как проходит мой рабочий день 🏃‍♂️

Вышла статья из рубрики “День с экспертом” на SkillFactory Media. Там я рассказываю про свой типичный рабочий день.

Из интересного и про мобильную разработку я рассказываю, что:
• у нас есть правило на короткие PRы 📝
• мы работаем по Trunk-Based Development 🌳
• я люблю парное программирование, но удается применять его редко 👨‍💻👩‍💻
• подставка под ноут — это маст 📦
• каждый день кормлю уличных котов 🙂

Заголовок и тон статьи может вызвать подозрение на тупые понты или что я собрался продавать мастер-классы “Эффективная эффективность: успевайте всё как я”. Знайте, такого намерения не было. 😅

💬 Мне интересно, а что у вас любимое в вашем рабочем дне? Или наоборот, что вас бесит?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥2🍌2😁1🙈1
🇦🇲 Увидимся на DevFest в Ереване 🇦🇲

В это воскресенье, 20 октября, в Ереване пройдет DevFest Armenia 2024!

Я буду выступать там (да, оффлайн) с докладом:
Compose as an Unbundled Library: What It Means for Your App.

Подписчики этого канала знают, что на эту тему я делал посты здесь и ни раз. Вот теперь расскажу целиком вслух:
🐣 Что значит unbundled library
📏 Как замерять UI перфоманс
⏱️ Как можно оптимизировать Compose, если все-таки столкнулись с долгой первой загрузкой

Если вдруг кто есть в Ереване, го на DevFest, пообщаемся!

#devfest #yerevan #compose
🔥122👍1
🎨 Зато Compose не скован версиями Android 🤖

Я пару раз уже писал на эту тему Compose как Unbundled Library. Сейчас напишу в последний раз (надеюсь 😅). Но теперь с конкретикой и расскажу, чем это хорошо или плохо.

В отличие от Compose, все классы View уже лежат в памяти нашего процесса еще до того, как вы вообще успели запустить приложение!

Когда же они туда попали? 🧠

Ответ — еще до старта вашего приложения! При инициализации процесса Zygote. 🧬

Есть такой файл, он называется preloaded-classes и лежит вот тут:
/system/etc/preloaded-classes.

В этом классе строчка за строчкой записаны все полные имена классов Android фреймворка. Их там больше 17k! Включая, конечно же, классы системы View! 📜

Потом в методе preloadClasses мы читаем этот файл, строчку за строчкой, и загружаем классы в память процесса!

Вот так! Еще до ващего Application::onCreate, до контент провайдеров, до того как ваш процесс форкнется от Zygote, в нем уже всё будет загружено!

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

Поэтому Compose не скован никакими версиями Android фреймворка. Мы не пишем с вами код, типа:
VERSION.SDK_INT >= VERSION_CODES.TIRAMISU

для компоуз кода.

Отвечая на вопрос чем это плохо 👎:
- Compose требует времени на загрузку в рантайме
Чем это хорошо 👍:
- Наконец-то есть гибкость и свобода!

💬 Вам нравится гибкость? Или вы бы предпочли предзагрузку вместе с Android фреймворком?

Кстати, на фото — это как раз я на DevFest Armenia на этих выходных, объясняю вот этот самый момент про Zygote и preloaded классы. 📸

#Compose #DevFest
👍27🔥153
This media is not supported in your browser
VIEW IN TELEGRAM
🚀 Как лучше работать с OTP?

Чтобы автоматически обрабатывать SMS, мы в Drinkit используем SMS Retriever API от Google.

Это популярный инструмент для такой задачи. Кто немного не знаком с ним я перечислю основные моменты:

1️⃣ Не нужны разрешения. Чтобы использовать это API, не нужно запрашивать у пользователя доступ к SMS. SmsRetriever даёт нам 5-минутное окно, в течение которого система ожидает входящее сообщение с кодом.

2️⃣ Безопасность. SMS Retriever API ожидает хеш приложения, который зашивается в SMS. Это значит, что у нашего приложения будет доступ только к “нашим” SMS-кам.

3️⃣ Удобство для пользователя. Если всё сделать, то код подтягивается автоматически, и пользователю не нужно вручную копировать его из сообщения. 👌 Прямо как на видео, смотрите!

Конечно, это не единственный способ. Есть и другие варианты:

- Использовать One-tap SMS verification API.
Там будет дополнительный Bottom Sheet с подтвеждением. Но, если честно, я такой встречаю крайне редко.
- Вообще не автоматизировать — пользователь сам вводит код. Периодически я встречаю такие приложения.
- BroadcastReceiver или Content Provider — старые подходы, которые требуют больше пермишенов и возни с кодом.

Однако, я заметил, что не все приложения используют SMS Retriever API. Например, видел что им пользуются Uber или Яндекс Такси. Но далеко не все приложения. 🤔 Интересно, почему?

А вы что используете для обработки OTP у себя? Делаете через SMS Retriever API или выбираете другой путь? Стоит ли мне подробнее расписть про SMS Retriever API? Делитесь в комментах! 😎

P.S. Мартышки, это не часть нашего UI, просто я скрыл номер телефона ☺️

#android #smsretriever #otp
👍24🤔21
🎃 Чего я боюсь 🎃

В Хеллоуин принято пугать друг друга, в шутку и не очень. Давайте поговорим о том, что нас пугает в разработке!

Вот мой топ 3 самых больших страха!

1️⃣ Случайно нажать Sync Projects With Gradle Files вместо нужной кнопки... и просто замереть в ужасе. 🧙‍♂️

2️⃣ Когда ты iOS-разработчик, а тебе говорят: "Сделай как на Android." 🧛‍♂️

3️⃣ Идешь читать доку "Migrate apps to Android 13/14/15" (подставь любую версию) 🕸️

Напишите в комментах, а какие у вас страхи? Если не боитесь! 👻
😁16👍2
This media is not supported in your browser
VIEW IN TELEGRAM
🇺🇸 Рисуем SVG в Compose Great Again

Сегодня расскажу, как можно нарисовать сложный рисунок в Compose, если у вас есть SVG файл. А именно как распарсить SVG файл в удобные для нас Path и отрисовать их “руками”.

🔍 Парсинг SVG: Мы загружаем SVG файл с помощью XmlPullParser, который читает каждый элемент. В каждом path элементе хранится информация о том, как рисовать фигуру — всё закодировано в атрибуте d. Этот атрибут содержит команды типа "M" (move to), "L" (line to), "C" (curve to) и координаты. Вместе они формируют контур, который и станет нашим рисунком.

🛠️ Конвертация Path: Здесь проблема. В Compose пока нет метода для декодирования пути напрямую из d атрибута SVG.

Но мы сделаем конвертацию Great Again! Мы сначала создаём старый добрый Path из androidx.core.graphics (через метод createPathFromPathData), а потом конвертируем его в Compose Path с помощью asComposePath. Немного костыльно, но работает.

Теперь, когда мы всё распарсили и конвертировали, можем просто отобразить это в Compose.

Я выложил пример на GitHub, где вы можете посмотреть, как это работает. В этом проекте пярмо то, что изображено на видосе, какая-то карта и какие-то непонятные области.

P.S. Да, нажатия сделаны не совсем идеально — попадание внутрь Path осуществляется по bounding box, а не точно по форме. Но это уже отдельная задача, а здесь у нас фокус на отрисовке! 😎

💬 А что интересного вы рисовали в Compose?

#compose #svg
🔥21😁7👍3
🚀 Используй ScatterMap, если ты помешан на производительности

Обожаю Romain Guy и его выступления. Недавно смотрел его видео Exploring Kotlin Performance на канале Code with the Italians 🎥

Он рассказывает, как писать код на Kotlin так, чтобы он был максимально производительным. Показывает во что компилируется Kotlin и анализирует это.

Мы можете мне возразить: зачем мне это? Ведь моё дело написать читаемый код, а дело разработчиков компиляторов сделать так, чтобы он работал быстро!

Но. Если вы хотите написать супер производительный UI и особенно на Compose, то тут каждая мелочь может иметь значение!

Я приведу один пример из видео: Map vs ScatterMap.

Если вы используете HashMap, то в скомпилированном коде будет много вызовов функций и аллокаций. И даже если GC у нас больше не в мейн треде, то лишние аллокации все равно не желательны для супер производительного UI. 🧹

Так вот, в таких случаях можно использовать ScatterMap. Эта штука ведет себя почти как Map, но работает с ключами по-другому и требует гораздо меньше аллокаций. Это значит, что производительность становится выше, особенно в UI-интенсивных задачах.

Но стоит учитывать пару нюансов:
- ScatterMap не потокобезопасен 🕵️ (просто держите это в уме)
- он не очень эффективен, если вы часто удаляете элементы или работаете с огромным количеством данных.

💬А вы когда-нибудь заморачивались, чтобы использовать ScatterMap? 🤔
Разобрать ли мне более подробно ScatterMap?

#ui #performance #scattermap
👍14🔥41
Как разрулить рисование пальцем и Zoom в Compose?

Мой коллега, Дима, очень любит Compose и пишет про него всякие интересные посты, кстати, подписывайтесь на него.

Например, в этом посте он разбирает как сделать так:
- если вы дотронулись одним пальцем, то вы рисуете;
- а если двумя — то зумите/поворачиваете.

Дима написал модифайер, там есть Gist. Если столкнетесь с подобной задачей, то будете знать, как её решать!

#compose #canvas
👍7
This media is not supported in your browser
VIEW IN TELEGRAM
В продолжение поста про рисование на Canvas, у нас появляется новое требование 🚨
Что если нам надо теперь уметь трансформировать холст?

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

Наш главный кандидат – PointerInputScope.detectTransformGestures(). Он сразу посчитает все значения и отдаст нам pan, zoom, rotation

Однако сразу как добавим его, обнаружим, что он конфликтует с жестом рисования detectDragGestures(). Причина простая – жест обрабатывается самым вышестоящим обработчиком и не пробрасывается дальше

Modifier
.pointerInput(Unit) {
detectDragGestures()
}
.pointerInput(Unit) {
detectTransformGestures()
}

Чтобы избежать этого, нужно что-то творческое

Возьмем исходный код из detectTransformGestures и подкорректируем его с учетом пожеланий:

1. Когда жест происходит одним пальцем, мы рисуем. Значит нам дополнительно нужно отслеживать drag, примерно как делает detectDragGestures
2. Когда жест двумя пальцами, начинаем трансформирование. И рисовать уже не получится
3. Когда мы начинаем одиночный жест, и с задержкой ставим второй палец, режим переходит в трансформацию только в случае если не преодолели threshold по drag. А нарисованное удаляем

В итоге получаем обработчик жеста – опубликовал его в виде Gist
Отличия от стандартной реализации – более сложное условие для начала трансформации

var dragAmount = 0f  
val dragAmountThreshold = 50f

// 2 pointers is required for transform gesture
val gesturePointersRequirementMet = downPointerCount > 1

if (!canceled && gesturePointersRequirementMet && dragAmountThreshold > dragAmount) {
// Handle gesture


И в если не проходим по условию – просто рисуем на канве
else {  
val change = event.changes.first()
if (!dragGestureStarted) {
dragGestureStarted = true
onDragStart(change.position)
}
if (transformGestureStarted) return@awaitEachGesture
onDrag(change.positionChange())
dragAmount += change.positionChange().getDistance()
}


Не забудем трансформирование применить в Modifier.graphicsLayer{} и динамический режим рисования/трансформирования как на видео готов!

Полный пример я опубликовал в репозитории про Canvas из прошлого поста

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

#compose #gestures #modifier #yandexcup
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥6
📺 Про ScatterMap на видео 📽️

В одном из прошлых постов я писал про ScatterMap и спросил вас, стоит ли мне рассказать про него подробнее. Получил фидбек, что стоит, и я решил рассказать!

Когда начал готовить пост, то понял, что материала много, и я в пост не уложусь, даже если буду рассказывать чисто по верхам. Это надо статью писать. Но статью писать (пока) не хочу, и я решил попробовать рассказать кратко в форме видоса. Экспериментальный формат 😅

Цель видоса — рассказать кратко суть и логику ScatterMap. Чтобы “на пальцах” было понятно что к чему. Не вдаваясь в детали. А те кто хочет — вэлкам читать статьи и слушать часовые доклады.

Например, кто заинтересовался, можно посмотреть эти материалы:
- Статья от Romain Guy про ScatterMap
- Видос Designing a Fast, Efficient, Cache-friendly Hash Table, Step by Step от Matt Kulukundis, где он очень классно рассказывает логику работы такой мапы

Получилось, что получилось. Но вы мне скажите, как вам? (Видос будет следующим постом)
🔥7
Media is too big
VIEW IN TELEGRAM
Как работает ScatterMap
🔥22👍101
Пишем транзишинометр на Андроид 🎛️

Сегодня вышла моя статья:
👉 Пишем транзишинометр для Андроид

Суть такая. Как замерять UI-перформанс? Здесь можно подойти с двух сторон:

- замерять плавность кадров: JankStats, Macrobenchmark и подобные штуки нам в помощь. 🎥📊

- замерять скорость открытия экранов, или, другими словами, как быстро происходят транзишны. 🚪

В статье я рассказываю, как написать свой транзишинометр (классное слово я придумал?), чтобы замерять скорость открытия экранов. Там с примерами кода, с картинками — всё по полной.

Например, я рассказываю, как можно замерить время от открытия экрана и до первого, и до последнего onDraw. И это всё как для Fragment, так и для Compose.

Мы активно использовали такой подход, когда переходили на Compose, чтобы отслеживать, насколько быстро открываются экраны. 💨📱

Если хотите узнать подробнее, читайте статью, ставьте плюсики! 👍

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

#android #compose #ui #performance #benchmark
🔥23👍7🦄31
Анонс DevFest в Измире и Анталии 🎤

Завтра, 7 декабря, я выступаю на DevFest в Измире, а уже через неделю, 14 декабря, жду вас в Анталии на DevFest'е. 📅

Честно говоря, не думаю, что среди подписчиков много тех, кто живёт в Измире. Но если вдруг вы из этих краёв — приходите! Будет весело, затусим! 🍕🎉

📍 Адрес:
https://maps.app.goo.gl/jCTHYbSCsEdfoFyG6

🌐 Сайт:
https://devfest24.gdgizmir.org/

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

Вот эти статьи:
1️⃣ Пишем транзишинометр для Андроид. Как понять, что мои экраны открываются быстро?

2️⃣ Jetpack Compose как unbundled-библиотека. Скорость UI vs. Гибкость разработки

Если интересны темы UI-перформанса или как жить с Compose, обязательно заглядывайте!

Мои доклады на DevFest и эти две статьи — очень близки. Просто статьи более подробные, чем доклады.

Ну а кто будет в Измире или Анталии, приходите на DevFest. Увидимся! 🚀

#devfest #compose #turkey
🔥121👍1👏1🥴1
Kotlin/JS ≠ KMP 😱

Разберёмся с формулировками. Я раньше думал, что если я написал в проекте:


plugins {
kotlin("multiplatform") version "2.1.0"
}


То у меня теперь KMP проект! Могу себе повесить медальку 🏅! Но это не так 🤔

KMP — это про шаринг кода между разными платформами: Android, iOS, Desktop, фронт, бэк и т.д. Суть KMP — использовать один и тот же Kotlin-код, который компилируется в разные бэкенды: JVM, JS, Native.

А вот если вы делаете проект только на Kotlin/JS (например, фронтенд, транспиляция в JavaScript), но не шарите код с другими платформами, то это всё-таки не KMP. Это просто проект на Kotlin/JS.

📝 Это мне пояснила Катя Петрова из JetBrains. Чтобы вы не думали, что я сам придумал. 😉

Если вы это знали — круто! 🎉
Если нет, как и я раньше — поздравляю, теперь знаете! 🎓

#kotlin #kmp #kotlinjs
🤓18👍5😁4🎉3👎1🤔1🗿1
Как поDDoSить самих себя 🚨

Недавно у нас в Drinkit случилась забавная история: наше собственное Android-приложение начало "ддосить" наш же бэк. И всё это по нашей же вине! 🤦‍♂️

Дело было так: мы переезжали с одной инфраструктуры на другую. Всё прошло вроде бы успешно, но после этого наше приложение стало слать невероятное количество запросов, которые стабильно завершались ошибкой. “DDoS” в кавычках, потому что до отказа бэка было далеко, но фоновый шум вырос катастрофически — по нашим меркам. 📈

Почему так произошло? Я это более подробно расскажу в следующем посте, а пока предлагаю вам проголосовать. Как вы думаете, в чём причина?

1️⃣ Приложение ночью в фоне начало слать кучу необязательных запросов. 🌙📡
2️⃣ Политика ретраев такая, что на один запрос генерировалось до 40 дополнительных.💥
3️⃣ Бэк внезапно стал во всём виноват. 🤷‍♂️
4️⃣ Всё вышеперечисленное сразу. 💣

Ниже бахну голосовалку отдельным постом.

💬 У вас было, что вы DDoSили сами себя?

#android #backend #retro
🔥5😁31