Scan Process
The scanning process happens entirely through the TireTreadScanView
and should be performed in Landscape mode.
Implementing the ScannerViewControllerHolder
Interface
In order to set up the scan view and retrieve the scan view controller, your UIViewController subclass should implement the ScannerViewControllerHolder
interface.
This interface gives your view controller two properties:
-
scannerViewController
: After the setup callTireTreadScanViewKt.TireTreadScanView
method (see below) is successfully made, this property will hold the instance ofTireTreadScannerViewController
, which handles the scanning process. -
dismissViewController
: This is a function property that will be called by the SDK when a request has been made to dismiss the scanner. Assign it a block within the lifetime of yourScannerViewControllerHolder
that handles this scenario in the appropriate manner.
Here is an example of how to implement the ScannerViewControllerHolder
interface:
class YourViewController: UIViewController, ScannerViewControllerHolder {
// Implement the properties defined by the ScannerViewControllerHolder interface
var scannerViewController: UIViewController?
var dismissViewController: (() -> Void)?
// Rest of your class implementation...
}
Remember to replace YourViewController
with the actual name of your view controller.
Make sure that YourViewController runs in Landscape mode.
|
Setting up the Scan View Controller
Once the SDK has been initialized and the necessary permissions have been granted, you can set up the scan view controller.
private func setupTireTreadScanView() {
let config = TireTreadScanViewConfig(measurementSystem: .metric, useDefaultUi: true)
TireTreadScanViewKt.TireTreadScanView(context: self, config: config) { error in
// Handle initialization error
}
}
private func addScanViewControllerAsChild() {
guard let scannerViewController = scannerViewController else {
// Handle error
return
}
addChild(scannerViewController)
view.addSubview(scannerViewController.view)
scannerViewController.didMove(toParent: self)
}
If the callback to TireTreadScanViewKt.TireTreadScanView(context, config)
does not produce an error, then the TireTreadScanView
becomes accessible to your application as the main view object of scannerViewController
.
Handling the SDK’s events
The scanning process is automatically stopped after 10 seconds. |
The TireTreadScanViewCallback
is the interface through which the TireTreadScanView
communicates back to your application. With these callbacks, you can react on changes and implement your own workflow around the scan process. The callbacks available are:
-
onScanStart
: Invoked when the scanning process begins -
onScanStop
: Invoked when the scanning process ends -
onImageUploaded
: Invoked after each frame is uploaded -
onUploadCompleted
: Invoked once all the frames were successfully uploaded for processing -
onUploadFailed
: Invoked if any issue has occurred during upload -
onDistanceChanged
: Invoked whenever the distance between the device and the tire changes. (This information serves as a guide to assist your app’s users in scanning correctly.)
Once your TireTreadScanView
object is available, add your callback implementation to it. In this example, we will use the same UIViewController
as the callback implementation.
Implement the TireTreadScanViewCallback
interface, and override the desired methods, e.g.:
// Implement the TireTreadScanViewCallback interface
extension YourViewController: TireTreadScanViewCallback {
func onUploadCompleted(uuid: String?) {
// Implement this method
self.playStopSound()
if let safeUuid = uuid {
self.displayLoading(uuid: safeUuid)
} else {
self.displayError()
}
}
func onImageUploaded(uuid: String?, uploaded: Int32, total: Int32) {
print("Native iOS: Image uploaded (\(uploaded)/\(total)) for uuid: \(uuid ?? "unknown")")
}
func onUploadFailed(uuid: String?, exception: KotlinException) {
self.displayError()
}
func onScanStart(uuid: String?) {
self.playStartSound()
self.progressView.isHidden = false
self.scanTimer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(updateProgressView), userInfo: nil, repeats: true)
}
func onScanStop(uuid: String?) {
print("Native iOS: Scan stopped for uuid: \(uuid ?? "unknown")")
}
/// Called when the distance has changed.
///
/// - Parameters:
/// - uuid: The UUID associated with the distance change.
/// - previousStatus: The previous distance status.
/// - newStatus: The new distance status.
/// - previousDistance: The previous distance value.
/// - newDistance: The new distance value.
///
/// Note: The distance values are provided in millimeters if the metric system is selected (`UserDefaultsManager.shared.imperialSystem = false`), and in inches if the imperial system is selected (`UserDefaultsManager.shared.imperialSystem = true`).
func onDistanceChanged(uuid: String?, previousStatus: DistanceStatus, newStatus: DistanceStatus, previousDistance: Float, newDistance: Float) {
if Int(newDistance) != Int(previousDistance) {
let distanceInCentimeters = UserDefaultsManager.shared.imperialSystem ? (newDistance * 2.54) : (newDistance / 10.0)
startBeeping(distanceInCm: Double(distanceInCentimeters))
DispatchQueue.main.async { [weak self] in
self?.updateUI(status: newStatus, distance: Int(UserDefaultsManager.shared.imperialSystem ? newDistance : distanceInCentimeters))
}
}
}
}
Check out the next section to learn how to handle the measurement results after the scan process is finished.