Release Notes 4.5.0
Highlights
- Play back Scaniverse playback sessions
- Native playback on every platform
- Localize to a specific VPS map asset
- List site scans and non-production assets
- Mesh download caching and memory budget
- Kotlin and Swift SDK hardening
Features/Fixes
Play back Scaniverse playback sessions
Developers can now download a playback session recorded in Scaniverse and play it back. The recording is cached on the device, and the download reports its progress. In Swift and Kotlin, open it with PlaybackDataset.open(scanId:onProgress:) (Swift) or PlaybackDataset.open(scanId, onProgress) (Kotlin). In Unity, open it with PlaybackDataset.OpenAsync(...), then assign the dataset to RuntimeNsdkSettings.PlaybackDataset. A cache session lets you check whether a recording is cached, list and delete cached recordings, and read a recording's frame count, size, and duration before downloading. It is NSDKPlaybackCacheSession in Swift, NSDKSession.playbackCache in Kotlin, and PlaybackCacheClient in Unity.
Native playback on every platform
Swift, Kotlin, and Unity now read playback datasets through the native playback reader, so all platforms parse a recording the same way. In Swift and Kotlin, PlaybackDataset.open(datasetPath) replaces the capture.json loaders, which are now deprecated. It exposes dataset info and per-frame PlaybackFrameMetadata, and Kotlin also opens asset:// paths from the APK. Unity's PlaybackDataset is now public, and Unity playback no longer accepts .zip dataset paths; see Breaking Changes and Setting up playback.
Localize to a specific VPS map asset
VPS2 can now localize against one VPS map asset of a site by its UUID, including assets that are not in production. Use localize(siteId:assetId:) in Swift, localize(siteId, assetId) in Kotlin, or TryLocalize(siteId, assetId) in Unity. Stopping localization now cancels the site's requests that are still in flight. Universal localization can also use areas mapped by aerial capture when aerialLocalizationEnabled is set in Swift, enableAerialLocalization in Kotlin, or AerialLocalizationEnabled in Unity.
List site scans and non-production assets
Sites can now list a site's scans and fetch one scan's details as ScanInfo. Use requestScansForSite and requestScanInfo in Swift and Kotlin, or RequestScansForSiteAsync and RequestScanInfoAsync on SitesClient in Unity. Location queries take a new AssetScope to include non-production assets; production-only remains the default. See Getting started with Sites.
Mesh download caching and memory budget
Mesh downloads can now be cached on disk, which avoids downloading the same geometry and textures again. Enable the cache with configure(with:) on NSDKMeshDownloader, configure(MeshDownloaderConfig) on MeshDownloaderSession, or ConfigureCache on LocationMeshManager. Asset mesh downloads now stop at a decoded-size budget, 256 MB by default and adjustable through maxDecodedSizeKb, and meshes decode on a background thread to lower peak memory. See Mesh download.
Kotlin and Swift SDK hardening
On Kotlin, NSDKSession can now be closed safely more than once and from any thread, and feature Flows such as Vps2Session.localizationUpdates survive close() and acquire(). The published Maven POM now declares its dependencies, and the AAR no longer adds storage permissions to apps. On Swift, the SDK is ready for Swift 6 strict concurrency, with Sendable value types and sessions and @Sendable progress callbacks.
Changelog
Added
- Added
localize(siteId, assetId)to localize against one VPS map asset by UUID, including non-production assets (UnityTryLocalize). - Added an
AssetScopeparameter torequestSiteAssetsByLocationto list non-production assets nearby; it defaults toProduction. - Added
requestScansForSiteandrequestScanInfoto list a site's scans and fetch scan details asScanInfo(UnityRequestScansForSiteAsync,RequestScanInfoAsync). - Unity: Added the
HttpUnauthorizedSites error for a missing, expired, or invalid access token. - Added an opt-in on-disk mesh download cache, configured with
MeshDownloaderSession.configure(Swiftconfigure(with:), UnityLocationMeshManager.ConfigureCache). - Added a
maxDecodedSizeKbbudget to asset mesh downloads, capping the decoded memory of delivered chunks. - Swift, Kotlin, Unity: Added
aerialLocalizationEnabled(KotlinenableAerialLocalization, UnityAerialLocalizationEnabled) to localize against areas mapped by aerial capture. - Swift, Kotlin: Added
PlaybackDataset.open(scanId, onProgress)to download, cache, and open a Scaniverse playback session. - Swift, Kotlin: Added a playback cache session (
NSDKPlaybackCacheSession, KotlinNSDKSession.playbackCache) withisCached,cachedPlaybacks,playbackFileInfo,deleteCached, andclearCache. - Swift, Kotlin: Added
PlaybackDataset.open(datasetPath), which reads datasets through native playback and exposesinfoand per-framePlaybackFrameMetadata. - Kotlin: Added
asset://APK asset paths toPlaybackDataset.openand madePlaybackDatasetAutoCloseable. - Unity: Added
PlaybackCacheClientandPlaybackDataset.OpenAsyncto open Scaniverse playback sessions, withIsCached,GetCachedPlaybacks,DeleteCached, andClearCache. - Unity: Made
PlaybackDatasetpublic andIDisposable, withFrameCount,FrameRate, andClose(). - Unity: Added
RuntimeNsdkSettings.PlaybackDatasetto play an app-openedPlaybackDatasetfrom the next XR initialization. - Unity: Added
AreaIdtoVps2LocalizedAssetandXRVps2AssetTrackingData. - Unity: Added
MeshChunkData,GetLocationMeshChunkDataByVpsMapAssetIdAsync, andCreateMeshChunkonLocationMeshManagerto stream mesh data and build chunks later. - Unity: Added
SiteNotFoundandVpsAssetsNotFoundtoVps2LocalizationError, matching the native site localization errors. - Python: Added
Ardk.set_frame_pacing_clockto pace module frame rates on camera frame timestamps. - Python: Added
Vps2Session.localize_to_siteandVps2Session.get_asset_tracking_data. - Python: Added a
portal_endpointparameter toArdk.create()andArdk.create_with_env_config()to choose the sites and assets endpoint.
Changed
stopLocalizenow cancels the site's in-flight localize requests, whose request records endFailedwithUnknown.- Asset tracking data for an asset whose localize request is still fetching now reports not-yet-tracked instead of
InvalidArgument. - When VPS stops georeferencing, the coarse output now holds the last confident VPS georeference instead of jumping to WPS.
- Swift, Kotlin, Unity: Asset mesh downloads now stop at a 256 MB decoded-size budget by default; pass 0 for no budget but beware that large sites can surpass mobile device memory budgets.
- Mesh downloads now decode on a background thread and free each node's response on arrival, lowering peak memory.
- VPS2 area targeting now excludes every map when a trusted position is out of range of all of them, stopping localization requests.
- Scanning no longer requires GPS and compass input; frames without them are recorded without location.
- Unity: Playback datasets are now read through native playback instead of the managed capture.json reader.
- Kotlin: Feature-session Flows such as
Vps2Session.localizationUpdatesnow surviveclose()/acquire(), complete whenNSDKSessioncloses, and emit an error only when it changes. - Swift:
GeolocationData,Vps2AssetTrackingData,Vps2LocalizedAsset,NSDKMapStorage,NSDKRecordingExporter, andNSDKSitesSessionnow conform toSendable.
Deprecated
- Swift: Deprecated
PlaybackDatasetLoader,BundlePlaybackDatasetLoader,PlaybackDatasetSource,captureRoot,compassTimestampBase, andPlaybackFrame.metadata; usePlaybackDataset.openinstead. - Kotlin: Deprecated
PlaybackDataset.loadFrom,AssetPlaybackDatasetLoader,PlaybackDatasetLoader,PlaybackDatasetSource,CaptureRoot, andFrameMetadata; usePlaybackDataset.openinstead.
Fixed
- Fixed a hang when two threads closed the same network request at once.
- Fixed a possible crash when a mesh download was released while its HTTP callback was still decoding the mesh.
- Fixed a crash when a feature getter ran on one thread while another thread destroyed that feature.
- Fixed data races when Sites results were polled while the network response was still being written.
- Fixed a scanning crash on Android devices with Samsung Xclipse 960 or newer GPUs.
- Fixed playback mishandling datasets with a malformed depth resolution or missing frame fields.
- Unity: Fixed the location manifest importer rejecting legacy location zips with a
LocalizationTargetIdor no top-level node. - Swift, Kotlin: Fixed
PlaybackSessiontimestamps jumping backwards when playback looped to the first frame. - Swift: Fixed
PlaybackSessionplaying slower than the dataset's recorded frame rate. - Swift: Fixed playback repeating edge pixels outside the image, instead of dark gray, when view and image aspect ratios differed.
- Kotlin: Fixed
PlaybackSessioncrashing when a frame failed to load, and running two workers after quickpause()/play()calls. - Kotlin: Fixed JNI strings corrupting characters such as emoji and aborting CheckJNI apps; strings now convert as standard UTF-8.
- Kotlin: Fixed native crashes when
NSDKSessioncreation failed orSceneSegmentationConfig.numThresholdsexceeded thethresholdsarray length. - Kotlin: Fixed
createLiveDataSourcemissing late precise-location grants and leaving GPS and compass running after destroy. - Kotlin: Fixed crashes when closing
NSDKSessiontwice, from another thread, during an in-flight call, or with features still started. - Kotlin: Fixed the published Maven POM omitting dependencies, which caused compile errors and
NoClassDefFoundErrorfor Maven consumers.
Breaking Changes
- Unity:
Vps2LocalizedAsset.EqualsandGetHashCodenow includeAreaId, so values for different areas of the same asset no longer compare equal. Review dictionary keys and change detection that relied on site and asset IDs alone. - Unity: Playback no longer accepts
.zipdataset paths, and the NSDK settings editor no longer rebuilds missing frame images fromvideo.mp4. Unzip datasets into a directory that contains every frame image, and point the playback dataset path at that directory. - Kotlin: The NSDK AAR no longer merges
READ_EXTERNAL_STORAGEandWRITE_EXTERNAL_STORAGEinto apps. Apps that pointPathConfigor log output at shared storage must declare these permissions in their own manifest. - Kotlin:
NSDKSession.close()now throwsIllegalStateExceptionwhen called from inside an NSDK call on the same thread, includingNsdkLogCallback.onLog, where it would otherwise deadlock. Close the session from outside NSDK callbacks. - Swift: Progress closures passed to the
NSDKRecordingExporterexport methods must now be@Sendable. They run off the main actor, so hop to the main actor before updating UI.NSDKDashcamSession.saveBufferandNSDKScanningSession.saveCurrentScanare now@MainActor.
Known Issues
- Importing the NSDK UPM in a project started from Universal 3D template might cause a few build errors reported in the console. Restarting the editor should fix this.
- VPS2 can keep reporting precise localization and tracked anchors while the device is disturbed, such as a covered camera or a dark room, so content can stay at a stale pose until confidence drops or the device localizes again.
- On iPad Pro running iOS 17 in the Unity NSDK sample app, rotating the device from landscape to portrait may cause a soft lock and screen flickering.