Dolgo.polo Dev | Денис Долгополов @dolgo_polo_dev Channel on Telegram

Dolgo.polo Dev | Денис Долгополов

@dolgo_polo_dev


Разбираемся в мобильной разработке (Android/iOS) и пытаемся выяснить, зачем оно так устроено

Статистика/цены: @dolgo_polo_dev_stats

По вопросам/рекламе: @dolgopolovdenis

Dolgo.polo Dev | Денис Долгополов (Russian)

Добро пожаловать в Telegram-канал Dolgo.polo Dev, ведущим которого является Денис Долгополов! Мы специализируемся на мобильной разработке для платформ Android и iOS, при этом стремимся понять, почему все устроено именно так, как есть. Наш канал предлагает уникальный взгляд на разработку мобильных приложений, а также делится полезной статистикой и информацией о ценах. У нас вы найдете исчерпывающую информацию о новейших технологиях и трендах в мобильной разработке, а также сможете следить за последними инновациями в этой области. Если у вас возникли вопросы или вам нужна помощь с рекламой, обращайтесь к нам по контактам: @dolgo_polo_dev_stats и @dolgopolovdenis. Присоединяйтесь к нам и станьте частью нашего сообщества мобильных разработчиков!

Dolgo.polo Dev | Денис Долгополов

15 Nov, 18:30


💎 Приложение просыпается чаще, чем вы думаете

Возможно я проспал этот момент на начальных уроках по Android, но

🔵Application.onCreate() вызывается чаще, чем пользователь запускает приложение

То есть прям гораздо чаще

Например, если приходит пуш, приложение запускает фоновую работу или система решает прогреть приложение для быстрого запуска — вызовется Application.onCreate()


Вывод:

🔵тригером для части логики может служить не Application.onCreate(), а первый вызов Activity.onCreate() (если эта логика нужно только для кейсов, когда юзер действительно открыл приложение)

Например, возможно ваше приложение логирует открытие приложения в Application.onCreate(), а по факту пользователь его не открывал, и у вас совершенно фейковые представления о DAU 💵

Или, возможно, из Application.onCreate() можно выкинуть инициализацию части библиотек, который не нужны без фактического открытия приложения пользователем

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

13 Nov, 09:01


Как проводить мобильное тестирование без телефонов?
 
27 ноября в 12:00 Selectel проведет вебинар, на котором расскажет, как настроить ADB-соединение с удаленным устройством на своей локальной машине и как использовать Мобильную ферму Selectel в автотестах Android-приложений.
 
Старший разработчик Мобильной фермы Selectel Антон Ореховский объяснит, как добавлять ADB-ключи и избегать ошибок при установке соединения, локально запускать автотесты и интегрировать Мобильную ферму в CI/CD. А также ответит на все ваши вопросы.
 
Зарегистрируйтесь по ссылке
 
Реклама, АО «Селектел», ИНН: 7810962785

Dolgo.polo Dev | Денис Долгополов

11 Nov, 19:00


🧬 Глобальный откат WebView в 2021 году

Старая история, которая уже чут-чут перебродила, но от того не стала менее увлекательной


Немного контекста:

android.webkit.* (WebView) — это java-классы, которые мы используем для взаимодействия с WebView. Являются частью Android SDK

Chromium — это нативный движок, к которому обращаются java-классы WebView через JNI (Java Native Interface) и который выполняет всю основную работу

главное — Chromium обновляется отдельно от AndroidSDK (вендором или через Play Market в рандомный момент)


Дело было в 2021 году:

Google выпустил обновление движка Chromium на пользователей. А он сломанный

И у всех гигантов (Gmail, Amazon...) стала крашится WebView в приложении

Помогало одно — откатить WebView через Play Market (или ждать обновления от гугла)

Конец


Кстати, если вам мало боли с WebView в жизни, то в Play Market можно скачать Canary и Beta сборки WebView (Chromium) и переключиться на них. На картинке отзыв на Сanary сборку. Она обновляется, внимание, ежедневно

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

07 Nov, 18:40


🪐 WebView в фоне

Интересный небольшой факт — WebView может загружать страницы без отображения самой WebView на экране

Можно вызывать WebView(context).loadUrl(url) не отображая WebView на экране и не добавляя ее в верстку

С помощью этого можно:

🔵настроить prefetch страниц — загрузить страницы заранее в фоне, чтобы не мучать пользователя долгим открытием

🔵закэшировать страницы заранее (если включить кэш WebView и прислать хэдер cache-control)

....

еще по теме:
🔵WebView vs GeckoView vs ChromeTabs vs TWA

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

04 Nov, 12:30


🧬 Сломанный UX как защита от дурака

Наливал тут кипяток из автомата с водой. Режим "экстра горячая вода для чая" на нем включался только после выполнения сложного ритуала — покрутить колесико, зажать кнопку, пару секунд подумать, и только после этого кипяток начинал литься


Давайте подумаем, где такой же подход стоит использовать в приложении

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


Как минимум — показать предупреждающий экран и попросить ввести пин-код

Хотя эти действия настолько обыденные, что обычно выполняешь их с той же легкостью, как открытие двери и выключение утюга


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

🔵потрясите телефон, если хотите удалить сообщение только у себя

🔵разгадайте капчу, если действительно хотите репостнуть этот аморальный мем в чат с родственниками, а не друзьями

🔵нажмите кнопки от 1 до 9, если хотите подключиться к звонку с включенной видеокамерой

Хороший пример кстати это флоу отмены подписки в яндексе. Случайно точно не нажмешь

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

04 Oct, 16:00


🧬 Как правильно тестировать приложение


Вместо флагмана новых поколей стоит взять в руки старенький инфиникс с поцарапанным экраном

Находиться нужно в положении полулежа, чтобы поворот экрана срабатывал в самый неожиданный момент

На часах должно быть около 17:00-19:00 вечера, когда устройство в рандомный момент переключается с темной темы на светлую

Язык системы — персидский или японский, время системы строго не московское

При этом стоит переместиться из уютного офиса куда-нибудь в область подвала, иначе сверхскоростной офисный Wi-Fi исказит пользовательский опыт

В идеале в этот момент батарея должна быть практически разряжена, а в списке запущенных приложений обязан находиться Cyberpank 2077, открытый через эмулятор Windows 10, и десяток свернутых браузеров

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

Гугл сервисы отключаем, хуавей кстати тоже

Версия ОС должна быть либо достаточно старая, либо последняя — работать будут одинаково непредсказуемо

Память устройства при этом должна быть забита на 97%. Оставшиеся 3% нужны, чтобы ПЗУ закончилось в случайный момент


Подготовка на этом завершена, можно начинать тестирование

🤡🤡💩

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

25 Sep, 18:45


🧬 Фингерпринт

Многие вероятно слышали про фингерпринт браузера:

-> сложив пару десятков открытых данных о браузере/компьютере пользователя, можно с большой вероятностью идентифицировать пользователя

Такой же фингерпринт без труда можно собрать в мобильном приложении


Недавно узнал два интересных факта:

🔵в режиме инкогнито браузер даже не пытается запутать фингерпринт

🔵убедиться в этом можно на крутом сайте amiunique.org/fingerprint — он показывает, насколько ваш фингерпринт уникальный и не такой как все)

и заодно выводит значения всех параметров, из которых формируется фингерпринт


Например, в него входят настройки WebGL, высота системных UI-панелей, список установленных плагинов и поддерживаемых видеокодеков


мой фингерпринт уникальный 😎

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

21 Sep, 16:20


кстати напоминаю про эти папочки

список там постепенно пополняется 📝, как натыкаюсь на новые каналы

и хожу агитирую шарить по возможности) 🪐

Dolgo.polo Dev | Денис Долгополов

21 Sep, 16:20


🔗 Какая Activity открыта

Нашел для себя еще одну крутую комманду adb:

adb shell dumpsys window windows | grep 'mActivityRecord'
// в Windows grep можно заменить на find

Она показывает имя открытой Activity


сделал для нее alias:

adbAStack = "adb shell dumpsys window windows | grep 'mActivityRecord"


Например, с помощью нее вычислил название активити со списком свернутых приложений в системном лаунчере:

com.sec.android.app.launcher/com.android.quickstep.RecentsActivity

Теперь могу открыть это меню прямо через adb (зачем?) или сделать в приложении кнопку "открыть список свернутых приложений" (зачем??)


А если серьезно команда имба, так как по внешнему виду UI не всегда понятно, с какой Activity работаешь

еще про adb:
🔵как тапать хомяка через adb
🔵(habr) прикладное adb для зумеров

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

28 Aug, 16:04


🧬 Жизнь это сложно

Но еще сложнее следить за жизненным циклом

Одна из самых сложных штук в мобилке, хотя казалось бы

Во-первых, ЖЦ отличается у:
🔵Application
🔵Activity
🔵Fragment
🔵View
🔵не говоря уже о процессах, сервисах и тасках

Добавим влияние диалогов/шторок, частично перекрывающих экран

Дальше умножаем это на сложные экраны современных девайсов — раскладушки, двойные экраны, режимы окна к окне...

Складываем с рекомпозицией от Compose, если используете AndroidView внутри Compose или наоборот

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

Готово, стало сложно 🧠

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

26 Aug, 16:03


🧬 Фоновые процессы теперь более заметны

Обратил внимание, что после обновления на Android 14 в списке запущуенных приложений начали отображаться запущенные процессы

"1 активный фоновый элемент"

Подозреваю, что туда попадают запущенные Service и, возможно, воркеры WorkManager-а

так что теперь у юзеров появляется дополнительная более явная возможность остановить фоновую работу

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

25 Aug, 09:11


🧬 Ваше устройство украли — мы его заблокировали

Гугл в начале мая анонсировал фичу Android Theft Protection


Если вор выхватит у вас телефон из рук и начнет с ним убегать, то экран автоматически заблокируется

Работает это на основе Google AI, который вероятно анализирует датчики акселерометра, gps и, возможно, камеры/микрофона (это уже мои догадки)


Вопросов эта фича вызывает больше чем ответов:

🔵сколько профессиональных карманников гугл нанял, чтобы записать дата-сет краж для обучения нейронки

🔵начнут ли воры красть телефоны странно и нестандартно двигаясь, чтобы запутать ИИ

🔵сработает ли эта фича, когда девушка выхватывает телефон, чтобы прочитать твои переписки

🔵неужели уже можно дешево в фоне постоянно гонять ИИ, анализирующий датчики, не переживая за CPU/батарею?

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

20 Aug, 11:02


🧬 Загадка на логику

Представьте, запускается приложение

В каком порядке будете инициализровать эти 4 библиотеки?

1️⃣ Sentry SDK — логирует ошибки, краши и ANR-ы

2️⃣ Auth SDK — хранит данные о юзере

3️⃣ UserTracker SDK — логирует действия юзера, в том числе события запуска

4️⃣ FeatureFlags SDK — стягивает фича флаги для А/Б

победителю — пятикратное ура 👍

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

08 Aug, 19:30


🧬 Кросс-платформа

Пошла волна 🌊 хейта в сторону кросс-платформы (раз, два), а у меня на эту тему давно черновик лежит)

Давайте так:

Все последнее время топят за кросс-платформу

А какие в ней плюсы для разработчиков?

Вы куда воюете?

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


А для простых работяг:

🔵уменьшение рабочих мест

🔵нужно ботать новые технологии

🔵нужно разобраться в костылях не только своей, но и чужой платформы

🔵x2 времени на сборку проекта, x3 проблем с кэшами студии, x4 сломанных джоб на CI

🔵более универсальное — всегда более ограниченное. привет урезанные API и библиотеки с минимальным конфигом, чтоб SDK не развалилось на повороте

🤡🤡💩

@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

03 Aug, 13:32


🧬 Все каналы по мобильной разработке

Собрал тут кажется самую большую коллекцию:


🌸Android — авторский контент об Android

🌸iOS — авторский контент об iOS

🌸Компании — bigtech-компании и организации

🌸Подборки/новости/библиотеки


@dolgo_polo_dev

Dolgo.polo Dev | Денис Долгополов

29 Jul, 17:04


Реверс-инжиниринг чужого приложения

Dolgo.polo Dev x Coffee&Code
#cross_post

💎 iOS

во что собирается приложение?

в .ipa-файл, а в нем код в формате unix executable file (бинарь, скомпилированный код)


можно ли декомпилировать чужое приложение?

да, если у вас есть доступ до .ipa файла (как его получить), можно с легкостью дойти до ассемблерного кода (используя Hopper, можно получить даже псевдо код)

приложения из AppStore шифруются и без jailbreak будет сложно достать что-то полезное из обфусцированного бинаря, но добрые (или не очень) люди создают сайты, где выкладывают незашифрованные бинари популярных приложений


можно ли пересобрать чужое приложение, изменив его исходники, и поставить себе на устройство?

да, например тулза sideloadly позволяет пересобрать .ipa файл с дополнительным фреймворком (который мы можем написать сами)

этот фреймворк, к примеру, может случайно посвиззлить (подменить реализацию метода в рантайме) функцию начисления количества внутриигровой валюты и сделать нас миллионерами


что защищает от хакнутых приложений?

🔵источник приложений только один — AppStore (уже нет)
🔵подпись .ipa-файла, связанная с аккаунтом разработчика
🔵DeviceCheck — фича, позволяющая сгенерировать токен оригинальность приложения и проверить его на бэкенде


можно ли посмотреть исходники любой библиотеки?

только если она в публичном доступе

в остальном, также декомпилировать и смотреть ассемблер или дампнуть хедеры (интерфейс либы)

еще есть возможность изучить библиотеку прямо в рантайме, если она написана на Objective-C, используя инструменты дебага

например можно:
🔵запринтить все методы объекта (подробнее)
🔵переопределить любой (да да, любой, даже приватный) метод
🔵подменить класс в рантайме, создать класс в рантайме
🔵вызывать любой метод (даже не объявленный)
🔵подключить любую библиотеку (даже системные фреймворки Apple) и много чего еще




💎 Android

во что собирается приложение?

в .apk-файл, в котором лежит java-байткод (Java/Kotlin-код компилируется в java-байткод на этапе сборки .apk)


можно ли декомпилировать чужое приложение?

да

получить .apk-файл можно из любого приложения, установленного на устройстве

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

единственная защита от этого — обфускация кода. но она лишь усложняет читаемость кода, а не защищает от считывания


можно ли пересобрать чужое приложение, изменив его исходники?

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


что защищает от хакнутых приложений?

🔵подпись приложения

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

если изменить исходный код приложения, то подпись потеряет актуальность, и система не даст установить такое .apk

🔵Play integrity API — фича, позволяющая сгенерировать токен оригинальность приложения и проверить его на бэкенде


можно ли посмотреть исходники любой библиотеки?

да, у нас есть доступ к исходникам любой либы, написанной на Java/Kotlin (в том числе системных/гугловских) прямо из Android Studio



💎 Выводы

все секреты, попавшие в .apk/.ipa-файл (токены/алгоритмы шифрования/пароли/протоколы...), могут быть вытащены и подменены с помощью реверс-инжиниринга на обоих платформах

на iOS изучить/подменить чужое приложение сложнее, но тоже реально

так что все что попало в .apk/.ipa-файл — считай open-source


спасибо Coffee&Code и в частности @gronzeisl за экспертизу по iOS

Dolgo.polo Dev | Денис Долгополов

19 Jul, 17:59


Новая рубрика — #cross_post

в ней мы сравним iOS и Android технологии

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

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

и возможно приблизим кросс-платформу. или точно поймем, что оно нам не надо


p.s. в некоторых темах будут участвовать приглашенные эксперты и просто заслуженные мэтры iOS/Android-разработки

Dolgo.polo Dev | Денис Долгополов

07 Jul, 15:15


Кастомные операторы

Наткнулся на либу для построения графов

Насколько она хороша не знаю, но меня зацепило, как они грациозно позволяют задать граф:


LabeledGraph { A - "C" - E }


• A и E — объекты вершин, возможно уже с какими-то связями

• "C" — название для новой вершины, для которой автоматически создастся объект

и вместе они соединяются в направленный граф с помощью минуса


примерно так:


operator fun minus(new: Any) = Vertex(incoming = this, current = new)


....

есть еще ситуации, когда кастомный operator реально упрощает жизнь?

operator fun minus(b: Int) = this + b 👍