Mapbox Directions for Swift

CircleCI Carthage compatible CocoaPods SPM compatible

Mapbox Directions for Swift (前身为 MapboxDirections.swift) 让您可以轻松地将您的 iOS、macOS、tvOS、watchOS 或 Linux 应用程序连接到 Mapbox DirectionsMap Matching API。 快速获取驾车、骑自行车或步行路线,无论行程是否直达或有多个停靠点,所有操作都使用类似于 MapKit 的 MKDirections API 的简单界面。 将 GPX 轨迹拟合到 OpenStreetMap 道路网络。 Mapbox Directions 和 Map Matching API 由 OSRMValhalla 路由引擎驱动。 有关更多信息,请参阅 Mapbox Navigation 首页。

Mapbox Directions 与 MapboxGeocoder.swiftMapboxStatic.swiftMapbox Navigation SDK for iOS 以及 Mapbox Maps SDK for iOSmacOS SDK 配合使用效果良好。

入门指南

在您的 Carthage Cartfile 中指定以下依赖项

# Latest stable release
github "mapbox/mapbox-directions-swift" ~> 2.14
# Latest prerelease
github "mapbox/mapbox-directions-swift" "v2.11.0-alpha.1"

或在您的 CocoaPods Podfile 中

# Latest stable release
pod 'MapboxDirections', '~> 2.14'
# Latest prerelease
pod 'MapboxDirections', :git => 'https://github.com/mapbox/mapbox-directions-swift.git', :tag => 'v2.11.0-alpha.1'

或在您的 Swift Package Manager Package.swift 中

// Latest stable release
.package(name: "MapboxDirections", url: "https://github.com/mapbox/mapbox-directions-swift.git", from: "2.14.0")
// Latest prerelease
.package(name: "MapboxDirections", url: "https://github.com/mapbox/mapbox-directions-swift.git", .exact("2.11.0-alpha.1"))

然后 import MapboxDirections

此仓库包含一个示例应用程序,演示了如何使用该框架。 要运行它,您需要使用 Carthage 0.19 或更高版本来安装依赖项。 详细文档可在 Mapbox API 文档中找到。

系统要求

v0.30.0 是 MapboxDirections.swift 的最后一个版本,它支持 iOS 9.x、macOS 10.11.x、tvOS 9.x 或 watchOS 2.x 的最低部署目标。 v0.30.0 也是最后一个与 Objective-C 或 AppleScript 代码兼容的版本。

用法

API 参考

您需要一个 Mapbox 访问令牌才能使用该 API。 如果您已经在使用 Mapbox Maps SDK for iOSmacOS SDK,Mapbox Directions 会自动识别您的访问令牌,只要您已将其放置在应用程序 Info.plist 文件的 MBXAccessToken 键中。

以下示例均以 Swift 提供(以 main.swift 表示)。 有关更多详细信息,请参阅 发行说明中的链接提供的文档。

计算位置之间的方向

主方向类是 Directions。 使用您的访问令牌创建一个方向对象

// main.swift
import MapboxDirections

let directions = Directions(credentials: Credentials(accessToken: "<#your access token#>"))

或者,您可以将您的访问令牌放置在应用程序 Info.plist 文件的 MBXAccessToken 键中,然后使用共享的方向对象

// main.swift
let directions = Directions.shared

手持方向对象,构造一个 RouteOptions 对象并将其传递到 Directions.calculate(_:completionHandler:) 方法中。

// 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)")
        }
    }
}

此库默认使用 Mapbox Directions API 的版本 5。

将轨迹匹配到道路网络

如果您有 GPX 轨迹或其他 GPS 衍生位置数据,您可以使用 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)")
        }
    }
}

您还可以使用 Directions.calculateRoutes(matching:completionHandler:) 方法来获取适用于任何标准 Directions API 响应的 Route 对象。

构建等时线地图

使用 Isochrone API 告知用户他们可以在给定位置的特定距离或时间内行进多远。 Isochrones 使用与 Directions 相同的访问令牌初始化。 配置完成后,您需要填写 IsochronesOptions 参数以计算所需的 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)
    }
}

检索距离或持续时间矩阵

使用 Matrix API 查看多个点之间的旅行时间或距离。 Matrix 使用与 Directions 相同的访问令牌初始化。 配置完成后,您需要填写 MatrixOptions 参数以计算所需的矩阵

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.")
    }
}

与其他 Mapbox 库一起使用

在地图上绘制路线

使用 Mapbox Maps SDK for iOSmacOS SDK,您可以轻松地在地图上绘制路线

// 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)
}

显示逐向导航界面

Mapbox Navigation SDK for iOS 为沿 MapboxDirections 提供的路线进行逐向导航提供了完整功能的用户界面。

在地图快照上绘制等时线轮廓

MapboxStatic.swift 提供了一种在地图上绘制等时线轮廓的简便方法。

// 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 是一个命令行工具,旨在通过模型对象往返任意 JSON 格式的 Directions 或 Map Matching API 响应,并返回 JSON。 这对于各种场景很有用,包括测试目的和设计更复杂的 API 响应处理管道。 它以 Swift 包的形式提供。

要使用 SPM 构建 MapboxDirectionsCLI

  1. swift build

要运行(并在尚未构建时构建)MapboxDirectionsCLI 并查看用法

  1. swift run mapbox-directions-swift -h

有关更多详细信息,请参阅 MapboxDirectionsCLI 文档

定价

对 Directions API 发出的 API 调用按请求单独计费。 查看 定价信息定价页面 以获取当前费率。