Migrating to the Scope SDKs (ConsolidatedSPM 1.1.1) — iOS - scopetech/Mobile-Public GitHub Wiki
Migrating to the Scope SDKs (ConsolidatedSPM 1.1.1) — iOS
Migration guide for integrator teams updating from earlier SDK versions. Companion: Flutter edition. Related wiki pages: iOS Session & App Lifecycle Management, iOS Diagnostic Logs and Export.
This release focuses on trip detection reliability on iOS 26 — trips that failed to end, merged together, were truncated mid-drive, or were incorrectly discarded are resolved. The update is designed to be low-effort: no integration redesign is required, and the few possible compile-time touch points are listed below with their one-line fixes.
Target versions
| Package | Version |
|---|---|
| ConsolidatedSPM-iOS | 1.1.1 (recommended — pins all of the below) |
| SCPSmartDriveSPM-iOS | 1.1.18 |
| TripWrapperSPM-iOS | 1.0.9 |
| SDApiManagerSPM-iOS | 1.0.7 |
| BLEFrameworkSPM-iOS | 1.0.5 |
| BiosenseSignalSPM-iOS | 1.0.0 |
| WellnessSPM-iOS | 1.0.1 |
[!IMPORTANT] SCPSmartDrive and TripWrapper are a matched pair — update them together. Updating the Consolidated package to 1.1.1 does this for you. After updating, commit your
Package.resolved; it records the exact set your build was tested with.
Step 1 — Update the dependency
Bump ConsolidatedSPM-iOS to 1.1.1 (File → Packages → Update to Latest Package
Versions, or edit the version rule), or bump the individual packages to the table
above. Then: File → Packages → Reset Package Caches, and Clean Build Folder.
Step 2 — Build, and fix what the compiler flags
Three known source-compatibility items. All are mechanical; the compiler pinpoints each site.
2.1 APIManagerProtocol.isRealtimeSendingEnabled() (TripWrapper) — the protocol
gained a member that selects the trip-end sending pipeline. If your build reports a
missing conformance on your API manager / coordinator class, add:
/// Batch (PreTrips) sending — the pre-update behavior.
/// Return true only if adopting realtime sending (and pass
/// enableRealtimeSending: true to initialize — the two must agree).
func isRealtimeSendingEnabled() -> Bool {
return false
}
2.2 CCTimeInterval is no longer Optional (SDApiManager nullability audit) —
if you wrapped its initializer in if let / guard let, remove the binding:
// Before
guard let interval = CCTimeInterval(from: start, to: end) else { return }
// After
let interval = CCTimeInterval(from: start, to: end)
The same applies to any other SDApiManager type the compiler flags with "Initializer for conditional binding must have Optional type."
2.3 SCPSmartDriveManagerDelegate.didReceiveLog optionality — if you implement
the SmartDrive log delegate directly, the description parameter is now non-optional:
// Before
func didReceiveLog(with group: LogGroup, groupInfo info: String?, description text: String!)
// After
func didReceiveLog(with group: LogGroup, groupInfo info: String?, description text: String)
No other public API changes. TripNotificationDelegate, TripConfigProvider,
DeviceIDProvider, LoggingProtocol, TripWrapperDelegate, and all trip data
accessors are unchanged — your integration code otherwise compiles as-is.
Step 3 — Behavior changes to review
These are deliberate and apply automatically; review whether any affect your product expectations.
- Long standstills end the trip. A stop longer than the trip-end threshold
(default 300 s) now completes the trip even with the phone still inside the vehicle
(e.g. a long railway crossing); driving on starts a new trip. The threshold remains
configurable (
autostopThresholdSeconds/ trip-end threshold setting). - Mode-of-transport skipping is distance-capped. Map-based public-transport
filtering no longer discards trips longer than
kSettingsMOTSkipMaxDistance(new default: 3000 m when unset). If you relied on unlimited MOT skipping, set the key explicitly. - Trip end times are the actual stop moment, not the confirmation moment (~5 minutes later). Trip start/end notifications align with the recorded lifecycle.
- Notification guidance: if your
TripNotificationDelegateskips scheduling the trip-end notification while the app is foreground — don't. App state at scheduling time says nothing about state ~5 minutes later when it fires. Always schedule; decide foreground presentation in yourUNUserNotificationCenterDelegate'swillPresent.
Step 4 — What you get automatically
- The trip-reliability fixes themselves: correct trip completion under iOS 26's motion-activity misbehavior, no mid-drive truncation by recovery routines, no duplicate/overlapping portal trips, no loss of short or transit-corridor trips, serialized realtime event sending.
- Health snapshots in your diagnostic logs. TripWrapper now emits a
TRIPWRAPPER HEALTH SNAPSHOTblock (through yourLoggingProtocol) at initialization, trip start, trip end, and backgrounding (throttled) — versions, permission states with ⚠️ markers, SDK configuration, trip counts. Include it when contacting support; it answers the first ten triage questions.- Note: snapshots are multi-line log entries. Your log export (per the Diagnostic Logs and Export guide) handles this as-is; if your in-app log viewer renders one line per entry, set the cell to multi-line or expect to read snapshots in the exported file.
- GPS startup diagnostics now log the location authorization status when no fix is available — permission problems announce themselves in the log header.
Step 5 — Verify
[!IMPORTANT] Fresh installs reset iOS location permission. After reinstalling during your own validation, confirm Location Always + Precise Location (and Background App Refresh) before test drives — automatic recording cannot function without them. The new health snapshot states all three with ⚠️ markers if wrong.
Drive-test checklist:
- Trips start and end at the correct times in dense city traffic with frequent stops.
- Consecutive trips separated by a parked stop longer than the threshold appear as separate trips.
- No duplicate or overlapping trips on the portal from a single drive.
- Trip start/end notifications correspond to real recorded trips.
- Car trips on bus/tram corridors are recorded normally.
- The first log lines after launch include the health snapshot with your app version
and
TripWrapper: 1.0.9/SmartDrive: 1.1.11.
Optional — the simplified integration facade
This release's reference apps also introduce an optional simplified integration
(ScopeSDK facade: one start, one authenticated, one stop, a single ScopeHost
struct instead of multiple protocol conformances). It is not required for this
migration — your existing protocol-based integration is fully supported and
unchanged. When you next revisit integration code, see
iOS Simplified SDK Integration
for the two-file architecture, its principles, and the step-by-step; the working
reference is the
SmartDriveDemo feature/sdk_simplification branch.
Support
If anything behaves unexpectedly after updating, export the diagnostic log (it now
begins with the health snapshot) and send it with your Package.resolved versions.