Реалізація 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 тижні |
Вартість розраховується індивідуально після аналізу вимог.







