Реализация геозон (Geofencing) в мобильном приложении
Геозона — это не просто «уведомление, когда пользователь пришёл». За этой задачей прячется целый пласт ограничений платформ, которые производители ужесточают с каждой мажорной версией ОС. Приложение, которое отлично работало на iOS 15, на iOS 17 может молчать — и это не баг в вашем коде.
Ограничения платформ, которые важно знать до начала разработки
iOS. CLLocationManager поддерживает до 20 активных геозон одновременно — системный лимит, не наш. Радиус минимум 100 метров — меньше не мониторится. На устройствах без A12+ чип точность ещё ниже. CLCircularRegion доставляет события didEnterRegion / didExitRegion, но задержка может составлять 3-5 минут в зависимости от режима энергосбережения. В iOS 13+ нужно запрашивать Always авторизацию через двухшаговый диалог: сначала whenInUse, потом пользователь сам идёт в Settings. Напрямую попросить Always уже нельзя — Apple отклонит при ревью.
Android. Geofencing API в com.google.android.gms:play-services-location требует Google Play Services. На Huawei без GMS — нужен отдельный путь через HMS LocationKit. Android 10+ ввёл ACCESS_BACKGROUND_LOCATION как отдельное разрешение, которое пользователь выдаёт в Settings, а не в стандартном диалоге. На Android 12 добавили SCHEDULE_EXACT_ALARM для точных будильников — без него Geofencing на Doze-устройствах может не срабатывать в нужный момент. Некоторые производители (Xiaomi MIUI, Samsung One UI с агрессивным battery saver) убивают фоновые сервисы раньше, чем API успевает доставить событие.
Как реализуем
iOS: базовый сценарий
let region = CLCircularRegion(
center: CLLocationCoordinate2D(latitude: 55.7558, longitude: 37.6173),
radius: 200,
identifier: "office_zone"
)
region.notifyOnEntry = true
region.notifyOnExit = false
locationManager.startMonitoring(for: region)
При превышении лимита 20 зон — приоритизируем по расстоянию от текущей позиции и динамически перегружаем набор активных регионов через stopMonitoring / startMonitoring. Логика ротации — в locationManager(_:didUpdateLocations:).
Для проектов, где нужно более 20 зон или радиус меньше 100 метров — переходим на Visit Monitoring (startMonitoringVisits()) или Significant Location Changes в комбинации с серверной проверкой геозоны по координатам.
Android: Geofencing API + WorkManager
val geofence = Geofence.Builder()
.setRequestId("warehouse_exit")
.setCircularRegion(lat, lon, 150f)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
.setLoiteringDelay(30_000) // DWELL через 30 секунд
.build()
val request = GeofencingRequest.Builder()
.addGeofence(geofence)
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.build()
geofencingClient.addGeofences(request, geofencePendingIntent)
PendingIntent ведёт на BroadcastReceiver, который запускает WorkManager-задачу вместо прямого выполнения логики. Это важно: прямой запуск длинной задачи из Receiver на Android 8+ вызывает BackgroundExecutionLimits исключение.
Для Huawei HMS — com.huawei.hms:location с практически идентичным API, но отдельной регистрацией PendingIntent через GeofenceService.
Серверная валидация как страховка
Мобильное геозонирование ненадёжно само по себе. Для критичных бизнес-сценариев (контроль выезда транспорта, геймификация с призами) строим дополнительную серверную проверку: устройство периодически отправляет координаты, сервер проверяет пересечение полигонов через PostGIS или геозоны через Redis GEORADIUS. Мобильный Geofencing — быстрый триггер, сервер — финальный арбитр.
Работа с разрешениями правильно
Самая частая причина отклонения в App Store — неправильное объяснение NSLocationAlwaysAndWhenInUseUsageDescription. Apple читает строки в Info.plist и требует конкретного описания: «для отправки уведомления при входе в зону самовывоза» вместо «для работы приложения».
В Google Play с мая 2023 фоновая геолокация проходит ручной ревью. Заявка должна объяснять конкретный юзкейс и показывать видео-демонстрацию. Закладывайте на это 3-7 дней.
Процесс работы
Анализ требований: количество зон, минимальный радиус, платформы, наличие GMS у целевой аудитории. Проектирование архитектуры с учётом ограничений платформ. Реализация с корректным управлением разрешениями. Тестирование: Walk Test через Xcode Simulator Location, реальные выезды для Android. Подготовка описаний для ревью.
Срок: три-шесть дней в зависимости от количества платформ, сложности логики триггеров и наличия серверной части.







