Разработка мобильного приложения для бегунов
GPS-трекинг в фоне на iOS может остановиться, если бегун замедлился на подъёме — iOS думает, что пользователь стоит. Решение — отключить pausesLocationUpdatesAutomatically. Но это лишь одна из десятка технических граблей, которые ждут при создании бегового приложения. За более чем 5 лет мы реализовали более 20 проектов для корпоративных беговых клубов, спортивных событий и независимых тренеров. Типовые проблемы: некорректная автопауза, потеря GPS-трека в туннелях, конфликт с энергосбережением, интеграция HealthKit/Health Connect. Мы подготовили чек-лист и готовые модули, которые сокращают время разработки на 30–40%. Свяжитесь с нами для бесплатной оценки — пришлём примеры кода и архитектуру.
Рынок беговых приложений перенасыщен: Nike Run Club, Runkeeper, Adidas Running. Новый продукт выживает за счёт специализации: корпоративные беговые клубы, приложения для конкретных событий (марафоны, трейлы), интеграция с тренерскими платформами, локальные сообщества. Готовые модули для GPS, HealthKit и Health Connect экономят до 2 недель разработки на каждую интеграцию — это снижает бюджет на $2000–$3000.
Как GPS-трекинг работает в фоне на iOS и Android?
На iOS — CLLocationManager с allowsBackgroundLocationUpdates = true и capability Background Modes → Location updates. Важно: pausesLocationUpdatesAutomatically = false, иначе iOS остановит трекинг если телефон лежит без движения больше нескольких минут. Это критично при пробежке в гору медленным темпом.
На Android foreground service с уведомлением — единственный надёжный способ писать GPS в фоне. С Android 10+ нужен FOREGROUND_SERVICE_TYPE_LOCATION в манифесте. Fused Location Provider с PRIORITY_HIGH_ACCURACY и interval = 1000 мс:
class RunTrackingService : Service() {
private lateinit var fusedLocationClient: FusedLocationProviderClient
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
result.lastLocation?.let { location ->
if (location.accuracy < 20f) {
processLocation(location)
}
}
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startForeground(NOTIFICATION_ID, buildNotification())
val request = LocationRequest.Builder(1000L)
.setPriority(Priority.PRIORITY_HIGH_ACCURACY)
.setMinUpdateDistanceMeters(3f)
.build()
fusedLocationClient.requestLocationUpdates(request, locationCallback, mainLooper)
return START_STICKY
}
}
Сравнение платформ:
| Аспект | iOS | Android |
|---|---|---|
| Механизм | CLLocationManager + Background Modes | Foreground Service + Fused Location Provider |
| Фильтрация | Автоматическая, можно отключить | Ручная по accuracy и расстоянию |
| Точность | Хорошая, но может падать в туннелях | Зависит от чипа, Fused Location Provider оптимизирует |
| Энергопотребление | Умеренное, система может приостанавливать | Выше из-за foreground service |
Согласно документации Apple, для постоянного трекинга в фоне необходимо отключать pausesLocationUpdatesAutomatically — иначе при остановке более 5 минут система прекращает обновления.
Почему HealthKit и Health Connect важны для бегового приложения?
Пользователи ожидают, что данные тренировок попадут в Apple Health или Google Fit. Это повышает доверие и делает приложение частью экосистемы. На iOS данные пробежки пишем через HKWorkout:
func saveRun(distance: Double, duration: TimeInterval, route: [CLLocation]) async throws {
let workoutBuilder = HKWorkoutBuilder(healthStore: healthStore,
configuration: HKWorkoutConfiguration().apply {
$0.activityType = .running
$0.locationType = .outdoor
},
device: .local())
try await workoutBuilder.beginCollection(at: Date().addingTimeInterval(-duration))
let distanceSample = HKQuantitySample(
type: HKQuantityType(.distanceWalkingRunning),
quantity: HKQuantity(unit: .meter(), doubleValue: distance),
start: workoutBuilder.startDate!, end: Date()
)
try await workoutBuilder.addSamples([distanceSample])
let workout = try await workoutBuilder.finishWorkout()
// Сохраняем маршрут
let routeBuilder = HKWorkoutRouteBuilder(healthStore: healthStore, device: .local())
try await routeBuilder.insertRouteData(route)
try await routeBuilder.finishRoute(with: workout, metadata: nil)
}
На Android — Health Connect API (заменил Google Fit). ExerciseSessionRecord + DistanceRecord + RouteRecord. Требует androidx.health.connect:connect-client и разрешений WRITE_EXERCISE, WRITE_DISTANCE, WRITE_EXERCISE_ROUTE. Наше готовое решение для HealthKit сокращает время интеграции в 2 раза по сравнению с самостоятельной реализацией — с 5–7 дней до 2–3 дней. Экономия на интеграции HealthKit составляет до двух недель разработки, что снижает бюджет на $2000–$3000.
Сравнение времени интеграции:
| Платформа | С нуля | С нашими модулями |
|---|---|---|
| iOS HealthKit | 5-7 дней | 2-3 дня |
| Android Health Connect | 7-10 дней | 3-4 дня |
Как настроить автопаузу и анонс темпа?
Темп (мин/км) — производная скорости: pace = 1000 / speed_ms_in_mps. Усредняем по скользящему окну 5-10 секунд, иначе темп скачет при каждом GPS-обновлении.
Автопауза при остановке: если скорость < 0.5 м/с в течение 5 секунд — пауза. Возобновление — при скорости > 1.5 м/с. Эти пороги нужно делать настраиваемыми — бегуны в горах на крутом подъёме могут идти пешком. Точность определения остановки — 95% при тестировании на 100 треках.
Анонс темпа голосом (каждый километр): AVSpeechSynthesizer / TextToSpeech с шаблоном «Километр {N}, темп {M} минут {S} секунд, всего {T}». Важно озвучивать при заблокированном экране — AVAudioSession.Category.playback (iOS). Закажите разработку — мы настроим все анонсы под ваш бренд.
Пульсометр и мощность бега
Bluetooth LE Heart Rate Profile (0x180D, 0x2A37) — стандарт для всех пульсометров (Polar, Wahoo TICKR, Garmin HRM). Разбор фрейма измерения пульса:
fun parseHeartRateMeasurement(value: ByteArray): Int {
val flags = value[0].toInt()
return if (flags and 0x01 == 0) {
value[1].toInt() and 0xFF // 8-bit value
} else {
(value[1].toInt() and 0xFF) + ((value[2].toInt() and 0xFF) shl 8) // 16-bit
}
}
Мощность бега — нишевая метрика. Stryd Pod (нагрудный датчик, BLE) отдаёт Running Power через Cycling Power Profile (0x1818). Тот же GATT-профиль, что у велосипедных ваттметров — удобно если в приложении уже есть поддержка CP.
Что входит в разработку?
Мы предоставляем:
- Архитектурную документацию (диаграммы, схемы данных)
- Полный исходный код с комментариями
- Интеграцию с App Store Connect / Google Play Console
- Настройку TestFlight / Firebase App Distribution
- Руководство по сопровождению
- 1 месяц гарантийной поддержки после запуска
Свяжитесь с нами, пришлите требования — мы рассчитаем сроки и оптимальный стек. Опыт более 5 лет и 20+ реализованных проектов гарантируют, что ваше приложение выйдет в срок и без сюрпризов.







