Розробка мобільного додатку для бігунів
Ринок беговых додатків перенасичен: Nike Run Club, Runkeeper, Adidas Running. Новий продукт виживає за рахунок спеціалізації: корпоративні беговие клуби, додатки для конкретних подій (марафони, трейли), інтеграція з тренерськими платформами, локальні спільноти. Технічно розробка беговых додатків добре вивчена, але деталі реалізації HealthKit/Health Connect та роботи з GPS в фоні регулярно вызывают питання.
GPS-трекінг в фоне: різні обмеження на iOS та Android
На 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 — CLLocationManager з allowsBackgroundLocationUpdates = true та capability Background Modes → Location updates. Важливо: pausesLocationUpdatesAutomatically = false, інакше iOS зупинить трекінг якщо телефон лежит без руху більше кількох хвилин. Це критично при пробіжці в гору повільним темпом — iOS думає, що користувач зупинився.
HealthKit та Health Connect: інтеграція з платформенним здоров'ям
На iOS дані пробіжки пишемо в HealthKit через 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 2023). ExerciseSessionRecord + DistanceRecord + RouteRecord. Потребує androidx.health.connect:connect-client та дозволів WRITE_EXERCISE, WRITE_DISTANCE, WRITE_EXERCISE_ROUTE.
Темп, дистанція та автопауза
Темп (хв/км) — похідна швидкості: pace = 1000 / speed_ms_in_mps. Усереднюємо по скользящому вікну 5-10 секунд, інакше темп стрибає при кожному GPS-оновленні.
Автопауза при зупинці: якщо швидкість < 0.5 м/с протягом 5 секунд — пауза. Возобновлення — при швидкості > 1.5 м/с. Ці пороги потрібно робити налаштовуваними — бігуни в горах на крутому підйомі можуть йти пішком.
Анонс темпу голосом (кожен кілометр): 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.
Розробка беговое додатку з GPS-трекингом в фоне, HealthKit/Health Connect, BLE пульсометром та голосовими анонсами: 7-10 тижнів на одну платформу. Кросс-платформа Flutter: 10-14 тижнів. Вартість розраховується індивідуально.







