Mapbox Directions for Swift
Mapbox Directions for Swift (formerly MapboxDirections.swift) makes it easy to connect your iOS, macOS, tvOS, watchOS, or Linux application to the Mapbox Directions and Map Matching APIs. Quickly get driving, cycling, or walking directions, whether the trip is nonstop or it has multiple stopping points, all using a simple interface reminiscent of MapKit’s MKDirections
API. Fit a GPX trace to the OpenStreetMap road network. The Mapbox Directions and Map Matching APIs are powered by the OSRM and Valhalla routing engines. For more information, see the Mapbox Navigation homepage.
Mapbox Directions pairs well with MapboxGeocoder.swift, MapboxStatic.swift, the Mapbox Navigation SDK for iOS, and the Mapbox Maps SDK for iOS or macOS SDK.
Getting started
Specify the following dependency in your Carthage Cartfile:
# Latest stable release
github "mapbox/mapbox-directions-swift" ~> 2.9
# Latest prerelease
github "mapbox/mapbox-directions-swift" "v2.11.0-rc.1"
Or in your CocoaPods Podfile:
# Latest stable release
pod 'MapboxDirections', '~> 2.9'
# Latest prerelease
pod 'MapboxDirections', :git => 'https://github.com/mapbox/mapbox-directions-swift.git', :tag => 'v2.11.0-rc.1'
Or in your Swift Package Manager Package.swift:
// Latest stable release
.package(name: "MapboxDirections", url: "https://github.com/mapbox/mapbox-directions-swift.git", from: "2.9.1")
// Latest prerelease
.package(name: "MapboxDirections", url: "https://github.com/mapbox/mapbox-directions-swift.git", .exact("2.11.0-rc.1"))
Then import MapboxDirections
.
This repository contains an example application that demonstrates how to use the framework. To run it, you need to use Carthage 0.19 or above to install the dependencies. Detailed documentation is available in the Mapbox API Documentation.
System requirements
- One of the following package managers:
- CocoaPods 1.10 or above
- Carthage 0.38 or above
- Swift Package Manager 5.5 or above
- Xcode 13 or above
- One of the following operating systems:
- iOS 12.0 or above
- macOS 10.14 or above
- tvOS 12.0 or above
- watchOS 5.0 or above
- Any Linux distribution supported by Swift
v0.30.0 is the last release of MapboxDirections.swift that supports a minimum deployment target of iOS 9.x, macOS 10.11.x, tvOS 9.x, or watchOS 2.x. v0.30.0 is also the last release that is compatible with Objective-C or AppleScript code.
Usage
You’ll need a Mapbox access token in order to use the API. If you’re already using the Mapbox Maps SDK for iOS or macOS SDK, Mapbox Directions automatically recognizes your access token, as long as you’ve placed it in the MBXAccessToken
key of your application’s Info.plist file.
The examples below are each provided in Swift (denoted with main.swift
). For further details, see the documentation available by the link in the releases.
Calculating directions between locations
The main directions class is Directions
. Create a directions object using your access token:
// main.swift
import MapboxDirections
let directions = Directions(credentials: Credentials(accessToken: "<#your access token#>"))
Alternatively, you can place your access token in the MBXAccessToken
key of your application’s Info.plist file, then use the shared directions object:
// main.swift
let directions = Directions.shared
With the directions object in hand, construct a RouteOptions object and pass it into the Directions.calculate(_:completionHandler:)
method.
// main.swift
let waypoints = [
Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.9131752, longitude: -77.0324047), name: "Mapbox"),
Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.8977, longitude: -77.0365), name: "White House"),
]
let options = RouteOptions(waypoints: waypoints, profileIdentifier: .automobileAvoidingTraffic)
options.includesSteps = true
let task = directions.calculate(options) { (session, result) in
switch result {
case .failure(let error):
print("Error calculating directions: \(error)")
case .success(let response):
guard let route = response.routes?.first, let leg = route.legs.first else {
return
}
print("Route via \(leg):")
let distanceFormatter = LengthFormatter()
let formattedDistance = distanceFormatter.string(fromMeters: route.distance)
let travelTimeFormatter = DateComponentsFormatter()
travelTimeFormatter.unitsStyle = .short
let formattedTravelTime = travelTimeFormatter.string(from: route.expectedTravelTime)
print("Distance: \(formattedDistance); ETA: \(formattedTravelTime!)")
for step in leg.steps {
print("\(step.instructions)")
let formattedDistance = distanceFormatter.string(fromMeters: step.distance)
print("— \(formattedDistance) —")
}
}
}
This library uses version 5 of the Mapbox Directions API by default.
Matching a trace to the road network
If you have a GPX trace or other GPS-derived location data, you can clean up the data and fit it to the road network using the Map Matching API:
// main.swift
let coordinates = [
CLLocationCoordinate2D(latitude: 32.712041, longitude: -117.172836),
CLLocationCoordinate2D(latitude: 32.712256, longitude: -117.17291),
CLLocationCoordinate2D(latitude: 32.712444, longitude: -117.17292),
CLLocationCoordinate2D(latitude: 32.71257, longitude: -117.172922),
CLLocationCoordinate2D(latitude: 32.7126, longitude: -117.172985),
CLLocationCoordinate2D(latitude: 32.712597, longitude: -117.173143),
CLLocationCoordinate2D(latitude: 32.712546, longitude: -117.173345)
]
let options = MatchOptions(coordinates: coordinates)
options.includesSteps = true
let task = directions.calculate(options) { (session, result) in
switch result {
case .failure(let error):
print("Error matching coordinates: \(error)")
case .success(let response):
guard let match = response.matches?.first, let leg = match.legs.first else {
return
}
print("Match via \(leg):")
let distanceFormatter = LengthFormatter()
let formattedDistance = distanceFormatter.string(fromMeters: match.distance)
let travelTimeFormatter = DateComponentsFormatter()
travelTimeFormatter.unitsStyle = .short
let formattedTravelTime = travelTimeFormatter.string(from: match.expectedTravelTime)
print("Distance: \(formattedDistance); ETA: \(formattedTravelTime!)")
for step in leg.steps {
print("\(step.instructions)")
let formattedDistance = distanceFormatter.string(fromMeters: step.distance)
print("— \(formattedDistance) —")
}
}
}
You can also use the Directions.calculateRoutes(matching:completionHandler:)
method to get Route objects suitable for use anywhere a standard Directions API response would be used.
Build an isochrone map
Tell the user how far they can travel within certain distances or times of a given location using the Isochrone API. Isochrones
uses the same access token initialization as Directions
. Once that is configured, you need to fill IsochronesOptions
parameters to calculate the desired GeoJSON:
let isochrones = Isochrones(credentials: Credentials(accessToken: "<#your access token#>"))
let isochroneOptions = IsochroneOptions(centerCoordinate: CLLocationCoordinate2D(latitude: 45.52, longitude: -122.681944),
contours: .byDistances([
.init(value: 500, unit: .meters, color: .orange),
.init(value: 1, unit: .kilometers, color: .red)
]))
isochrones.calculate(isochroneOptions) { session, result in
if case .success(let response) = result {
print(response)
}
}
Retrieve a distance or duration matrix
See the travel times or distances between many points using the Matrix API. Matrix
uses the same access token initialization as Directions
. Once that is configured, you need to fill MatrixOptions
parameters to calculate the desired matrix:
let matrix = Matrix(credentials: Credentials(accessToken: "<#your access token#>")
let waypoints = [
Waypoint(coordinate: CLLocationCoordinate2D(latitude: 37.751668, longitude: -122.418408), name: "Mission Street"),
Waypoint(coordinate: CLLocationCoordinate2D(latitude: 37.755184, longitude: -122.422959), name: "22nd Street"),
Waypoint(coordinate: CLLocationCoordinate2D(latitude: 37.759695, longitude: -122.426911))
]
let matrixOptions = MatrixOptions(sources: waypoints, destinations: waypoints, profileIdentifier: .automobile)
matrix.calculate(matrixOptions) { session, result in
if case .success(let response) = result,
let expectedTravelTime = response.travelTime(from: 0, to: 1) {
print("Expected route duration from '\(waypoints[0].name)' to '\(waypoints[1].name)' is \(expectedTravelTime / 60) minutes.")
}
}
Usage with other Mapbox libraries
Drawing the route on a map
With the Mapbox Maps SDK for iOS or macOS SDK, you can easily draw the route on a map:
// main.swift
if var routeCoordinates = route.shape?.coordinates, routeCoordinates.count > 0 {
// Convert the route’s coordinates into a polyline.
let routeLine = MGLPolyline(coordinates: &routeCoordinates, count: UInt(routeCoordinates.count))
// Add the polyline to the map.
mapView.addAnnotation(routeLine)
// Fit the viewport to the polyline.
let camera = mapView.cameraThatFitsShape(routeLine, direction: 0, edgePadding: .zero)
mapView.setCamera(camera, animated: true)
}
Displaying a turn-by-turn navigation interface
The Mapbox Navigation SDK for iOS provides a full-fledged user interface for turn-by-turn navigation along routes supplied by MapboxDirections.
Drawing Isochrones contours on a map snapshot
MapboxStatic.swift provides an easy way to draw a isochrone contours on a map.
// main.swift
import MapboxStatic
import MapboxDirections
let centerCoordinate = CLLocationCoordinate2D(latitude: 45.52, longitude: -122.681944)
let accessToken = "<#your access token#>"
// Setup snapshot parameters
let camera = SnapshotCamera(
lookingAtCenter: centerCoordinate,
zoomLevel: 12)
let options = SnapshotOptions(
styleURL: URL(string: "<#your mapbox: style URL#>")!,
camera: camera,
size: CGSize(width: 200, height: 200))
// Request Isochrone contour to draw on a map
let isochrones = Isochrones(credentials: Credentials(accessToken: accessToken))
isochrones.calculate(IsochroneOptions(centerCoordinate: centerCoordinate,
contours: .byDistances([.init(value: 500, unit: .meters)]))) { session, result in
if case .success(let response) = result {
// Serialize the geoJSON
let encoder = JSONEncoder()
let data = try! encoder.encode(response)
let geoJSONString = String(data: data, encoding: .utf8)!
let geoJSONOverlay = GeoJSON(objectString: geoJSONString)
// Feed resulting geoJSON to snapshot options
options.overlays.append(geoJSONOverlay)
let snapshot = Snapshot(
options: options,
accessToken: accessToken)
// Display the result!
drawImage(snapshot.image)
}
}
Directions CLI
MapboxDirectionsCLI
is a command line tool, designed to round-trip an arbitrary, JSON-formatted Directions or Map Matching API response through model objects and back to JSON. This is useful for various scenarios including testing purposes and designing more sophisticated API response processing pipelines. It is supplied as a Swift package.
To build MapboxDirectionsCLI
using SPM:
swift build
To run (and build if it wasn't yet) MapboxDirectionsCLI
and see usage:
swift run mapbox-directions-swift -h
For further details, see the MapboxDirectionsCLI documentation.
Pricing
API calls made to the Directions API are individually billed by request. Review the pricing information and the pricing page for current rates.