Устали от перегруженных трекеров: как в 21 год я в соло разработал беговое Android-приложение WEIRUN на Jetpack Compose, BLE и Supabase
От борьбы с китайскими энергосберегайками и парсинга сырых байтов нагрудных датчиков до готового релиза без Google-сервисов. История независимого разработчика.
Большинство современных беговых приложений превратились в перегруженные комбайны.
Картина знакома каждому, кто бегает круглый год: стоишь на улице в дождь или на холодном ветру перед темповой тренировкой, пальцы замерзают, запускаешь трекер — а тебе в лицо летит баннер годовой подписки, предложение купить кроссовки, всплывающая лента чужих постов и три экрана подтверждений. Вместо быстрого нажатия «Старт» ты вынужден бороться с интерфейсом. А после ухода зарубежных сервисов из РФ ситуация стала еще веселее: танцы с бубном вокруг обходов, проблемы с оплатой и внезапные обрывы синхронизации.
Мне как разработчику и бегуну с 9-летним стажем нужен был простой, быстрый и визуально строгий инструмент: моментальный старт, точная фиксация пульсовых зон через нагрудные датчики по Bluetooth (BLE) и полное отсутствие информационного мусора.
Поняв, что идеала на рынке нет, я решил написать свой беговой Android-трекер — WEIRUN — в одиночку.
Ниже история того, как за 8 месяцев проект вырос из чистого экрана Android Studio в боевой софт: с какими граблями я столкнулся при работе с Bluetooth SIG, почему Android безжалостно глушит GPS на 10-м километре и как в соло закрыть бэкенд без миллионных бюджетов.
Почему нативный Android, а не кроссплатформа?
Когда заходит речь об MVP, многие сразу тянутся к Flutter или React Native: мол, один код на две платформы, экономия времени. Но когда проект завязан на:
- Непрерывную работу Foreground Service с высокоточным сбором GPS;
- Постоянный опрос Bluetooth Low Energy (BLE);
- Агрессивную политику убийства фоновых процессов китайскими оболочками (MIUI, HyperOS, ColorOS, EMUI);
— любая абстракция кроссплатформы начинает сыпаться. Приходится писать такое количество нативных бриджей на Kotlin, что смысл кроссплатформы теряется.
Поэтому стек был выбран бескомпромиссно нативный:
- Язык: Kotlin
- UI: Jetpack Compose (Single-Activity, декларативный UI)
- Архитектура: Clean Architecture + MVI/MVVM на StateFlow и SharedFlow
- Фоновые службы: Foreground Service + кастомные уведомления
- Датчики: Android BLE API (Bluetooth Low Energy)
- Бэкенд: Supabase (PostgreSQL, Row Level Security, Auth)
Грабли №1: Подключение нагрудных пульсометров (BLE) и парсинг битов
Для атлета, который тренируется по пульсовым зонам (а не бегает в анаэробном угаре на каждом кроссе), подключение нагрудного датчика (Polar, Garmin, CooSpo, Magene) — критическая функция. Встроенные оптические датчики на смартфонах и дешевых браслетах безбожно врут при ускорениях.
Все спортивные пульсометры работают по стандартному профилю Bluetooth SIG: Heart Rate Service (0x180D) и характеристике Heart Rate Measurement (0x2A37). Казалось бы — подключайся и читай. Но в реальности сырые данные прилетают массивом байт ByteArray, где каждый бит имеет значение:
- Первый байт — сервисные флаги.
- Если нулевой бит флага равен 0, пульс передается в формате UINT8 (1 байт, значение до 255 уд/мин).
- Если флаг равен 1, пульс летит в UINT16 (2 байта). Если не реализовать эту ветку, то на пиковом ускорении при пульсе выше 255 (или при сбое датчика) приложение просто упадет с IndexOutOfBoundsException прямо во время тренировки.
- Следующие биты определяют, есть ли в пакете данные о контакте с кожей, потраченной энергии и RR-интервалах (вариабельность сердечного ритма).
Пришлось написать собственный надежный парсер, который на лету декодирует битовые маски и раскладывает пакет на чистую модель данных с учетом смещения байтов (offset):
В результате подключение происходит мгновенно, а данные в интерфейсе обновляются плавно и без задержек.
Грабли №2: Фоновый режим и битва с китайскими энергосберегайками
Худший кошмар любого бегуна: ты пробежал полумарафон, достаешь телефон, а трекер заснул на 3-м километре, потому что оболочка решила сэкономить 0.5% заряда батареи.
Как эта проблема была решена в WEIRUN:
- Изолированный Foreground Service: Логика тренировки вынесена в отдельный сервис с явным системным типом foregroundServiceType="location | connectedDevice". Это говорит системе Android: «Этот процесс жизненно важен, он держит связь с внешним оборудованием и пишет координаты».
- Оптимизированный Notification: Системное уведомление обновляется каждую секунду через NotificationCompat, транслируя текущий темп, дистанцию и ЧСС прямо в шторку и на Always-On Display. При этом сам Compose-экран в фоне спит и не нагружает GPU.
- Локальный буфер (Offline-First): Любые координаты и пульсовые точки сначала пишутся пачками в локальную SQLite (Room). Даже если телефон попал в глухую зону без связи или сеть упала — ни один метр тренировки не потеряется. Синхронизация с сервером происходит пачками после восстановления коннекта.
Грабли №3: Почему не свой бэкенд на Ktor/Spring, а Supabase?
Когда ты работаешь в соло, распыляться на поддержку собственного микросервисного зоопарка, настройку Kubernetes и ручные миграции баз данных — верный путь похоронить проект через 2 месяца от выгорания.
Я выбрал Supabase и ни разу не пожалел:
- Честный PostgreSQL под капотом: никаких ограничений документных баз, полноценная реляционная модель данных для аналитики тренировок.
- Row Level Security (RLS): права доступа к тренировкам настраиваются прямо на уровне таблиц базы. Физически невозможно перетереть или прочитать чужие данные, даже если кто-то попытается дернуть API напрямую.
- Бесшовная авторизация: готовая система сессий и токенов из коробки, не требующая поддержки собственного auth-сервиса.
Эстетика и геймификация: интерфейс, в котором хочется оставаться
Беговой софт не должен выглядеть как скучная бухгалтерская таблица. В дизайн WEIRUN я заложил строгую, темную эстетику с неоновыми акцентами, которая отлично читается на ярком солнце через спортивные очки и не бьет по глазам в сумерках.
- Карточка тренировки: визуализация аэробных и анаэробных зон пульса, расчет каденса, темпа и расхода калорий в один скролл.
- Награды и 3D-медали: система достижений за ключевые старты (например, стартовая медаль «Первая волна»), которые можно сразу экспортировать в сторис в один клик.
Релиз в 2026 году: жизнь без Google Play
Публикация мобильного софта в текущих реалиях для инди-разработчика из России превратилась в отдельный квест. Рассчитывать только на Google Play бессмысленно, поэтому дистрибуция сразу строилась через альтернативные каналы: RuStore, Huawei AppGallery и прямые APK-релизы.
Главный вывод: архитектуру нужно изначально проектировать без жесткой привязки к Google Play Services. Все карты, пуши и аналитика должны работать независимо, чтобы сборка запускалась на любом устройстве — от чистого AOSP до HarmonyOS.
Что дальше?
WEIRUN уже перешагнул стадию идеи: приложение стабильно работает на боевых пробежках, держит связь с нагрудниками и пишет точные треки. Впереди — расширение социального функционала, внедрение соревновательных сегментов и умной аналитики восстановления.
Пилить продукт в одиночку — это вызов, но это дает абсолютную свободу делать софт для людей, а не ради навязчивой рекламы.
Буду рад адекватной критике архитектуры, фидбеку по UI и идеям от тех, кто сам разрабатывает под Android или регулярно выходит на пробежки.
Как вам интерфейс и подход к BLE? Каких фич вам больше всего не хватает в современных спортивных трекерах? Давайте обсудим в комментариях.
Скачать можно в RuStore и AppGallery: