iOS SmartDrive framework - scopetech/Mobile-Public GitHub Wiki
This document describes how ScopeTechnology framework "SmartDrive" works and how to integrate into your application. While the target audience is coders/developers, it brings better understanding for those who are not too tech-savvy as well.
SmartDrive framework main functionality is to record trips. It supports trip recording:
- with Beacons (BLE device from ScopeTechnology).
- with MHub837s (BLE device from ScopeTechnology).
- without any BLE device (called "Smart" version).
Part of the Consolidated SPM package. Related: App configuration & permissions ยท Integration guides ยท Release notes ยท Demo app
Following instructions will allow you to integrate our SDK into your application. Additionally, here is the demo sample app that you can follow while going through this document.
In introduction we mentioned that SmartDrive has two configuration types:
- for BLE devices (including ScopeTechnology - beacons and MHubs837s)
- for no BLE devices (smart solution)
It is important to apply correct configuration and permissions for your specific business needs.
- Minimum Deployments: iOS 15.0
Permissions. SmartDrive needs location and motion access to record trips:
- Location โ used to capture the trip route and analyze the trip in detail, and for BLE device scanning in beacon mode.
- Motion & Fitness โ lets the algorithm tell whether the user is driving or walking (so trips are detected in time and ghost trips are avoided), and drives exception detection (driving behaviour during the trip).
Important
The full permission and background setup โ Info.plist keys, the required Always + Precise location level, Background Modes, Background App Refresh, and notifications โ is documented once for the whole package in Consolidated SPM โ Section 4: Required App Configuration.
Two that commonly stop background trips:
- Background trips require Always + Precise location โ Section 4.4 Location authorization and accuracy.
- Background App Refresh must be on for periodic background work (retry / upload) โ Section 4.5 Background App Refresh.
The library (SDK) is shared within SmartDriveDemo app as .xcframework
Important
Always confirm that you are using latest version.
All core configuration happens using SCPSmartDriveManager helper class.
import SCPSmartDrive
We need to tell SmartDrive framework weather we want to use BLE devices for trip recording or use smart solution instead.
Important
If SmartDrive is intended to work with BLE devices
UserDefaults.standard.set(true, forKey: "recordTripsWithBeaconOnly")
SCPSmartDriveManager.sharedInstance().setMotionActivityEnabled(false)
SCPSmartDriveManager.sharedInstance().setSBeaconManagerEnabled(true)
SCPSmartDriveManager.sharedInstance().startSignificantLocationUpdates(true)
SCPSmartDriveManager.sharedInstance().setTripMonitoringDisabled(false)
Important
If SmartDrive is intended to work with no BLE devices using smart solution
UserDefaults.standard.set(false, forKey: "recordTripsWithBeaconOnly")
SCPSmartDriveManager.sharedInstance().setMotionActivityEnabled(true)
SCPSmartDriveManager.sharedInstance().setSBeaconManagerEnabled(false)
SCPSmartDriveManager.sharedInstance().setTripAutostartEnabled(true)
SCPSmartDriveManager.sharedInstance().setTripMonitoringDisabled(false)
Trip auto sending happens automatically, no additional code needed.
Our solution uses trip end timer to validate if trip has truly finished (compared to heavy traffic with no movement for longer period of time). Trip end timer does not change recorded trip actual time range.
Warning
While you can change trip end timer based on your needs, it is strongly suggested to configure it between 3 - 5 minutes range to avoid ghost trips. Default value is 300 seconds.
UserDefaults.standard.set(300, forKey: "kSettingsTripEndThreshold") //Example for 5 minutes
Mode of Transport is clever solution to avoid trip recording on pre-defined transport types. For instance, if you want to avoid public transport buses or trains, you can configure so and framework will discard them. By default - disabled.
let motSkipTrip = [
"Air", // Airplane
"Water", // Boats, jet skis
"Public", // Bus, trams etc.
"Railway", // Train
"OffRoad" // OffRoad. Available from v1.1.9
]
SCPSmartDriveManager.sharedInstance().configureMOT(withIsMOTEnabled: true,
motSkipTrip: motSkipTrip,
elevationKey: "",
staticMapsKey: "<YOUR_KEY_HERE>")
When enabled will monitor driver actions during the trip. Following distracting driving types are available:
- PHONE USE - phone is being used while driving. Browsing different apps, tilting it, shaking it and other similar actions will be caught.
- PHONE CALLS - phone call is while driving WITH OUT headset (not available in current version).
SCPSmartDriveManager.sharedInstance().setDistractedDriverDetectionEnabled(true)
// set distraction types which should be tracked
SCPSmartDriveManager.sharedInstance().getDistractedDriverManager()?.setPhoneUseDetectionEnabled(true)
SCPSmartDriveManager.sharedInstance().getDistractedDriverManager()?.setPhoneCallDetectionEnabled(true)
Tip
If you want to detect events based on minimum speed, make sure you are using library version v1.0.21+
SCPSmartDriveManager.sharedInstance().getDistractedDriverManager()?.setMinimumSpeedToDetectDistraction(5) // If user speed is below 5km/h -> ignore events
SmartDrive is started as user logs in and above mentioned configuration methods are called.
Stop SmartDrive manually on logout to prevent trip recording for unauthorised user:
SCPSmartDriveManager.sharedInstance().setTripDataMonitoringOn(false)
SCPSmartDriveManager.sharedInstance().setTripMonitoringDisabled(true)
SCPSmartDriveManager.sharedInstance().setMotionActivityEnabled(false)
SCPSmartDriveManager.sharedInstance().setDistractedDriverDetectionEnabled(false)
// If SmartDrive is intended to work **with BLE devices**
SCPSmartDriveManager.sharedInstance().startSignificantLocationUpdates(false)
// If SmartDrive is intended to work **with no BLE devices** using smart solution
SCPSmartDriveManager.sharedInstance().setTripAutostartEnabled(false)
When configured lets send events during the trip. Trip start, end and periodic location updates trigger all the unsent events sending. Configuration:
// Set sending enabled first:
AppDelegate.shared.isRealtimeTripSendingEnabled = true
// Provide MProfiler credentials: service url, service provider, api key:
let mProfilerServiceUrl = "<YOUR_VALUE>"
let mProfilerServiceProvider = "<YOUR_VALUE>"
let mProfilerApiKey = "<YOUR_VALUE>"
SCPSmartDriveManager.sharedInstance()?.configureMProfilerEnvironment(mProfilerServiceUrl, provider: mProfilerServiceProvider, key: mProfilerApiKey) { error in
// Check an error here
}
// If needed it's possible to check if MProfiler is configured correctly:
SCPSmartDriveManager.sharedInstance()?.checkMProfilerConfiguration { isValid, message in
// Check isValid
}
// Observe for a new event and send events when start, end or periodic location updates event has been received:
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveNewEvent(_:)), name: NSNotification.Name.newEventRegistration, object: nil)
...
@objc private func didReceiveNewEvent(_ notification: NSNotification) {
guard let event = notification.userInfo?["event"] as? SCPEvent else {
return
}
if event.eventType == NSNumber(integerLiteral: Int(SCPEventType.tripStart.rawValue)) || event.eventType == NSNumber(integerLiteral: Int(SCPEventType.tripEnd.rawValue)) || event.eventType == NSNumber(integerLiteral: Int(SCPEventType.periodicLocationUpdate.rawValue)) {
sendEvents()
}
}
...
private func sendEvents() {
// See implementation in SmartDriveDemo app
}
While a trip is being recorded you can read its live status and components directly from SCPSmartDriveManager. There are two kinds of information: the recorder status, which changes at trip boundaries, and the live components (distance, duration, speed), which you poll while a trip is active.
Status โ react to changes. SCPSmartDriveManager posts smartDriveStatusChanged whenever the recorder state changes. Observe it and read getRecorderState():
NotificationCenter.default.addObserver(self,
selector: #selector(statusDidChange),
name: NSNotification.Name.smartDriveStatusChanged,
object: nil)
@objc func statusDidChange() {
switch SCPSmartDriveManager.sharedInstance().getRecorderState() {
case .recorderStateIdle: break // no trip
case .recorderStateWaitingForLocation: break // waiting for GPS
case .recorderStateWaitingForTripStartConfirmation: break // possible trip starting
case .recorderStateActiveTrip: break // recording
case .recorderStatePassiveTrip: break // recording (passive)
case .recorderStateWaitingForTripStopConfirmation: break // possible trip ending
case .recorderStatePending: break // finalising
@unknown default: break
}
}
For a simple "is a trip being recorded right now" boolean, use isRecordingTrip().
Components โ poll while active. Read speed, distance, and duration from the manager. Gate distance and duration on there being an active trip:
let sd = SCPSmartDriveManager.sharedInstance()
// Speed is metres per second โ multiply by 3.6 for km/h
let speedKmh = sd.getCurrentSpeed() * 3.6
guard TripWrapper.shared.getCurrentTrip() != nil else {
// No active trip โ only speed is meaningful
return
}
let distanceKm = sd.getCurrentTripDistance() // kilometres
let durationSeconds = sd.getCurrentTripDuration() // seconds
Units and behaviour:
-
getCurrentSpeed()returns m/s โ convert to km/h with* 3.6. -
getCurrentTripDistance()returns kilometres. -
getCurrentTripDuration()returns seconds (format asHH:MM:SSif you display it). - When not recording,
getCurrentSpeed()can report residual GPS drift; the demo zeroes speed below 5 km/h when!isRecordingTrip(). -
TripWrapper.shared.getCurrentTrip()returns the active trip (ornil); use it to gate distance/duration and to read identifiers such astripIdandstartDate.
Refresh cadence. There is no push for live components โ poll them on a timer. The demo uses a 1-second repeating Timer (with 0.5 s tolerance) and pauses it in the background (invalidate on willResignActive, recreate on didBecomeActive) to save battery.
Tip
Reference implementation: TripStatusViewModel.swift (status observation, timer, formatting) and the status screen in TripsViewController.swift in the demo app.
- Consolidated SPM โ main page: install, configure, and the full framework list.
- Section 4: Required App Configuration โ permissions, background modes, Background App Refresh.
- Section 10: Integration Guides โ session & app lifecycle, diagnostic logs & export.
- Release Notes.
- SmartDriveDemo app โ reference implementation.