Реализация Persistent AR (сохранение AR-сцен между сессиями)
Пользователь расставил мебель в AR, закрыл приложение, открыл снова — и всё на месте. Именно это делает Persistent AR. ARKit реализует это через ARWorldMap — снимок карты мирового пространства, который можно сериализовать, сохранить и загрузить в следующей сессии.
Звучит просто. На практике — несколько нетривиальных проблем с качеством карты, восстановлением локализации и обработкой edge-кейсов.
Как работает ARWorldMap
ARWorldMap содержит feature points — визуальные ориентиры, которые ARKit использует для локализации. Чем их больше и чем они разнообразнее, тем точнее восстановление сцены. Карта сохраняется через:
arView.session.getCurrentWorldMap { worldMap, error in
guard let worldMap = worldMap else { return }
let data = try? NSKeyedArchiver.archivedData(withRootObject: worldMap, requiringSecureCoding: true)
// сохраняем data на диск или в облако
}
Загрузка в новой сессии:
let worldMap = try? NSKeyedUnarchiver.unarchivedObject(ofClass: ARWorldMap.self, from: data)
let config = ARWorldTrackingConfiguration()
config.initialWorldMap = worldMap
session.run(config, options: [.resetTracking, .removeExistingAnchors])
После запуска сессии с initialWorldMap ARKit пытается релокализоваться — найти текущий вид камеры в сохранённой карте. Статус отслеживается через session(_:cameraDidChangeTrackingState:): ждём .limited(.relocalizing) → .normal.
Проблемы, которые реально встречаются
Плохое качество карты. ARWorldMap имеет свойство mappingStatus: .notAvailable, .limited, .extending. Сохранять карту в статусе .limited — получить плохую релокализацию. Нужно блокировать кнопку «Сохранить» до достижения .extending и показывать пользователю подсказку: «Медленно обойдите комнату».
Релокализация не происходит. Приходим в ту же комнату, но освещение изменилось (день/ночь, зашторили окно). ARKit использует visual feature points — в условиях кардинально другого освещения ориентиры не совпадают. Решение частичное: сохранять карту при разных условиях освещения и выбирать ближайшую к текущим условиям. Полного решения на уровне ARKit нет — это фундаментальное ограничение Visual-Inertial Odometry.
Якоря дрейфуют при восстановлении. Анкоры сохраняются внутри ARWorldMap. При восстановлении позиция анкора восстанавливается с точностью до качества карты. Критичные объекты (например, разметка на полу) могут сместиться на 2–5 см. Для таких случаев добавляем ARAnchor с именем и после релокализации подтягиваем их к ближайшей поверхности через raycast.
Размер карты. ARWorldMap большой комнаты — 5–20 МБ. Хранить на устройстве — нормально. Синхронизировать в CloudKit без сжатия — дорого. Используем Data.compressed(using: .lzfse) (iOS 16+) или Compression.lzma для уменьшения до 1–4 МБ.
Хранение пользовательских данных с картой
Анкоры сохраняются в ARWorldMap.anchors. Но данные приложения (что именно стоит на анкоре — диван, лампа, таблица цен) нужно хранить отдельно и связывать по ARAnchor.identifier:
// При сохранении
let metadata: [String: Any] = [
anchor.identifier.uuidString: ["type": "sofa", "modelName": "ikea_kallax"]
]
// При восстановлении — матчим по UUID
Это стандартная практика, но её часто пропускают, пытаясь запихать данные в ARAnchor.name — строка из 256 символов и никакой типизации.
Кейс
Приложение для interior design, 3000 активных пользователей. Сохранение плана расстановки мебели между сессиями. Главная боль: пользователи сохраняли карту сразу после запуска (.limited mapping status) — и жаловались, что объекты «плавают». Добавили UI-индикатор качества карты (зелёный/жёлтый/красный) с блокировкой сохранения до зелёного. Жалобы снизились радикально.
Сроки
| Функциональность | Сроки |
|---|---|
| Базовое сохранение/восстановление сцены | 1–2 недели |
| Облачная синхронизация карт + мульти-устройство | 3–4 недели |
| Интеллектуальная релокализация + управление качеством | 2–3 недели |
Стоимость рассчитывается индивидуально после анализа требований.







