Session lifecycle
A session is one scan, from the moment your user opens the scan screen to the file you upload. Most of what happens in between, the SDK handles with the user directly. Your app's job is to start the session, notice when it ends, and clean up.
What a scan goes through
Think of a session as a short journey your user takes through a property. It starts idle while the onboarding shows, begins scanning when the user is through it, and ends one of three ways: finished when they tap Complete scan, cancelled when they exit, or failed if something stops the scan.
| State | What's happening | What your app does |
|---|---|---|
| Idle | The session exists, but nothing is recording yet. | Call start(). |
| Starting | Recording is starting. It can pass too quickly to see. | Nothing. |
| Scanning | The user is scanning. The state also says how well tracking is going. | Nothing. The scan view coaches the user. |
| Paused | Your app went to the background, or you paused the scan. Nothing is recorded. | Nothing. It resumes when your app comes back. If you paused it, call resume(). |
| Recovering | iOS only: after a pause or interruption, the scan is finding where it left off. | Nothing. |
| Saving | The user completed the scan, and it's being saved. | Wait. |
| Finished | The scan is saved. | export(), then close(). |
| Cancelled | The user exited, or you called cancel(). Nothing is kept. |
close() and leave the scan screen. |
| Failed | The scan stopped with an error. | See Handling errors. |
Only three of these need anything from you: finished, cancelled and failed. The rest are there if you want to show your own status, such as a "Saving…" label. New states may be added in future releases, so keep a default or else branch when you switch on the state.
Following the scan
The state always holds its current value, so you can read it whenever your screen needs it. On iOS, RoomioScanSession is Observable: a SwiftUI view that reads session.state updates by itself, and UIKit can follow it with withObservationTracking. On Android, state is a Kotlin StateFlow; collect it with repeatOnLifecycle so your screen picks up the latest value each time it's shown. In JavaScript, useRoomioScanSession(session) gives you the state as React state.
Alongside the state, the session sends events for things that happen during the scan: tracking getting better or worse, the distance walked, the advice the scan view is giving, and errors, including ones the scan carries on from. You don't need them to complete a scan. They're useful if you want to log how scans go, or show your own progress.
Events aren't replayed, so subscribe before you call start() if you want them from the beginning:
Task {
for await event in session.events {
// tracking, progress and guidance
}
}
session.start()
// UNDISPATCHED so it is already listening when start() runs.
lifecycleScope.launch(start = CoroutineStart.UNDISPATCHED) {
session.events.collect { event -> /* tracking, progress and guidance */ }
}
session.start()
const subscription = session.addListener((event) => {
/* tracking, progress and guidance */
});
session.start();
// later: subscription.remove();
progressUpdated reports the distance the user has walked while tracking, in metres. Use it as a rough sense of how much has been covered, not as a percentage: the SDK can't know how big the property is.
Ending a scan
Your user decides when the scan is done. The scan view's Complete scan button saves it, and its close button asks the user to confirm before throwing it away. On Android, the back button does the same as the close button while a scan is in progress.
If your app needs to end the scan itself, for example from a time limit or a button of your own, call stop() to save it or cancel() to discard it. stop() throws not_ready in the first few seconds of a scan, while there's not yet enough to save. In JavaScript there's no cancel(); close() discards the scan.
When your app goes to the background
A phone call or a quick switch to another app shouldn't cost your user their scan. The scan pauses by itself while your app is in the background, keeping what it has captured, and carries on when the user comes back. You don't need to forward your activity's onPause and onResume.
To pause for a reason of your own, such as showing your own sheet over the scan, call pause(). The scan then stays paused, even across a trip to the background, until you call resume() or the user taps Resume scan in the scan view. Complete scan and the close button still work while it's paused.
On Android, keep the activity hosting the scan in one orientation. A rotation or other configuration change recreates the activity, and the session goes with it.
Closing
close() releases the camera, and the session can't be used afterwards. Call it once you're done with a session, however it ended: after exporting, when it's cancelled, after a fatal error, or when the user leaves the scan screen some other way.
close() doesn't dismiss your scan screen; leave it yourself. For the next scan, start a new session.