Skip to main content
Version: Next

Migrate from SkyPath SDK 3.x to 4.0

This guide is provided to ease the transition of existing applications using SkyPath v3.x to v4.0 APIs.

v4.0 renames the turbulence API to observations, replaces the mutable dataQuery with a validated fetchConfig, and moves start/simulation/analytics onto dedicated entry points.

Most renamed APIs ship an @available(*, unavailable, renamed:) shim, so Xcode will point at the replacement with a fix-it. Work through the sections below in order and the compiler will find the rest.


1. Initialization

  1. Build an AuthConfig from your existing start(...) arguments — airline becomes companyId.
  2. Replace the start(...) call with initialize(with:completion:).
  3. Delete any stop() calls; the SDK does not need to be stopped.
  4. Replace StartError handling with GeneralError (or the generic SPError).
  5. Remove any reads of SkyPath.env.
// 3.x
SkyPath.shared.start(apiKey: key, airline: icao, userId: userId, env: env) { error in }

// 4.0
let config = AuthConfig(apiKey: key, companyId: icao, userId: userId, env: env)
SkyPath.shared.initialize(with: config) { error in }
3.x4.0
start(apiKey:airline:userId:env:completion:)initialize(with:completion:)
stop()Removed — stopping the SDK is no longer available
StartErrorRemoved — errors are GeneralError / other SPError types
SkyPath.envRemoved

2. Fetch configuration

  1. Rename the type DataQuery to FetchConfig everywhere.
  2. Replace every SkyPath.shared.dataQuery.<field> = value assignment with updateFetchConfig { $0.<field> = value }fetchConfig is now read-only.
  3. Group fields you used to set one by one into a single updateFetchConfig closure, so validation and the fetch check run once.
  4. Add try and error handling — updateFetchConfig(_:) and setFetchConfig(_:) throw a QueryError on a malformed polygon/viewport or an unsupported aircraftICAO.
  5. Rename the three toggles: dataUpdateEnabled, dataUpdateInBackgroundIsEnabled, peerEnabled.
  6. Delete fetchData(...), fetchingStatus(...) and updateDate(of:) calls.
// 3.x
SkyPath.shared.dataQuery.polygon = polygon
SkyPath.shared.dataQuery.types = [.turbulence]

// 4.0 — all mutations in one closure = a single validation + fetch evaluation
do {
try SkyPath.shared.updateFetchConfig {
$0.polygon = polygon
$0.types = [.observations]
$0.aircraftICAO = "B737"
}
} catch {
print(error)
}

// or replace entirely
do {
try SkyPath.shared.setFetchConfig(FetchConfig(polygon: polygon))
} catch {
print(error)
}
3.x4.0
SkyPath.dataQuery (settable)SkyPath.fetchConfig (read-only) + updateFetchConfig(_:) / setFetchConfig(_:)
DataQueryFetchConfig
SkyPath.dataUpdateEnabledSkyPath.isFetchEnabled
SkyPath.dataUpdateInBackgroundIsEnabledSkyPath.isBackgroundFetchEnabled
SkyPath.peerEnabledSkyPath.isPeerEnabled
fetchData(refresh:types:)Removed — data is fetched automatically; change fetchConfig instead
fetchingStatus(for:dataType:)Removed
updateDate(of:)Removed — use SkyPath.dataUpdatedAt

fetchData(refresh:types:) was a public API and has no replacement: there is no way to trigger a fetch manually any more. The SDK fetches on its own schedule and re-evaluates whenever fetchConfig changes, so remove any "refresh data" button or pull-to-refresh that called it.

3. Data types

  1. Rename the type DataTypeOptions to DataType everywhere.
  2. Rename the case .turbulence to .observations.
  3. Change every DataTypeOptions value to a Set<DataType> literal — types, viewportTypes, and your own properties.
  4. Replace DataTypeOptions.all, .asArray and .rawValue usages with an explicit Set<DataType>.
  5. Replace DataAreaType.any with .route, .viewport or .all.
// 3.x
SkyPath.shared.dataQuery.types = [.turbulence, .oneLayer]
if DataTypeOptions.forecast.enabled { ... }

// 4.0
try SkyPath.shared.updateFetchConfig { $0.types = [.observations, .oneLayer] }
if DataType.forecast.enabled { ... }
3.x4.0
DataTypeOptionsDataType
DataTypeOptions.turbulenceDataType.observations
DataTypeOptions.all / .asArray / .rawValueRemoved — use a Set<DataType> literal
DataAreaType.anyRemoved — use .route, .viewport, or .all

DataType.forecast still requires .oneLayer to also be in types, and entitlement via DataType.forecast.enabled.

4. Observations (was Turbulence)

  1. Rename the call turbulence(with:) to observations(with:).
  2. Rename the types TurbulenceQueryObservationsQuery and TurbulenceItemObservationsItem everywhere, including your own properties, arrays and function signatures.
  3. Update QueryResult<TurbulenceItem> to QueryResult<ObservationsItem>.
  4. Update TurbulenceCluster.turbulence and .nearestMaxSevTurbulence call sites — they now hand back ObservationsItem.
  5. Rename TurbulenceItemable.turbulenceItem to asTurbulenceItem.
3.x4.0
SkyPath.turbulence(with:)SkyPath.observations(with:)
TurbulenceQueryObservationsQuery
TurbulenceItemObservationsItem
QueryResult<TurbulenceItem>QueryResult<ObservationsItem>
TurbulenceCluster.turbulence / .nearestMaxSevTurbulenceNow [ObservationsItem] / ObservationsItem?
Array<TurbulenceItem>.geoJSON(withType:)Array<ObservationsItem>.geoJSON(withType:)
TurbulenceItemable.turbulenceItemasTurbulenceItem (now returns ObservationsItem)

5. Aircraft

  1. Delete all uses of the Aircraft and AircraftSize types — they are no longer public.
  2. Replace SkyPath.aircraft = ... with updateFetchConfig { $0.aircraftICAO = "B737" }.
  3. Delete aircrafts() calls; there is no list of supported aircraft any more.
  4. Replace aircraft(byId:) validation with a do/catch around updateFetchConfig — an unsupported ICAO throws.
  5. Read the current value from SkyPath.fetchConfig.aircraftICAO instead of SkyPath.aircraft.
// 3.x
if let aircraft = SkyPath.shared.aircraft(byId: "B737") {
SkyPath.shared.aircraft = aircraft
}

// 4.0 — throws if the ICAO is not supported
do {
try SkyPath.shared.updateFetchConfig { $0.aircraftICAO = "B737" }
} catch {
print(error)
}
3.x4.0
SkyPath.aircraftSkyPath.fetchConfig.aircraftICAO (default "B737")
SkyPath.aircrafts()Removed
SkyPath.aircraft(byId:)Removed — set aircraftICAO and handle the thrown error
Aircraft, AircraftSizeRemoved

6. Notifications

  1. Delete notifications(with:) calls and move that logic into didReceiveNotification(_:), starting monitoring with startMonitoringNotifications(with:).
  2. Rename NotificationResult.turbulence to .observations.
  3. Make NotificationQuery.minSev non-optional — remove the ? and drop nil assignments; the default is now .light.
  4. Delete switchToBeamOnDistanceFromRoute, excludeOwnTimeSpan and tiles from your NotificationQuery setup.
  5. Remove any NotificationResultType.tiles branches.
// 3.x
let result = try SkyPath.shared.notifications(with: query).get()

// 4.0
SkyPath.shared.startMonitoringNotifications(with: query)
// → SkyPathDelegate.didReceiveNotification(_:)
3.x4.0
SkyPath.notifications(with:)Removed — startMonitoringNotifications(with:) + didReceiveNotification(_:)
NotificationResult.turbulenceNotificationResult.observations
NotificationQuery.minSev: TurbulenceSeverity?minSev: TurbulenceSeverity, default .light
NotificationQuery.switchToBeamOnDistanceFromRouteRemoved — beam mode kicks in automatically when far from the route line
NotificationQuery.excludeOwnTimeSpanRemoved
NotificationQuery.tiles / NotificationResultType.tilesRemoved

7. Recording state

  1. Replace inPosition, isHorizontal and inNoise reads with a single SkyPath.recordingState check.
  2. Replace the didUpdateRecordingStatus(to:) / didChangeDevicePosition(_:horizontal:) delegate methods with didUpdateRecordingState(to:) — see §9 Delegate.
  3. Map your pilot-facing messages onto the four RecordingState cases.

Both 3.x callbacks collapse into didUpdateRecordingState(to:), and state == .recording carries what each of them used to report:

  • what didUpdateRecordingStatus(to: true) reported is now state == .recording;
  • what didChangeDevicePosition(inPosition:horizontal:) reported is now inPosition == (state == .recording) and horizontal == (state == .horizontal).

So if you handled both, move both bodies into the single method and derive the old booleans from state.

// 4.0
switch SkyPath.shared.recordingState {
case .recording, .notInPosition, .horizontal, .noise: break
}

func didUpdateRecordingState(to state: RecordingState) { }
3.x4.0
SkyPath.inPositionSkyPath.recordingState == .recording
SkyPath.isHorizontalSkyPath.recordingState == .horizontal
SkyPath.inNoiseSkyPath.recordingState == .noise

8. App events

  1. Replace setMapLayer(enabled:) with reportAppEvent(.mapLayer(enabled:)).
  2. Replace notifiedTurbulenceSeverity(_:coordinate:altFt:dataSource:) with reportAppEvent(.notifiedTurbulence(severity:coordinate:altFt:dataSource:)).
// 3.x
SkyPath.shared.setMapLayer(enabled: true)
SkyPath.shared.notifiedTurbulenceSeverity(sev, coordinate: coord, altFt: alt, dataSource: source)

// 4.0
SkyPath.shared.reportAppEvent(.mapLayer(enabled: true))
SkyPath.shared.reportAppEvent(.notifiedTurbulence(severity: sev, coordinate: coord, altFt: alt, dataSource: source))
3.x4.0
setMapLayer(enabled:)reportAppEvent(.mapLayer(enabled:))
notifiedTurbulenceSeverity(_:coordinate:altFt:dataSource:)reportAppEvent(.notifiedTurbulence(severity:coordinate:altFt:dataSource:))

9. Delegate

  1. Implement all available SkyPathDelegate methods — there are no default implementations any more, so a missing one is a compile error.
  2. Rename didReceiveNewTurbulenceData(areaType:) to didReceiveNewObservationsData(areaType:).
  3. Merge didFailToFetchNewData(with:type:) and locationManagerDidFail(withError:) into didFail(with:dataType:). dataType is optional: it carries the failing DataType for data-fetch errors and is nil for everything else (authorization, token refresh, location).
  4. Delete the six removed callbacks listed below — the SDK no longer calls them.

The 4.0 protocol is exactly: didReceiveNewObservationsData(areaType:), didReceiveNewOneLayer(areaType:), didFail(with:dataType:), didReceiveNotification(_:), didUpdateRecordingState(to:).

// 3.x
func didFailToFetchNewData(with error: SPError, type: DataTypeOptions) { }
func locationManagerDidFail(withError error: Error) { }

// 4.0
func didFail(with error: SPError, dataType: DataType?) {
switch dataType {
case .observations, .oneLayer: reloadTurbulenceLayer()
case .forecast: reloadForecastLayer()
case nil: break // not data-type specific, e.g. unauthorized or location
default: break
}
}
3.x4.0
didReceiveNewTurbulenceData(areaType:)didReceiveNewObservationsData(areaType:)
didFailToFetchNewData(with:type:)didFail(with:dataType:)
locationManagerDidFail(withError:)didFail(with:dataType:) (dataType is nil)
didUpdateRecordingStatus(to:) / didChangeDevicePosition(_:horizontal:)didUpdateRecordingState(to:)
detectedTurbulence(_:)Removed
serverReachabilityUpdated(to:)Removed
didUpdateLowPowerMode(_:)Removed
didUpdateFetchingStatus(to:areaType:dataType:)Removed
didUpdateConfig()Removed
didUpdatePeers(discovered:connected:)Removed

10. Severity colors

  1. Rename TurbulenceSeverity.none to .smooth everywhere, including switch cases.
  2. Define your own colors for the severity levels — colors were removed from the SDK. Use the reference palette from the Data page.
  3. Repoint .color, .borderColor, .colorOpacity and .colorWithOpacity call sites at your own colors.
3.x4.0
TurbulenceSeverity.noneTurbulenceSeverity.smooth
.color, .borderColor, .colorOpacity, .colorWithOpacityRemoved — provide your own

11. Logging

  1. Replace SkyPath.logger.printLevel = ... with SkyPath.loggerLevel = ....
  2. Replace SkyPath.logger.exportLogs(...) with SkyPath.exportLogs(...).
  3. Delete every other logger usage — the Logger type is no longer public.
3.x4.0
SkyPath.logger.printLevelSkyPath.loggerLevel
SkyPath.logger.exportLogs(notifyOnQueue:completion:)SkyPath.exportLogs(notifyOnQueue:completion:)
LoggingLevelPrintLevel
Logger, logger.isEnabled, .logsDirectory, .maximumNumberOfLogFiles, .rollingFrequencyRemoved

12. Flight

  1. Rename Flight.fnum to Flight.num.
  2. Change Flight(dep:dest:fnum:fnumManual:) to Flight(dep:dest:num:) — the fnumManual argument is gone.
  3. Remove reads of Flight.id, .depLat, .depLng, .destLat, .destLng; keep those values on your own model if you need them.
  4. Remove observers of the didUpdateFlight notification.
3.x4.0
Flight.fnumFlight.num
Flight(dep:dest:fnum:fnumManual:)Flight(dep:dest:num:)
Flight.id, .fnumManual, .depLat, .depLng, .destLat, .destLngRemoved
Notification.Name.didUpdateFlightRemoved

13. Testing & simulation

  1. Insert .testing between SkyPath.shared and every simulation call — the methods themselves keep their names and signatures.
  2. Keep these calls on the staging environment only (env: .staging(serverUrl: nil) in AuthConfig).
// 3.x
SkyPath.shared.enableSimulation(true)
SkyPath.shared.simulatedLocation(location)

// 4.0
SkyPath.shared.testing.enableSimulation(true)
SkyPath.shared.testing.simulatedLocation(location)
3.x4.0
SkyPath.enableSimulation(_:)SkyPath.testing.enableSimulation(_:)
SkyPath.simulatedLocation(_:)SkyPath.testing.simulatedLocation(_:)
SkyPath.enablePushSimulated(_:)SkyPath.testing.enablePushSimulated(_:)
SkyPath.simulateTurbulence(sev:)SkyPath.testing.simulateTurbulence(sev:)
SkyPath.simulateBadLocation(_:)SkyPath.testing.simulateBadLocation(_:)
SkyPath.simulateBadLocation (property)SkyPath.testing.simulateBadLocation

14. Errors

  1. Remove the four deleted QueryError cases from your switch statements.
  2. Add invalidRoute where you handle polygon/route problems.
  3. Handle the two new GeneralError cases if you switch exhaustively: unauthorized(message:) (HTTP 401) and location(error:).
3.x QueryError case4.0
altRangeNotRoundToThousandFeetRemoved
polygonTooManyCoordinatesRemoved — use invalidPolygon
invalidCoordinatesRemoved — use invalidPolygon
dataQueryInvalid(message:)Removed — use invalidPolygon / invalidRoute / general(error:)
invalidRoute added

15. Removed with no replacement

  1. Move local-notification scheduling into your app using Apple's UserNotifications framework.
  2. Replace Tile usages with the plain String tile keys still returned by QueryResult.tiles and accepted by ObservationsQuery.tiles / excludeTiles.
  3. Delete any UI driven by serverReachable or lowPowerMode.
3.x4.0
SPLocalNotificationManagerRemoved — use UserNotifications directly
Tile, Itemable.tileRemoved — use String tile keys
SkyPath.serverReachableRemoved — reachability status is no longer available
SkyPath.lowPowerModeRemoved — low power mode status is no longer available
Aircraft, AircraftSizeRemoved — see §5 Aircraft
Logger, LoggingLevelRemoved — see §11 Logging
StartErrorRemoved — see §1 Initialization