Разработка мобильного приложения для недвижимости (PropTech)
Приложение для недвижимости — это агрегация данных об объектах, карта с поиском в области видимости, фильтры с десятками параметров, виртуальные туры и форма связи с застройщиком или агентом. Технически самая болезненная часть — не UI, а работа с большими объёмами объектов на карте и синхронизация состояния фильтров с поисковыми запросами.
Карта как основной UI
Большинство пользователей PropTech-приложений ищут по карте, а не по списку. Значит, карта — первый экран, а не вкладка. Это влияет на архитектуру: нельзя загружать все объекты за один запрос — их могут быть тысячи.
Viewport-based loading — загружаем только объекты в текущей области видимости карты:
GET /properties?bounds=55.70,37.55,55.80,37.70&filters=...
bounds — прямоугольник текущего вьюпорта. При скролле/зуме — новый запрос. Дебаунс 500 мс на событие onCameraIdle (не onCameraMove) — запрашиваем только после остановки камеры.
PostGIS на сервере:
SELECT id, lat, lon, price, property_type
FROM properties
WHERE geom && ST_MakeEnvelope(:west, :south, :east, :north, 4326)
AND price BETWEEN :min_price AND :max_price
ORDER BY created_at DESC
LIMIT 200;
Кластеризация. При большом количестве объектов в области и низком зуме — кластеры с числом внутри. При зуме > 14 — отдельные маркеры. На iOS — GMUMarkerClusterer, на Android — ClusterManager, во Flutter — flutter_map_marker_cluster. Кластеры пересчитываем на каждый onCameraIdle.
Фильтры с десятками параметров
Фильтр недвижимости — один из самых сложных UI-компонентов в мобильной разработке. Количество комнат, тип жилья, ценовой диапазон (Range Slider), площадь, этаж, год постройки, тип договора, срочность. Плюс специфические для страны поля.
Главная проблема: хранение состояния фильтра. Не в локальных переменных экрана — пользователь уходит на карточку объекта и возвращается. Состояние фильтра должно жить в ViewModel / StateHolder и переживать рекомпозицию.
На Android — data class FilterState в ViewModel, StateFlow<FilterState> в UI. При изменении любого поля фильтра — copy() + обновление Flow. Дебаунс 300 мс перед запросом к API — не отправлять запрос при каждом сдвиге слайдера.
filterState
.debounce(300)
.flatMapLatest { filters -> propertyRepository.search(filters) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
На iOS — @Published var filterState: FilterState в ObservableObject, Combine.debounce(for:scheduler:).
Сохранение поиска. Пользователь сохраняет текущий набор фильтров как «поисковый агент» — получает push-уведомления при появлении новых подходящих объектов. FCM + серверный cron-job, который раз в час прогоняет сохранённые запросы.
Карточка объекта
Фотогалерея с плавным scroll-driven переходом из карты. На iOS — кастомный UIViewControllerTransitioningDelegate для hero-анимации маркера → фото. На Android — Shared Element Transition с ActivityOptionsCompat.makeSceneTransitionAnimation.
Виртуальный тур. 360°-фото через VR Panorama или Matterport embed. На iOS — SceneKit + сферическая геометрия для рендера equirectangular-панорамы, или WKWebView с Matterport iframe. На Android — GoogleVR SDK (устарел, но всё ещё работает) или то же решение через WebView. Нативный рендер производительнее, WebView проще и поддерживает больше форматов.
Ипотечный калькулятор. Простая математика на клиенте — сумма, ставка, срок → ежемесячный платёж. Формула аннуитетного платежа:
let monthlyRate = annualRate / 12 / 100
let n = Double(months)
let payment = principal * monthlyRate * pow(1 + monthlyRate, n) / (pow(1 + monthlyRate, n) - 1)
Никаких API не нужно, работает офлайн.
Интеграция с источниками данных
Объекты недвижимости чаще всего берутся из нескольких источников: парсинг Циан/Авито (серая зона с точки зрения ToS), собственная CRM застройщика, CREA/IDX-фиды (для западного рынка), ручное наполнение через CMS.
Для агрегации с внешних порталов — серверная синхронизация через API (если доступен) или ETL-пайплайн. В мобильном приложении это не видно — просто нормализованные данные из собственного API.
Для застройщика с собственной CRM — интеграция через REST API с маппингом полей. Синхронизация по webhook (CRM нотифицирует при изменении объекта) или по расписанию раз в 15 минут.
Специфика iOS vs Android для PropTech
На iOS с iOS 16 появился MapKit с MKMapView и SwiftUI integration. Для PropTech с тысячами маркеров — MKMapView на UIKit с dequeueReusableAnnotationView быстрее, чем SwiftUI Map. Кластеризация через MKAnnotationView + MKClusterAnnotation — встроена в MapKit, не нужна сторонняя библиотека.
На Android — Google Maps SDK с Jetpack Compose через GoogleMap composable из maps-compose — хорошо интегрируется с Compose-архитектурой, поддерживает все маркеры и полилинии.
Процесс работы
Аудит требований: источники данных, фильтры, обязательные интеграции (CRM, ипотечный брокер, нотариусы). Проектирование схемы данных и API. Разработка карты с viewport-loading и кластеризацией. Разработка системы фильтров. Карточка объекта с галереей и виртуальным туром. Система поисковых агентов. Интеграция с источниками данных. Тестирование на нагрузку (тысячи маркеров, сложные фильтры).
Срок: три-шесть месяцев в зависимости от количества платформ, сложности фильтров и набора интеграций.







