Обновить

Мобильная разработка

Сначала показывать
Порог рейтинга

Представлен открытый проект Send it, with PairDrop (веб-версия проекта) — AirDrop для всех. Это универсальный способ передачи файлов на ПК и мобильных устройствах в браузере между Windows, Linux, Android, iOS, macOS и другими ОС:

  • работает без скачиваний драйверов и утилит и дополнительного ПО;

  • просто открываем сайт на обоих устройствах в браузере и начинаем передачу;

  • если используете одну сеть Wi‑Fi — устройства сразу увидят друг друга;

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

  • передача файлов идем напрямую между устройствами;

  • можно передавать большие объёмы данных без ограничений.

Теги:
+5
Комментарии0

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

Три вещи которые горели чаще всего.

Разные версии Android. На эмуляторе всё красиво. На реальном устройстве со старой версией что-то обязательно едет. Держу под рукой старый телефон с Android 10, туда ставлю перед каждым релизом.

Разрешения. Забываешь добавить в манифест, на новых версиях система спрашивает пользователя, пользователь жмёт «запретить» и половина функций молча перестаёт работать. Без каких-либо ошибок в логах.

ProGuard и минификация. Локально всё работает. В release сборке падает что-то что ты вообще не трогал. Потому что минификатор убрал класс который использовался через рефлексию.

Список не длинный но каждый раз спасает от как минимум одного стыдного бага в продакшене.

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

Теги:
+4
Комментарии0

Открытый проект RepoStore для смартфонов на Android превращает GitHub в Google Play и помогает найти любые Android‑приложения среди репозиториев. С помощью RepoStore можно быстро найти и открыть APK‑файл — у него будут описание и даже рейтинг. Всё разделено по категориям.


Теги:
+13
Комментарии0

Ваш телефон работает не на вас.

К 2026 году слежка переехала из очевидных приложений в незаметные — фоновые сервисы и функции, у которых нет даже иконки на экране. Вы их не видите. Они видят вас.

Я сделал Sovereign — приложение, которое делит один Android на три изолированных пространства:

Гражданин — госуслуги, банки, маркетплейсы, MAX, Telegram. Человек — личное: Signal, крипто-кошельки, торрент-хабы. Суверен — зашифрованный анклав для самого ценного.

Без root. Без облака. Без подписки.

Что умеет: рентген слежки приложений (X-Ray), хранилище с пост-квантовым шифрованием, ИИ прямо в телефоне офлайн, скрытый сейф.

Честно: это цифровая гигиена, а не режим невидимки для спецслужб. Никаких пустых обещаний.

Sovereign — часть экосистемы соло-разработчика Vladislav Shter. Рядом: Egregor (уже в продаже) и скоро уникальный SovereignWeb3 Browser.

Демо и покупка: https://s0vereign.pw/sovereign.html

Видео: https://youtu.be/cvy4_lwi-TI

GitHub: https://github.com/VladislavShter/SOVEREIGN

#приватность #защитаданных #Android #слежка #Sovereign #кибербезопасность

Теги:
+1
Комментарии0

Сравнение Claude Code Fable и Codex Open AI по ходу работы над одним и тем же проектом

Вчера, 1-го июля, программисты и активисты начали бурную трудовую неделю. А именно: вернулась модель Claude Fable 5 и она будет доступна в вольном режиме до (или по) 7 июля. Так что есть 7 дней, чтобы сделать буст своим проектам.

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

Что сказать про впечатления? - Ощущение вот того самого вайб кодинга, о котором говорил Карпаты. Говоришь модели что делать и она делает. Технических ошибок просто нет, от слова совсем. Есть ошибки архитектурные, но не существенные, исправляются одной-двумя итерациями.

И кстати, получилось сравнить с Codex'ом от Open AI, который решил попробовать на старте этого же проекта. Результат сравнения такой: Codex очень сильно подтянулся в работе с кодом, иногда даже кажется, что нет различий.

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

Claude Code Fable в этом отношении гораздо чётче действует. Более жёстко держит инструкции, больше памяти, что характерно, помнит предыдущий и даже предыдущие чаты. Меньше разбрасывания на второстепенные детали, чётче фокус. Даже чек-лист у него выглядит проще, чётче и понятнее, чем у Codex.

Единственное, что может я так натаскал Claude. С другой стороны, не использую MCP, RAG, даже скилы и хуки. Зашил все в память, их там три: общая пользовательская, описание проекта и правила работы.

И напоследок обнаружил в Claude очень полезную функцию оценки загруженности контекстного окна.

Может она уже давно там была, о ней вроде писали, но что-то казалось, что это в CLI. А теперь оказывается её можно использовать и в декстопной версии. Думаю и другим пользователям это тоже пригодится.

Обычно смотришь, если чат начинает тормозить, значит пора. Или спросишь саму модель, но она обычно отвечает, что если на глаз, то загружена на 75%, но лучше начать новый чат. А теперь можно точно увидеть процент загруженности. Более того, можно даже увидеть чем именно загружено контекстное окно.

Для этого в чате Claude Code, в поле ввода достаточно ввести слэш команду - /context

Прикрепляю скриншот как это выглядит вживую

И ещё такое впечатление, что Claude Fable стал жечь меньше токенов за счёт какого-то более делового, но все ещё дружелюбного стиля общения.

Так что, удачи всем с проектами на этой бурной трудовой неделе!))

Теги:
+2
Комментарии0

Сквозное шифрование, или как Telegram и Bitcord защищают переписку.

Хочу написать небольшой пост о сквозном шифровании, или, если использовать технический термин, E2EE (End-to-End Encryption).

Сегодня эта технология широко применяется во многих мессенджерах. Я тоже реализовал E2EE в мессенджере Bitcord . Однако далеко не все понимают, как именно работает этот механизм, поэтому попробую объяснить простыми словами.

Поскольку я являюсь разработчиком и основателем собственного мессенджера, реализовать эту схему для меня не составило особого труда. Главный секрет заключается в понимании принципов работы криптографических алгоритмов, таких как AES и RSA. Хотя современные реализации E2EE обычно используют не RSA, а алгоритмы на эллиптических кривых (например, X25519), я не стал прибегать к усложнениям.

Алгоритм AES я использовал для непосредственного шифрования текстового сообщения, которое один пользователь отправляет другому. Для шифрования применяется секретный ключ (или пароль). Основная проблема такого подхода заключается в том, что этот ключ необходимо каким-то образом передать получателю. Если злоумышленник перехватит ключ, он сможет расшифровать сообщение.

Чтобы этого не произошло, я использовал ещё один алгоритм - RSA. Для его работы требуется пара криптографических ключей: публичный и приватный. Так как RSA не предназначен для шифрования больших объёмов данных, я его использовал для безопасной передачи того самого секретного ключа, который используется алгоритмом AES.

В результате схема выглядит так.

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

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

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

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

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

В этом и заключается смысл сквозного шифрования: сервер передаёт сообщения, но не имеет возможности их прочитать.

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

Именно поэтому требование "передать ключи" технически лишено смысла. Передавать попросту нечего.

П.С.

Я - сетевой долгожитель и начинал свой путь еще в эпоху Фидонета (FidoNet). Эта сеть была по-настоящему децентрализованной: никаких общих серверов и никакого DNS. Все строилось просто: компьютер, модем и терминальная программа для связи. Часто в роли узла (ноды) выступал сервер в банке, где знакомый сисадмин выделял адреса. При этом подключиться можно было к любому другому участнику, даже к частному лицу. Вот это и была настоящая децентрализация! Думаю, учитывая растущее давление регуляторов на современный интернет, мы скоро снова вернемся к проверенным идеям старого доброго Фидо.

Теги:
+7
Комментарии0

Прямая Web3-монетизация без посредников (Peer-to-Peer) для артистов на радио.

Буквально вчера закончил написание сервисного бота для коммерческих нужд в мессенджере "Concord". Основной целью проекта является автоматизация процессов публикации авторского материала на интернет-радио. Бот был создан как помощник для авторов аудиоконтента: музыкантов, продюсеров, подкастеров и т. п.

Задача была непростой. Нужно было объединить возможности мессенджера с его токеномикой и реализовать передачу медиаконтента (картинок, аудиофайлов, текстовых данных) на удаленный сервер в формате JSON. Для этого я написал серверную страницу на PHP, в которой реализовал весь необходимый API.

При передаче медиаданных пользователь запускает нужного бота и отправляет ему в личные сообщения весь необходимый материал. Отправка изображения артиста и аудиофайла выполняется напрямую, без каких-либо команд. Бот сам идентифицирует тип данных, полученных от пользователя, и записывает их в локальные файлы. Вот как я реализовал проверку принадлежности данных к типу файлов:

function isJpeg(string $data): bool
{
    return substr($data,0,2) === "\xFF\xD8";
}

function isMp3(string $data): bool
{
    if (substr($data,0,3)==="ID3") {
        return true;
    }

    return isset($data[1])
        &&
        ord($data[0])===0xFF
        &&
        (ord($data[1]) & 0xE0)===0xE0;
}

После получения данных нужно сразу определить что именно пришло - команда или файл:

if (preg_match('/^\/(help|bio|title|tracks|done)\b/i', $data))
{
    processCommand($db, $uuid, $data);
    exit;
}

if (isBase64($data))
{
    saveBinary($db, $uuid, $data);
    exit;
}

reply("Unknown command, please use /help.", false);

Описание профиля артиста и названия его треков передаются в текстовом виде используя специальный набор команд:

  • /help - Show this help

  • /bio text - Update artist biography

  • /tracks - Show info of all tracks

  • /title text - Update current track title

  • /pay amount - Pay for service

  • /done - Finalize current track

  • Send JPG image to update artist image

  • Send MP3 audio to update current track

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

  1. артист отправляет фото профиля

  2. артист отправляет описание профиля

  3. артист загружает трек

  4. артист отправляет описание трека

  5. артист выполняет оплату сервиса

  6. артист финализирует трек

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

МОНЕТИЗАЦИЯ

Отправка материала артистом требует платы за сервис. Когда артист подтверждает оплату, бот списывает с его кошелька требуемую сумму и зачисляет её на кошелек владельца радиосервиса. Это значительно упрощает обмен активами между плательщиком и получателем.

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

схема работы блокчейна
схема работы блокчейна

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

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

Если у вас появятся предложения, буду рад подискуссировать.

Теги:
0
Комментарии6

Как перестать вручную поддерживать экран настроек

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

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

Илья, iOS‑разработчик в Naumen, рассказывает, как пришел к подходу, при котором разработчику достаточно описать новое свойство, а интерфейс собирается автоматически.

Почему задача оказалась сложнее?

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

Но довольно быстро возник другой вопрос: как проверять изменения без постоянной пересборки приложения?

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

Почему обычный экран настроек не решил проблему?

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

Чтобы добавить новую настройку, нужно было каждый раз:

  • добавлять свойство;

  • добавлять соответствующий UI‑компонент;

  • настраивать обработку;

  • связывать с хранилищем данных.

Я начал искать подход, при котором разработчику не нужно отдельно поддерживать интерфейс настроек. Хотелось, чтобы достаточно было просто описать новую настройку, а все остальное система делала сама.

В этот момент я вспомнил про Reflection. В Swift этот механизм ограничен и фактически работает как интроспекция, но даже этих возможностей оказалось достаточно для решения задачи.

Как сделать так, чтобы экран собирался автоматически?

В основе подхода лежит декларативный принцип: разработчик описывает свойства объекта настроек и добавляет к ним метаданные, например, название настройки или связи с другими параметрами.

Дальше система анализирует структуру объекта, определяет типы данных и автоматически подбирает нужные UI‑компоненты:

  • для булевых значений — переключатели;

  • для текста — поля ввода;

  • для чисел — поля с ограничением на числовой ввод.

Что изменилось после внедрения такого подхода?

Теперь для добавления новой настройки достаточно описать новое свойство и добавить необходимые метаданные. После этого настройка автоматически появляется в интерфейсе.

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

→ Подробнее своим опытом Илья поделился в статье.

Теги:
+5
Комментарии0

Как я научил свою читалку различать примечания и комментарии в «Войне и мире»

Я не профессиональный программист. Пишу Android-читалку MRead для себя и для тех, кому тоже надоели комбайны. Код закрытый, всё работает локально, без серверов и трекинга. Раздаю через RuStore, 4PDA и GitHub.

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

Проблема

Открываю «Войну и мир». В одном предложении сразу два маркера сноски: примечание (перевод французского) и научный комментарий. В разных изданиях они нумеруются независимо, поэтому в тексте легко встретить два маркера с одинаковой цифрой. Старая логика по тапу вытаскивала из текста ближайшую цифру и искала абзац, начинающийся с этого числа, по всем главам, и показывала первое совпадение. Итог: тап по «6» открывал не ту сноску, а тап по числу вроде «1805» вообще пытался найти несуществующую сноску.

Почему наивный подход не работает

Цифра это не идентификатор. Она повторяется и в каждой главе, и между разделами «Примечания» и «Комментарии». А вот в исходнике всё однозначно: каждый маркер это ссылка с уникальным адресом.

EPUB: 1 FB2: [6] и {4}

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

Что я поменял

  1. При разборе HTML сохраняю не только текст абзаца, но и ссылки-сноски с точной позицией маркера. Позицию считаю надёжно: оборачиваю маркер невидимыми символами из Private Use Area до очистки текста, а после очистки нахожу их и вычисляю смещение. Так цифры в обычном тексте (годы, числа) не путаются с маркерами.

  2. Позиции храню в абсолютных координатах главы. Это важно, потому что мой пагинатор режет абзацы на куски по строкам. Абсолютные смещения переживают нарезку без отдельной возни в пагинаторе.

  3. По тапу беру не цифру, а ссылку под пальцем, и резолвлю сноску по точному id из нужного файла. Для FB2 пришлось ещё и сохранить id секций сносок при конвертации в HTML, потому что примечания и комментарии лежат в отдельных главах.

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

Результат: тап по примечанию открывает перевод, тап по комментарию открывает комментарий, а год «1805» больше никого не трогает.

Контекст для тех, кому интересно

Рендер текста у меня не WebView, а нативный движок на Canvas с собственной пагинацией (Jetpack Compose, Kotlin). Это даёт контроль над переносами, выравниванием по ширине и стабильной привязкой цитат и закладок, но за каждую такую фичу приходится платить ручной работой вроде этой истории со сносками.

Что ещё в 1.4.0, кратко

• Полнотекстовый поиск по PDF (для PDF с текстовым слоем)
• Озвучивание (TTS): голоса, скорость, таймер сна, автопереход, пауза с памятью места
• Передача слова во внешний словарь и контекст предложения в экспорт Anki
• Настраиваемые блоки настроек чтения, межабзацный интервал, Bold/Italic
• Полки, фоновый импорт из папок, оценки и заметки, Material You

Ссылки

RuStore

GitHub

4PDA

Если у вас была книга FB2, переоткройте её, чтобы заработали точные сноски (HTML генерится при импорте). EPUB подхватит сам.

Буду рад замечаниям по подходу. Если делали резолв сносок иначе, расскажите как, мне правда интересно.

Теги:
Всего голосов 3: ↑3 и ↓0+6
Комментарии0

Обратная сторона рабочих чатиков

Андрей Врацкий начал строить рынок корпоративных мессенджеров в 2015 году, когда WhatsApp и Telegram только начинали проникать в рабочие чаты, а безопасники в компаниях делали вид, что все ок и деловая переписка — это личная ответственность сотрудника. 

На создание продукта ушло четыре года. Когда eXpress вышел в 2019-м, то выяснилось: все уже так привыкли к Telegram и WhatsApp, что менять ничего не хотят. 

Прошло семь лет. Сегодня иностранные мессенджеры заблокированы, отечественный* удален из App Store на неопределенный срок. На этом фоне спрос на eXpress вырос в четыре раза — и это пока Telegram все еще работает. Что будет, когда перестанет? 

Хотя по мнению Врацкого, хороший продукт будет востребован вне зависимости от обстоятельств и критерий его успеха — это конкурентоспособность на мировом рынке.

Подробнее — во втором выпуске подкаста «IT-фронтир».

Теги:
Всего голосов 4: ↑3 и ↓1+4
Комментарии2

Как я ускорил бэкапы в 20 раз и обошёл ловушку Jsoup: развитие самописной Android‑читалки MRead (v1.3.0)

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

Статья получила теплый отклик и в комментариях набежало много отличных предложений. В этом посте я хочу поделиться техническими решениями, которые вошли в крупное обновление 1.3.0.

1. Бэкапы и боль от Storage Access Framework (SAF)

В приложении есть функция бэкапа: упаковка базы данных Room, настроек и распакованных HTML‑глав с картинками в один ZIP‑архив. Изначально я писал файлы напрямую в OutputStream, полученный через ContentResolver (SAF). Итог: библиотека на 500 МБ архивировалась около 5 минут. SAF проводит проверки безопасности для каждого записываемого чанка, что убивает I/O операции.

Решение: сборка архива переехала во внутренний кэш приложения. Туда пишем без ограничений SAF — буфером по 64 КБ и уровнем сжатия BEST_SPEED (картинки уже сжаты, гнать их через BEST_COMPRESSION бессмысленно). Когда ZIP готов целиком, он одним куском копируется в пользовательскую папку через SAF — вместо тысяч мелких защищённых записей получается одна

2. Material You: как получить правильные цвета обоев

При внедрении динамических тем (Android 12+) я столкнулся с тем, что стандартный вызов dynamicLightColorScheme().background на многих устройствах выдает просто унылый белый или бледно‑серый цвет, игнорируя сочные оттенки обоев.

Решение: Самые насыщенные цвета из системной палитры Monet хранятся в secondaryContainer и surface. Решение нашлось в самой палитре Monet: наиболее насыщенные цвета живут в secondaryContainer и surface, а не в background. Переориентировал маппинг цветов приложения на эти слоты и интерфейс действительно ожил. Теперь интерфейс действительно реагирует на смену обоев. Плюс привязал OnSharedPreferenceChangeListener, чтобы тема менялась мгновенно на всех экранах без перезапуска.

3. Странности парсинга FB2 и баги Jsoup

Иногда вместо обложки FB2 парсер ставил черно‑белую картинку из середины книги. FB2 хранит все изображения в тегах <binary> в конце файла в хаотичном порядке. Если тег <coverpage> отсутствует, старый алгоритм просто брал первую попавшуюся картинку из бинарной кучи.

Я переписал фоллбэк: теперь, если явной обложки нет, Jsoup ищет первый тег <image> прямо внутри <body> книги.

Попутно всплыло неочевидное поведение Jsoup: если атрибут отсутствует, attr() возвращает пустую строку, а не null — это задокументировано, но интуитивно ожидаешь null. Из‑за этого Элвис‑операторы (?:) молча проглатывали пустую строку вместо ухода в fallback. Написал строгую обертку takeIf { it.isNotEmpty() }, и теперь обложки извлекаются безошибочно.

4. Изолированный свайп яркости в Compose

Нужно было добавить регулировку яркости свайпом по левому краю экрана. Проблема: в режиме вертикального скролла (VerticalPager) свайпер страниц перехватывает вертикальные жесты на себя.

Решение: перехватывать жест на фазе Initial — до того, как пейджер успевает его обработать. Если касание началось в левых 15% ширины экрана, событие забирается себе и до пейджера не доходит.

Помимо этого в релизе 1.3.0:

  • Добавлен полноэкранный просмотрщик иллюстраций с pinch‑to‑zoom (на основе detectTransformGestures).

  • Написан собственный File Picker со сканированием вложенных папок и извлечением книг прямо из ZIP‑архивов на лету.

  • Добавлен поворот страниц для PDF с сохранением состояния в SharedPreferences.

  • Разделен UI верхнего меню: закладки теперь можно переименовывать, а тап по номеру страницы открывает быстрый переход.

  • Добавлен множественный выбор в библиотеке (массовое добавление на полки/удаление/скрытие).

Ссылки:

Теги:
Всего голосов 1: ↑1 и ↓0+3
Комментарии1

🤗 Привет всем!

😻 Обновление HalChat for Android: v1.0.2 (Vote or don't vote)

Что нового?
😌Теперь есть описание чатов.
🤖 Добавлено обновление данных чата.
😉 Добавлены метаданные файлов HD - мгновенное определение что за файл или какие размеры изображения.
😇 Доступны опросы/голосования в чатах.

Что исправлено?
🤓 Если получение или расшифровка пароля была прервана, то теперь он запросит заново, и пароль будет доступен в любом случае.
🫢 Теперь при получении пароля от чата, в списке чатов сообщения будут расшифроваться.
😎 Исправлена система файлов в чате, они будут отображаться всегда и в том числе изображения (исправлен баг).

До новых встреч!

Google Play: https://play.google.com/store/apps/details?id=halwarsing.net.halchatandroid
RuStore: https://www.rustore.ru/catalog/app/halwarsing.net.halchatandroid
HalChat Web: https://halch.at/c/tZgWWT
GitHub: https://github.com/halwarsing/HalChat/tree/dev

Теги:
Всего голосов 1: ↑1 и ↓0+3
Комментарии2

Ближайшие события

Собеседование. Часть 3: Магия коллекций в Kotlin — от лямбд до скрытых аллокаций

В прошлых частях мы препарировали алгоритмы и заглянули под капот хэш-таблиц. Сегодня поговорим о том, за что разработчики так искренне любят Kotlin — о коллекциях.

На собеседованиях этот блок вопросов — мой любимый детектор. Он отлично показывает, умеет ли человек отличать красивый синтаксический сахар от суровой реальности JVM.

Уровень 1: Синтаксический сахар и интерфейсы

Я спрашиваю: «В чем фундаментальная разница между List и MutableList в Kotlin?» Ожидаемый ответ: Kotlin изящно разделил интерфейсы на читаемые (read-only) и изменяемые. У List просто нет методов add или remove. Это спасает нас от случайных мутаций состояния, особенно когда мы гоняем данные в реактивном UI.

Далее переходим к функциям-расширениям. Кандидат пишет классическую цепочку: users.filter { it.age > 18 }.map { it.name }

Выглядит чисто. Здесь же я подкидываю вопрос про reduce и fold. Оба метода сворачивают коллекцию, но если кандидат бездумно использует reduce, я с легкой улыбкой спрашиваю: «А что будет, если список окажется пустым?» Будет больно и UnsupportedOperationException. Поэтому fold с его стартовым значением — выбор тех, кто хочет спать спокойно.

Уровень 2: Срываем покровы компилятора

Когда кандидат уверенно жонглирует лямбдами, пора заглянуть под капот. Я задаю вопрос: «А что конкретно создается в памяти, когда ты вызываешь listOf(1, 2, 3) или mapOf(1 to "A")

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

  • mapOf() под капотом вернет java.util.LinkedHashMap. Но! Контракт Map не гарантирует сохранение порядка. Если вам критически важен порядок вставки, не надейтесь на реализацию «под капотом» — пишите linkedMapOf() явно, иначе в один прекрасный день обновление языка сломает вам логику.

  • listOf(1, 2, 3) вернет не обычный java.util.ArrayList. Он вернет внутренний класс java.util.Arrays$ArrayList. И разница тут колоссальная. Это fixed-size обертка над массивом. Если любитель хардкора решит сделать (list as MutableList).add(4), он моментально получит краш в рантайме.

Далее вопрос на засыпку: «Если мы в цикле вызываем filter { ... }, не убиваем ли мы Garbage Collector созданием анонимных классов для лямбд?» Отличный кандидат вспомнит про модификатор inline. Компилятор физически вставляет тело функции в место вызова, поэтому аллокации объектов лямбд не происходит.

Уровень 3: Экспертный взгляд и ловушка Sequences

Вроде бы inline нас спас? И да, и нет. Тут начинается территория архитектуры и производительности. Я возвращаю кандидата к его коду: users.filter { it.age > 18 }.map { it.name }

«Модификатор inline спас нас от лямбд, — говорю я. — Но что будет, если в списке 100 000 юзеров? Что произойдет с памятью?»

Эксперт должен увидеть угрозу: каждая стандартная функция (filter, map) создает новую промежуточную коллекцию. Сначала создастся список из 50 000 взрослых юзеров, а потом еще один из 50 000 их имен. Это колоссальная аллокация памяти.

«Как этого избежать?» Ответ: использовать Sequencesusers.asSequence().filter {...}.map {...}.toList(). Последовательности работают лениво, протаскивая каждый элемент по цепочке поштучно, без создания огромных временных списков.

Финальная ловушка. Я спрашиваю: «Значит ли это, что нужно использовать asSequence() вообще везде?» Истинный эксперт скажет: Нет. У Sequence есть свои скрытые налоги: создание объектов-оберток (TransformingSequence, FilteringSequence) и накладные расходы на виртуальные вызовы next()/hasNext() для каждого элемента. На коротких списках обычная цепочка filter/map отработает быстрее. Бенчмарки показывают, что Sequence начинает выигрывать только на объемах примерно от 1 000 элементов (в зависимости от тяжести цепочки). Не стоит заниматься преждевременной оптимизацией там, где она не нужна.

Резюме

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

Теги:
Всего голосов 5: ↑5 и ↓0+7
Комментарии0

Помогите, кто чем может. Яндекс пробил дно

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

В связи с тем, что с продукцией Apple в России в последнее время ситуация постоянно ухудшается, планирую перейти на Android. Нашел подходящую модель на Яндекс.Маркете смартфон Conquest F3 Plus. Одна проблема — в этой модели экран еще меньше, чем у меня сейчас. Значит, есть риск, что приложения, которые глючили на старом смартфоне, вообще не смогут работать на новом.

С данным вопросом я обратился в поддержку Яндекса. Я был уверен, что получу точный ответ, будет работать приложение Яндекс.Go на интересующем меня устройстве или не будет. Ведь что может быть проще? Любой разработчик может, даже если не знает точно, в эмуляторе задать указанное разрешение экрана и прогнать тесты.

Ответом поддержки я был, мягко говоря, ошарашен. Ниже привожу текст нашего диалога со скринами.

Здравствуйте! Будет ли работать ваше приложение на вот такой модели смартфона?
https://market.yandex.ru/cc/9aPY2a
Разрешение экрана 540x1200.

Данную информацию вы можете уточнить в магазине приложений, из которого вы хотите скачать наше приложение

Я хочу купить новый смартфон, но мне нужно знать, будут ли работать нужные приложения. Ваше приложение очень плохо работает на экране с разрешением 1344x750. Хоть и работает. Какое разрешение поддерживает yandex.go? Будет ли оно работать на экране 540x200?

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

Что значит, не получится? Напишите разработчикам, и они вам скажут.

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

Какой магазин?

Магазин приложений вашего устройства

Итак, поддержка Яндекс.Go не смогла ответить на вопрос о системных требованиях собственного приложения. Неожиданно. У меня нет ни малейших идей, как такое стало возможно.

В связи с этим я решил обратиться за помощью к товарищам по отрасли. Может, кто-нибудь из читателей Хабра пробовал ставить Яндекс.Go на Android 12 с разрешением экрана 540x1200. Нормально работает?

Теги:
Всего голосов 8: ↑4 и ↓4+2
Комментарии29

Восстановление аккаунта в эфемерном мессенджере, не ломая приватность? Легко!

RCQ это анонимный мессенджер: без телефона и почты, история только на устройстве, сервер хранит минимум. Цена такой модели: потерял телефон, и аккаунт (сам UIN, твоя личность в сети) потерян навсегда. Это отпугивало тех, кому нужен постоянный аккаунт. Мы добавили фразу восстановления и постарались не превратить приватный мессенджер в обычный облачный.

Сразу: Android-клиент теперь в проде, фраза в нём есть. Ссылка в конце.

Аккаунт это ключи

Логина и пароля нет. Аккаунт это пара ключей: X25519 (шифрование) и Ed25519 (подпись). UIN это просто ручка на сервере, привязанная к публичному ключу. Приватные ключи не покидают устройство. Отсюда: бэкап аккаунта это бэкап ключа, а восстановление это доказать серверу, что ключ у тебя.

Откуда фраза

При создании аккаунта генерируется случайный seed на 32 байта. Из него детерминированно выводятся оба ключа через HKDF-SHA256 с фиксированными info-строками:

identity_priv = HKDF-SHA256(seed, "rcq-recovery-x25519-v1", 32) signing_priv = HKDF-SHA256(seed, "rcq-recovery-ed25519-v1", 32)

Из одного seed всегда те же ключи, значит достаточно сохранить seed. Кодируем его в 24 слова по BIP39 (как в криптокошельках): 256 бит энтропии плюс 8 бит контрольной суммы, режется по 11 бит, словарь на 2048 слов. Контрольная сумма ловит опечатки.

Восстановление

На новом устройстве вводишь 24 слова:

  1. Из слов получается seed, из seed те же ключи.

  2. Клиент берёт у сервера одноразовый челлендж.

  3. Подписывает его Ed25519-ключом, шлёт подпись.

  4. Сервер проверяет подпись против публичного ключа и отдаёт UIN и токен.

Приватный ключ никуда не передаётся, пароль нигде не хранится. Это challenge-response: перехват челленджа бесполезен, он одноразовый.

Что возвращается

Возвращается личность: UIN, ключи, контакты, группы, ожидающие сообщения. НЕ возвращается локальная история переписки, она только на устройстве (зашифрованный бэкап истории это отдельная фича на будущее). Активные ratchet-сессии (forward secrecy) сбрасываются, собеседники видят смену ключа, как в Signal.

Почему это не ломает приватность

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

Баланс такой: seed есть у каждого нового аккаунта, но воспользоваться им (записать фразу) это твой осознанный выбор, не навязанный. Плюс фразу прячем за подтверждением (+PIN), чтобы её не выгребли с разблокированного на минуту телефона.

Кросс-платформенно

Деривация и словарь одинаковы на Android и iOS. Мы прогнали обе реализации (CryptoKit и наш Android-стек) на одном seed и сравнили побайтово: одинаковые ключи, одинаковые слова. Фразу с Android можно ввести на iPhone и наоборот.

Границы

  • История чатов пока не восстанавливается.

  • Аккаунты, созданные до фичи, фразы не имеют (их ключи не из seed), для них будет экспорт сырого ключа (но для этого мы и в бете, так что на релизе такого не случится).

  • Это не мультидевайс: ввести фразу на втором телефоне можно, но это переезд, а не одновременная работа, ratchet-сессии разойдутся.

Код клиента открыт, Android в проде. Будем рады разбору, особенно по криптографии.

Скачать APK (Alpha)/iOS TF (Beta): https://rcq.app/
GH: https://github.com/rcq-messenger

Теги:
Всего голосов 9: ↑8 и ↓1+9
Комментарии4

Собеседование. Часть 2: От структур данных до магии Load Factor и data class’ов ​

В прошлом выпуске мы выяснили, как простая задача на разворот массива вскрывает понимание вычислительной сложности. Сегодня мы поговорим о структурах данных и специфике языка программирования. ​

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

Уровень 1: Начинающие специалисты и базовые структуры

​Начинаем с разминки. Я прошу объяснить разницу между Array, ArrayList и LinkedList. Это фундамент, без которого сложно двигаться дальше. ​Если кандидат понимает структурную разницу, я спрашиваю про скорость доступа к произвольному элементу (Time Complexity):

  • Array (Массив): Непрерывный блок памяти фиксированного размера. Чтение по индексу происходит мгновенно, вычислительная сложность O(1).

  • ​ArrayList: Умная обёртка над массивом, умеющая динамически расширяться (путем копирования элементов в новый массив при переполнении). Доступ по индексу также O(1). ​

  • LinkedList (Связный список): Элементы разбросаны в памяти, каждый узел знает только о своем соседе. Чтобы найти нужный элемент, нужно последовательно пройти по цепочке. Скорость доступа — O(N). ​

Если специалист отвечает на это уверенно, значит, базовое понимание Computer Science заложено верно. ​

Уровень 2: Переход к Kotlin

​Дальше я меняю плоскость и перехожу к синтаксису. Вопрос: «В чем разница между обычным class и data class в Kotlin?» ​Ожидаемый ответ на этом этапе: data class из коробки генерирует полезные методы, избавляя разработчика от написания бойлерплейта. Компилятор самостоятельно создает equals(), hashCode(), toString(), метод copy() и componentN() для деструктуризации.

Затем я прошу уточнить целевое использование. Кандидат должен пояснить, что data class нужен для хранения данных (например, моделей из сети) или состояния UI. Главная особенность в том, что объекты data class’ов сравниваются по содержимому (значениям полей), а не по ссылке в памяти. ​

Уровень 3: Углубленное понимание платформы ​А теперь самое интересное — мы сплетаем теорию структур данных и специфику Kotlin воедино. ​

Я спрашиваю: «Отлично, data class переопределяет метод hashCode(). А для чего именно он нужен? Как он используется под капотом?» ​Здесь требуется рассказать про принципы работы HashMap или HashSet: ​Метод hashCode() возвращает число, определяющее, в какую «корзину» (bucket) внутреннего массива попадет объект. ​Если хэши совпадают (коллизия), применяется метод equals(), чтобы найти точный объект внутри этой корзины. ​

И: «Что такое Load Factor в хэш-таблице? И что произойдет, если мы установим его слишком высоким (например, 0.95)?» ​

Правильный ответ: Load Factor (по умолчанию 0.75) — это метрика того, насколько может быть заполнена таблица до автоматического увеличения её размера (rehash). Если установить высокое значение, корзины переполнятся. Возникнет лавина коллизий. В результате хэш-таблица внутри одной корзины деградирует в LinkedList! Скорость доступа падает до линейной O(N) (или O(log N) для деревьев в новых версиях), лишая структуру её главного преимущества. ​

Резюме: ​Алгоритмы и структуры данных — это, по сути, сухая теория. Для меня как для интервьюера гораздо важнее то, как человек применяет её на практике. ​

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

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

Теги:
Всего голосов 1: ↑1 и ↓0+3
Комментарии0

Собеседование. Часть 1: Как простая задача на разворот массива вскрывает понимание Computer Science

За свою карьеру я провел сотни технических собеседований на самые разные грейды — от джунов до системных архитекторов. И делал я это в разных локациях: в России, Европе и США. Процессы найма везде немного отличаются, но есть подходы, которые работают безотказно в любой точке земного шара.

Многие кандидаты боятся алгоритмических секций, ожидая зубодробительных задач с LeetCode. Но моя цель — не завалить, а понять инженерное мышление. Поэтому я часто начинаю с элементарной задачи: дан массив чисел, его нужно отзеркалить (перезаписать в обратном порядке).

Эта задача — идеальная «лесенка», раскрывающая реальный уровень инженера. Давайте пройдем по ней вместе.

Шаг 1: Уровень Джуниора. Просто сделай это

От джуна я жду умения перевести бизнес-требование в код. Самый очевидный способ решить задачу в лоб — создать второй массив и скопировать туда элементы с конца.

fun reverseArrayNaive(arr: IntArray): IntArray {
    val result = IntArray(arr.size)
    for (i in arr.indices) {
        result[i] = arr[arr.size - 1 - i]
    }
    return result
}

Если код написан без ошибок с индексами — отлично. Если человек путается и не может подойти к задаче — для меня это красный флаг. Если код готов, я задаю первый вопрос: «Какова вычислительная сложность?». Ожидаемый ответ: сложность O(N) по времени, так как мы проходим массив один раз.

Шаг 2: Уровень Мидла. Экономим память

Переходим на следующий уровень. Я спрашиваю: «А что со сложностью по памяти?». Кандидат логично отвечает, что раз мы создаем массив того же размера, сложность — O(N).

Усложняем задачу: «Представь устройство с жестким лимитом ресурсов. Нам нельзя выделять память под второй массив. Как переписать алгоритм, чтобы сложность по памяти стала O(1)

Продвинутый разработчик сразу предложит in-place решение: менять элементы местами с начала и с конца.

fun reverseArrayInPlace(arr: IntArray) {
    var left = 0
    var right = arr.size - 1
    
    while (left < right) {
        val temp = arr[left]
        arr[left] = arr[right]
        arr[right] = temp
        left++
        right--
    }
}

Шаг 3: Уровень Синьора. Психологическая ловушка

Если in-place вариант написан, я подкидываю вопрос с подвохом: «В первом варианте цикл делал N итераций. Во втором указатели встретились посередине, то есть цикл выполнился N/2 раз. Уменьшилась ли вычислительная сложность по времени?»

И тут многие радостно отвечают: «Да! Мы сократили операции в два раза, код стал быстрее!». И это ловушка.

Правильный ответ: Нет, сложность осталась O(N). Давайте посчитаем атомарные операции присваивания:

  1. В наивном подходе мы делали 1 присваивание за итерацию. Цикл шел N раз. Итого: N операций.

  2. В in-place подходе мы делаем swap. Это три операции (temp = a, a = b, b = temp). Цикл идет N/2 раз. Умножаем 3 на N/2 и получаем 1.5 × N операций!

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

За 10 минут с помощью одной задачи мы проверили:

  1. Умение писать циклы (Джун).

  2. Понимание Big O и расхода памяти (Мидл).

  3. Понимание реальной цены оптимизаций (Синьор).

Это не спортивное программирование с хитрыми математическими трюками. Это проверка базовой инженерной гигиены.

Теги:
Всего голосов 8: ↑6 и ↓2+6
Комментарии7

TalkBack в 2ГИС

Уже несколько лет мы поддерживаем VoiceOver на iOS — это был сложный и многоступенчатый путь к доступности приложения. После релиза мы увидели, что это реально работает, и людям с нарушением зрения стало проще пользоваться 2ГИС. В этом году мы решили, что пришло время для Android. 

Под капотом — собственный мини-фреймворк

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

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

2ГИС устроен немного иначе: наш интерфейс написан на Qt Quick и с точки зрения Android это один пустой View. Никаких кнопок, списков и текстовых полей TalkBack «внутри» не видит. Сам Qt предоставляет кроссплатформенный API для работы со службами доступности из Qt Quick, но его платформенная интеграция для Android на данный момент поддерживает весьма ограниченный набор методов, которого категорически не хватает для разработки по-настоящему удобных и доступных приложений.

Поэтому мы решили написать свой мини-фреймворк для работы со службами доступности Android из Qt Quick. Основную архитектуру мы подсмотрели в Qt:

  • визуальные элементы в Qt Quick размечаются через attached-свойства;

  • из этой разметки получается дерево accessibility-узлов, управляемое из C++;

  • это дерево accessibility-узлов предоставляется службам доступности Android через virtual view hierarchy посредством JNI.

При этом мы добавили поддержку многих недостающих API из Android SDK:

  • научились работать с текстовыми полями ввода;

  • научились описывать коллекции элементов;

  • поддержали автоматическую прокрутку списков при перемещении accessibility-фокуса;

  • поддержали детализацию навигации по тексту: озвучку любого элемента можно прослушать как целиком, так и по словам или по символам.

Пользовательские сценарии

Мы честно признали, что озвучить всё приложение сразу невозможно. Поэтому сделали MVP. Теперь можно:

  • найти место и узнать актуальную информацию о нём;

  • прослушать карточку организации и быстро сориентироваться в деталях;

  • позвонить по контактному номеру прямо из карточки;

  • построить маршрут и пройти его шаг за шагом;

  • понять, какой транспорт подходит, где садиться и на какой остановке выходить.

Для этих сценариев мы разметили 555 UI‑элементов.

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

Теги:
Всего голосов 4: ↑3 и ↓1+2
Комментарии0

Критический успех

4 июня собираемся с мобильными разработчиками в атмосфере любимых фэнтези и настольных ролевых игр — на Alfa Mobile D&D party. Впереди приключение для истинных авантюристов: объединяйтесь в отряды и открывайте секреты башни.

Друиды поделятся мудростью:

 С техническим лидером Android-разработки Виталием Перятиным обсудим, что на самом деле под капотом у MCP. Спойлер: всё просто

 С ведущим iOS-разработчиком Петросом Тепояном погрузимся в мир ИИ-разработки и приключений, или Туда и обратно

Завершим игру вечеринкой. Советуем подумать над образом своего персонажа: за 3 лучших подарим подарки!

Где: в секретном баре в Москве. Локацию пришлём с соколом в письме.

Регистрируйтесь на приключение!

Теги:
Всего голосов 2: ↑0 и ↓2-2
Комментарии0

Как сделать мобильное приложение для УК, которое не удалят?

CTO Doubletapp Никита Анчутин выступил на «Неспальном митапе» от Сделка.рф — неформальной встрече девелоперов и цифровизаторов. Никита рассказал, как сделать приложение для управляющей компании, которым жильцы реально будут пользоваться, а не удалят сразу после установки.

Часто приложения УК не приживаются: жильцы ими не пользуются, а УК не получают обратной связи. Причина — разрыв между ожиданиями пользователей и видением заказчика. В видео — инструкция, как создать цифровой инструмент, который станет качественным посредником между сторонами:

  • поможет УК слышать жильцов и оперативно решать проблемы;

  • даст жителям удобный доступ к услугам и каналам коммуникации;

  • объединит интересы обеих сторон в одном интерфейсе.

В видео — разбор: как совместить потребности жильцов и УК; какие функции критически важны для обеих сторон; каких ошибок заказчикам стоит избегать при постановке задач.

Будет полезно девелоперам, продуктовым менеджерам, представителям УК и застройщиков, UX/UI‑дизайнерам и IT‑руководителям.

Doubletapp — IT‑компания, разрабатывающая мобильные приложения с 2015 года. Мы создаём эффективные инструменты для бизнеса и удобные решения для пользователей.

Теги:
Всего голосов 2: ↑1 и ↓10
Комментарии0

Инструменты, которые упрощают iOS-разработку

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

Ринат, iOS‑разработчик Naumen, рассказал об инструментах, которые помогают ему решать такие задачи и упрощать повседневную работу.

  • Periphery: поиск мертвого кода в Swift‑проектах

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

Periphery помогает находить такие места и наводить порядок перед изменениями в кодовой базе.

Как использую

Запускаю Periphery перед рефакторингом — например, когда нужно обновить модуль профиля с сотнями файлов.

periphery scan

После сканирования инструмент показывает классы, методы, свойства, enum cases, imports и другие элементы. Так проще понять, что действительно участвует в работе приложения.

Что важно знать: результаты всегда нужно проверять вручную. Инструмент может не учитывать динамические вызовы, reflection, Objective-C runtime, storyboard-ссылки или код, который используется через строки.

  • Network Link Conditioner: тестирование слабой сети

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

Network Link Conditioner — инструмент от Apple, который помогает эмулировать разные сетевые условия. Например, индикатор загрузки крутится бесконечно, повторная попытка не срабатывает, время ожидания слишком короткое, а пользователь не получает понятного сообщения об ошибке.

Как использую

Обычно проверяю сценарии авторизации, оплаты, загрузки медиа и офлайн‑режимы. Для этого включаю профиль вроде плохого 3G, высокой задержки или потери пакетов и смотрю, как приложение ведет себя в нестабильной сети.

Что важно знать: проверять стоит не только низкую скорость интернета, но и нестабильность сети. А еще важно не забывать выключать Conditioner после проверки :)

  • just: короткие команды вместо длинных инструкций

В iOS‑проектах быстро накапливаются команды, которые приходится запускать постоянно: тесты, форматирование, генерация ресурсов. Со временем это превращается либо в огромный онбординг‑документ, либо в постоянный поиск нужной команды в документации.

just собирает основные сценарии работы в одном месте и запускает их через короткие понятные команды. В итоге justfile становится чем‑то вроде живой документации проекта.

Как использую

Чтобы каждый раз не вспоминать синтаксис, храню основные сценарии работы в justfile.

test:
    xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'
format:
    swiftformat .
    swiftlint
clean:
    rm -rf ~/Library/Developer/Xcode/DerivedData

После этого вместо длинных команд достаточно написать:

just test
just format
just clean

Что важно знать: just не заменяет CI, Makefile или build system. Это скорее удобный слой для повседневных команд. Поэтому лучше держать justfile простым и не превращать его в большой набор скриптов.

  • Mint: фиксация версий CLI-инструментов на Swift

Когда у разработчиков разные версии линтеров, форматтеров и других CLI‑инструментов, могут появиться расхождения. Mint помогает зафиксировать набор инструментов внутри проекта и сделать локальный запуск ближе к CI, чтобы у всей команды был одинаковый результат.

Как использую

Вместо глобальной установки SwiftLint, SwiftFormat, XcodeGen или других CLI‑инструментов можно хранить версии в Mintfile и запускать их одинаково у всех разработчиков.

mint run realm/SwiftLint
mint run nicklockwood/SwiftFormat

Что важно знать: Mint полезен именно для Swift CLI-пакетов. Для Ruby-gems, Node.js-инструментов или системных утилит понадобятся другие менеджеры. Также важно кэшировать установленные бинарные файлы в CI, иначе сборки могут тратить лишнее время на установку инструментов.

Теги:
Рейтинг0
Комментарии0

Save the date: встречаемся 22 апреля на iOS Meetup Wildberries & Russ

22 апреля в 19:00 мск приглашаем на iOS-митап. В программе три технических доклада и нетворкинг с инженерами, которые ежедневно строят мобильную разработку в Wildberries & Russ. Поговорим про автоматизацию релизного процесса, масштабируемое UI-тестирование и тонкости работы с файловой системой iOS.

Регистрация

Доклады:

— Автоматизация релизов в Wildberries | Севастьян Жуков, Deploy Lab Team Lead

Как команда с нуля создала инструмент для управления релизным процессом мобильного приложения и масштабировала его на другие продукты компании. Разберём этапы автоматизации и работу с App Store API: управление релизами и отслеживание их статуса.

— UI-тестирование приложения Wildberries | Руслан Колчаков, iOS TestLab Lead и Валерий Карачаков, iOS TestLab Dev

Руслан расскажет про вызовы при организации тестирования, инфраструктуру и метрики здоровья TestLab. Валерий дополнит докладом про распределённое UI-тестирование на динамически формируемом кластере раннеров: как избежать простоев, эффективно утилизировать ресурсы и ускорить тестирование.

— Работа с файловой системой на iOS | Александр Игнатьев, iOS-разработчик команды Асто

Разберём нюансы работы с файлами, структуру iOS Sandbox и App Group как способ выйти за её пределы.

⏹️Формат: офлайн в Москве + онлайн-трансляция

Регистрация

Теги:
Рейтинг0
Комментарии0

От хакатонного эксперимента до релиза, или как появился параллельный режим в CarPlay

Раньше при подключении CarPlay пользователи видели в приложении 2ГИС на телефоне «заглушку» — почти пустой экран. И наш iOS‑разработчик Ваня задумался: «Почему бы не добавить полезности?»

Идея родилась на внутреннем хакатоне. Он решил не переносить интерфейс целиком, а разделить роли между устройствами. Телефон — для действий. CarPlay — для результата.

Собрал прототип, а затем команда подхватила инициативу. И это одна из самых быстрых задач, которая дошла до релиза.

Все действия выполняются на телефоне и сразу отображаются на экране в машине. Без переходов, без ожидания и без разрыва между устройствами
Все действия выполняются на телефоне и сразу отображаются на экране в машине. Без переходов, без ожидания и без разрыва между устройствами

Это интересно, потому что: 

  • новый сценарий для автомобилистов: теперь можно взаимодействовать с приложением на телефоне, пока навигация идёт в CarPlay; 

  • красивый обход архитектурного ограничения; 

  • инженерная инициатива, которая с хакатона дошла до прода.

Теги:
Всего голосов 5: ↑5 и ↓0+6
Комментарии0

Как стать IOS-разработчиком?

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

Если нравится экосистема Apple и хочется работать в закрытой, но при этом цельной среде — попробуйте разработку под IOS. На Хабр Карьере как раз есть множество учебных программ по этому направлению, а ниже — подборка ключевых инструментов "яблочного" разработчика.

SWIFT. Основной язык программирования для iOS.

Xcode. Официальная среда разработки от Apple.

CocoaPods.  Менеджер зависимостей для подключения библиотек.

Realm. Локальная база для хранения данных в приложении.

GCD. Технология для работы с многопоточностью.

UIKit. Фреймворк для создания интерфейсов приложений.

Начать учиться можно здесь

Теги:
Всего голосов 3: ↑2 и ↓1+1
Комментарии0

Как стать Android-разработчиком?

Войти в Android-разработку проще, чем кажется: начать можно с освоения базовых инструментов, а затем постепенно углубляться и закреплять знания на практике. Главное — двигаться последовательно и не пытаться охватить всё сразу.

Сегодня мы собрали подборку для тех, кто хочет стать Android-разработчиком и разобраться в основе профессии. А на Хабр Карьере есть все, чтобы выстроить понятный маршрут: сотни учебных программ — от базовых знаний до практики и первых проектов.

  • Java. Базовый язык программирования для Android

  • Kotlin. Кроссплатформенный язык программирования

  • Android Studio. Среда разработки (IDE) для приложений

  • Retrofit2. Типобезопасный HTTP‑клиент

  • Mockito. Фреймворк для модульного тестирования

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

Теги:
Всего голосов 3: ↑3 и ↓0+5
Комментарии0

Сегодня с 10 часов адрес https://api.telegram.org/bot недоступен. Этот адрес взаимодействия ботов с платформой телеграмм. Как итог телеграмм боты "легли".  Если точнее, телеграмм вызывает обработчик, но обратно в телеграмм отправить ничего нельзя.

Пока те боты, которые получают из телеграмм и отправляют ещё живут..

Одно из решений: использование приватных проски.

Теги:
Всего голосов 2: ↑2 и ↓0+3
Комментарии3

Выпустили мобильное приложение для Интернетометра от Яндекса

Команда Yandex Infrastructure разработала приложение под iOS и Android для бесплатного сервиса Интернетометр. Как и в веб‑версии сервиса в приложении можно замерять скорость скачивания, скорость загрузки и время задержки интернет‑соединения в миллисекундах. 

В приложении доступны светлая и тёмная темы
В приложении доступны светлая и тёмная темы

Сбор информации организован с использованием сети CDN‑серверов Яндекса: для большей точности сервис опрашивает не один, а сразу несколько ближайших серверов. Ежемесячно Интернетометром пользуются 5,5 миллионов человек — в среднем они запускают 18 миллионов измерений. 

Сервис предоставляет ключевую информацию о подключении: IP‑адрес, версию браузера, разрешение экрана и так далее. В будущем в приложении будет доступен расширенный режим измерений: он будет особенно полезен для технических специалистов, которые настраивают интернет‑соединение. Также у провайдеров проводной и беспроводной связи появится личный кабинет, где они смогут отслеживать замеры в зоне своего покрытия.

Теги:
Всего голосов 9: ↑8 и ↓1+7
Комментарии2

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

12 марта 20:00
>> Профессиональные модульные тесты в Android: как тесты улучшают код
Открытый вебинар курса «Android-разработчик. Продвинутый уровень»
Урок о том, как писать в Android осмысленные модульные тесты для ViewModel, репозиториев и бизнес-логики, чтобы они не маскировали проблемы, а реально улучшали архитектуру и поддержку кода. Записаться на урок

18 марта 20:00
>> Пишем простой проигрыватель на SwiftUI
Открытый вебинар курса «IOS-разработчик»
Соберете на SwiftUI простой медиапроигрыватель с интерактивным интерфейсом, освоите работу с локальными аудио- и видеофайлами в iOS и наметите путь к интеграции внешних сервисов. Записаться на урок

19 марта 20:00
>> Современная архитектура приложения и внедрение зависимостей
Открытый вебинар курса «Android-разработчик. Продвинутый уровень»
Разберемся, как выстроить Android-приложение на основе чистой архитектуры, связать слои через MVVM и настроить внедрение зависимостей с помощью Koin без лишней магии. Записаться на урок

23 марта 20:00
>> Навигация Pro-уровня в SwiftUI: как строить масштабируемые iOS-приложения без хаоса в переходах
Открытый вебинар курса «IOS-разработчик. Продвинутый уровень»
Как в SwiftUI проектировать навигацию без архитектурного хаоса: отделять переходы от интерфейса, управлять deep link и модальными экранами, строить масштабируемую структуру приложения. Записаться на урок

25 марта 20:00
>> Как писать Flutter-код так, чтобы ИИ правильно его дописывал
Открытый вебинар курса «Flutter-разработчик»
Поймете, почему искусственный интеллект ошибается при генерации Flutter-кода, и освоите приёмы, которые улучшат подсказки, повысят читаемость проекта и ускорят дальнейшую разработку. Записаться на урок

Еще больше бесплатных уроков от преподавателей курсов по всем ИТ-направлениям можно посмотреть в календаре мероприятий.

Теги:
Всего голосов 3: ↑2 и ↓1+1
Комментарии0

Новый китайский модульный смартфон из дополнительных компонентов выглядит интереснее чем то, что показывает Apple на презентации iPhone.

Теги:
Всего голосов 3: ↑2 и ↓1+1
Комментарии3

AI может вернуть TDD в мейнстрим

Долгие годы его выбирали либо фанаты дисциплины, либо команды на сверхкритичных проектах — слишком дорого. Писать тесты до кода медленно, поддерживать тестовый контур сложно, поэтому большинство команд жили по схеме: сначала код, потом «когда-нибудь допишем тесты». Но AI резко меняет экономику разработки: юнит-тесты генерируются за минуты, E2E собираются из user flow, интеграционные тесты склеиваются по контрактам. И появляется эффект, который разработчики любят больше всего — код становится не страшно менять.

Но есть важный нюанс. AI действительно отлично ускоряет тесты после разработки, но не спасает плохую архитектуру. Если система спроектирована криво — вы просто быстрее автоматизируете хаос. Поэтому всё чаще возвращаемся к идее тестов как инструмента проектирования. TDD перестаёт быть «религией» и становится способом делать контракты проще, зависимости чище, а систему — слабосвязанной.

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

Я — Мария Лещинская, руковожу тестированием в Surf. Мы много экспериментируем с AI в разработке, тестировании и процессах — и регулярно делимся инсайтами из практики.

Если вам интересно, как меняется разработка прямо сейчас — подписывайтесь и читайте больше материалов от экспертов Surf на нашем Телеграм-канале «Директорат Surf обсуждает». Впереди ещё много практических наблюдений и кейсов с реальными результатами. Ничего не скрываем — рассказываем как есть.

Теги:
Всего голосов 5: ↑1 и ↓4-1
Комментарии0

Разработчик на iOS получает по $5 млн каждый месяц на 24 ИИ‑приложениях в App Store. В реальности это одно приложение в разных обёртках: распознавание камней, монет, древесины и даже звёзд. Фотографии пользователей по API передаются на серверы OpenAI, после чего ChatGPT идентифицирует предмет.

Теги:
Всего голосов 4: ↑3 и ↓1+2
Комментарии2

Ахиллесова пята SharedPreferences

Статья про то, о чём не спрашивают на собесeдованиях и не рассказывают на курсах по Android-разработке — о неявной особенности Android, которая влияет на деградацию производительности и приводит к невоспроизводимым ANR в вашем приложении.

SharedPreferences часто используют «по привычке» — сохранить токен, флажок, пару строк. Но в какой-то момент это начинает тормозить интерфейс и даже приводить к ANR, особенно если запись/чтение происходит не там и не тогда, где вы ожидаете. Автор делится измерениями производительности, показывает, как деградация превращается в потерю кадров при переходах между экранами, а затем сравнивает варианты.

Ахиллесова пята SharedPreferences и стоит ли внедрять Datastore как альтернативу
В этой статье я расскажу то, о чём не спрашивают на собесeдованиях и не рассказывают на курсах по An...
habr.com

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

Читайте статью «Ахиллесова пята SharedPreferences и стоит ли внедрять Datastore как альтернативу»

Теги:
Рейтинг0
Комментарии0

Основы работы с Helm: как упростить деплой в Kubernetes

Helm — это менеджер пакетов для Kubernetes. По сути, он делает для кластеров то же, что apt для Linux или npm для JavaScript: позволяет устанавливать приложения как готовые пакеты, а не собирать всё вручную из десятков YAML-файлов.

В основе Helm — чарт: набор шаблонов с описанием ресурсов Kubernetes. При установке создается релиз с собственной историей версий — можно обновлять приложения, отслеживать изменения и при необходимости быстро откатываться. А еще Helm объединяет десятки ресурсов в один пакет и позволяет переиспользовать конфигурации для разных окружений через values.yaml.

В блоге разобрали установку Helm, основные команды, работу с репозиториями и релизами, проверку чартов перед деплоем, управление зависимостями и откаты. Читайте на сайте Рег.облака.

Теги:
Всего голосов 5: ↑3 и ↓2+1
Комментарии0

SpaceWeb объединил управление хостингом, VPS и доменами в одном мобильном приложении

SpaceWeb перезапустил мобильное приложение и перевел его на технологию Progressive Web App (PWA). Теперь все ключевые функции управления услугами доступны в одном интерфейсе прямо со смартфона — без ограничений по функциональности.

Приложение полностью повторяет возможности веб-панели управления. Пользователи могут заказывать и контролировать хостинг, VPS/VDS и облачные сервисы, управлять доменами, DNS и SSL/TLS-сертификатами, отслеживать баланс и нагрузку, настраивать доступы. Также доступны пополнение счёта, автоплатежи и участие в партнерской программе.

Переход на PWA позволил синхронизировать обновления: все новые функции, которые появляются в основной панели управления, сразу становятся доступны и в мобильной версии.

Все подробности о перезапуске — на сайте SpaceWeb.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Пользователь сделал игру про лучника, который стреляет во врагов, а управление происходит за счёт вставления и вытаскивания зарядного кабеля из разъёма при подключённом блоке питания. Никаких кнопок, тачскрина и свайпов — только провод и порт.

Теги:
Всего голосов 4: ↑3 и ↓1+2
Комментарии7

Превращаем обои на iPhone в стильный календарь — он показывает текущую дату на и каждую ночь обновляется. При этом не нужны сторонние приложения — хватит встроенного приложения «Команды».

  • Открываем сайт проекта и выбираем модель iPhone, стиль оформления, цветовую схему и часовой пояс;

  • Копируем ссылку, которую сгенерирует сайт;

  • Заходим в приложение «Команды», открываем вкладку «Автоматизация» внизу и жмём на знак «+»;

  • Создаём новую автоматизацию по времени суток: выставляем 00:01, выбираем «Немедленный запуск» и отключаем уведомления;

  • Добавляем действие «Получить содержимое URL» и вставляем туда скопированную ссылку с сайта;

  • Делаем второе действие «Установить фото как обои», выбираем только «Экран блокировки» (снимите галочку с домашнего экрана);

  • Разворачиваем настройки действия и отключаем «Показать окно просмотра»;

  • Нажмите «Play» внизу справа, чтобы проверить команду — обои должны смениться мгновенно.

  • Бонусом внизу будет отображаться прогресс года, чтобы вам удобнее было переживать из-за того, что до Нового года осталось 348 дней.

Теги:
Всего голосов 3: ↑0 и ↓3-3
Комментарии0

Клиент YouTube для Android под названием Download YT PRO весит всего 60 кБ (48 кБ в архиве). Приложение не требует Root-прав, убирает рекламу, даже спонсорскую. Видео не ставится на паузу, если свернуть приложение или заблокировать экран. Есть встроенный загрузчик видео и шортсов. Добавлен ИИ Gemini, который сразу сделает саммари даже часовых лекций и выдаст факты и советы по контенту.

Теги:
Всего голосов 3: ↑3 и ↓0+3
Комментарии2

Я целую неделю отлаживал свой блок GPU, в котором с мая месяца сделал новый подблок, которого не было у AMD, у которого Самсунг лицензировал технологию RDNA. Моим единственным желанием на Новый Год было чтобы прошел тест. Так как баг проявлялся только на подсистеме, тест которой шел 6 часов в софтвере и 8 часов на эмуляторе, после каждого изменения нужно было ждать это время. И вот я проснулся 1 января и тест прошел. Это значит, что с высокой вероятностью этот новый подблок моего дизайна войдет в телефоны Самсунг 2028 года. Все, сегодня можно не работать, а идти в лес или редактировать статью, которую у меня приняли на крутую конференцию. С Новым Годом!

Теги:
Всего голосов 24: ↑23 и ↓1+28
Комментарии11

Где изучать операционные системы?

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

А у нас на Хабр Карьере как раз есть все для этого — сотни проверенных и полезных курсов по самым разным направлениям. Сегодня у нас последняя в этом году подборка — по операционкам.

Android. От основ Kotlin и архитектуры приложений до публикации в Google Play и работы над реальными проектами.

iOS. Swift и все возможности Apple, чтобы разрабатывать приложения для iPhone и iPad.

Windows. Системное администрирование и работа с корпоративной инфраструктурой.

Linux. База для системных администраторов, DevOps и инженеров по безопасности.

→ Делайте полезные подарки себе и своим близким благодаря нашей витрине курсов.

Теги:
Всего голосов 2: ↑2 и ↓0+2
Комментарии0
1
23 ...